欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

nginx基础配置篇

程序员文章站 2022-06-11 14:42:11
...

序言

nginx是非常流行的一个http反向代理服务器,虽然不是专业的运营人员,但作为开发人员,掌握一些基本的用法也是蛮必要的,本篇记录nginx的一些基本配置。

调整工作进程数

nginx启动会创建主进程和工作进程,默认只会创建一个工作进程用于处理连接(底层使用epoll等事件处理模型),如果是多核服务器,建议把工作进程的数量设置为cpu的核数,如8核cpu可以如下设置:
worker_processes 8;

基本资源访问

1) 最常见的nginx用法就是把它当作一个静态资源服务器,先看一个最简单的例子:
在本机hosts文件中如下配置: 127.0.0.1 static.test.com

nginx.conf配置server:
server {
    listen static.test.com;
    root D:/learn/static;
}

然后访问 http://static.test.com/hello.js 即可以访问到 D:/learn/static/hello.js。

2) 我们也可以配置多个域名同时访问同一个资源
在hosts中添加如下映射:127.0.0.1 static2.test.com

nginx.conf配置server:
server {
    listen 80;
    server_name static.test.com  static2.test.com;
    root D:/learn/static;
}

访问http://static2.test.com/hello.js 即可以访问到 D:/learn/static/hello.js。

3) 此外,域名还可以使用通配符,比如,所有以 test.com结尾的域名都支持访问hello.js,

修改nginx.conf,如下:
server {
    listen 80;
    server_name *.test.com;
    root D:/learn/static;
}

此时 http://static2.test.com/hello.js 仍然是有效的。

4) 也可以使用正则对域名进行匹配

修改nginx.conf,如下:
server {
    listen 80;
    server_name ~^(.+)\.test\.com$;
    root D:/learn/$1;
}

此时访问 http://static.test.com/hello.js 相当于访问 D:\learn\static\hello.js
此时访问 http://static2.test.com/hello.js 相当于访问 D:\learn\static2\hello.js
可以实现多站点动态目录。

5) 简单的location
有时候我们需要定义访问的一些路径,可以简单使用 location,如下所示:

server {
    listen 80;
    server_name static.test.com;
    location /static {
        root D:/learn/;
    }
}

访问 http://static.test.com/static/hello.js,实际上会转成 D:/learn/static/hello.js

6) 可以使用别名来实现5的功能
配置如下:

server {
    listen 80;
    server_name static.test.com;
    location /static {
        alias D:/learn/static;
    }
}

访问 http://static.test.com/static/hello.js,实际上会转成 D:/learn/static/hello.js,可以认为别名是一种替换,使用 D:/learn/static 来替换 /static。

强大的location

location的功能比较强大,规则比较多,但只要总结好,还是不难记住的。
location主要配置两种路径格式:普通格式 和 正则表达式,一般在server下面都会配置多个location,这时候,如何匹配就显示尤为关键了。先来看下location的语法格式:
location [=|~|~*|^~|@] /uri/ { … }

可以看到一共支持5种前缀,再加上可以没有前缀,所以一共有6种格式。前面说过,分大类的话,其实只有两类:

普通格式 (4种) 正则(2种)
= 精确匹配
^~ 不需要继续正则匹配
@ 命名 location
(没有前缀也算一种)
~ 区分大小写
~* 不区分大小写

nginx在匹配的时候,会把server下面的location分为普通格式组和正则组,先匹配普通组,如果有必要,再匹配正则组。
接下来简要描述匹配的大致算法流程:

1、分组,根据6种前缀,先分为普通格式组 和 正则组;

2、 先匹配普通格式组;
a. 如果请求的路径跟location配置的路径完全一样,并且配置时有 = 前缀,命中此location,结束流程。
比如配置 location = /static/index.html {},访问 http://xx/static/index.html
这也就是精确匹配的由来。

b. 到这一步,=前缀就不再参与计算了,因为已经不可能精确匹配了。接着,在剩余的普通格式中,找出最长匹配请求路径的那一条location配置,如果这个location有 ^~前缀,那么命中此 location,结束流程,否则把这个location当作一个备胎先记住,然后执行正则组的匹配。

最长路径匹配说明:
location = /static/pathb/pathc/ {}
location = /static/patha/ {}
location = /static/ {}
当访问 http://xx/static/patha/a.html 时,显然 location = /static/patha/ {} 这条路径匹配最长。

3、匹配正则组
说明: 正则组按照location出现的位置依次匹配,只要匹配上一个即刻终止。

前面说过,在普通组的匹配中,在某些情况下会有一个备胎location。当所有正则组都无法匹配到时,这个备胎就是最终匹配到的location,但是当任何一个正则匹配上的时候,就会使用此正则location,结束流程,备胎location将被丢弃。

举个简单的示例:
配置如下:
server {
    listen 80;
    server_name static.test.com;
    location /static/ {
        deny all;
    }
    location ^~ /static/path/ {
        allow all;
    }
    location ~ \.html {
            deny all;
    }
}

访问 http://static.test.com/static/path/index.html 时返回 404。
按照前面的算法流程,location ^~ /static/path/ {} 为普通格式中的最长匹配,而且还带有 ^~前缀,于是命中,匹配结束,由于我们没有配置映射的方式,所以找不到,返回了404。
细心的朋友可能发现没有说到@前缀,其实它主要用于其他用途。

比如有如下配置:
server {
    listen 80;
    server_name static.test.com;

    location ^~ /static/path/ {
        allow all;
    }
    error_page 404 = @baidu;
    location @baidu {
        proxy_pass http://www.baidu.com;
    }
}

当访问 static.test.com/static/path/s?wd=nginx 的时候,虽然匹配上了location ^~ /static/path/ {},但结果却是404,这时候被error_page捕获到了,从而在nginx流转到了location @baidu{},然后通过proxy_pass把请求转发给了http://www.baidu.com,经测试发现,浏览器重定向到了http://static.test.com/s?wd=nginx&tn=SE_PSStatistics_p1d9m0nf,然后确实可以显示百度返回的内容。

强大的rewrite模块

跟location一样,rewrite也是nginx中非常核心的特性,用于处理各种请求转发。一般提到rewrite,都会涉及到几个相关的指令,如下表所示:

指令 出现上下文 说明
break server,location,if 完成当前的规则集,不再处理rewrite指令
if server,location 条件判断,不支持嵌套,不支持多个条件&&和
set server,location,if 用于定义一个变量,并给变量赋值。变量的值可以为文本、变量以及文本变量的联合。
return server,location,if 该指令用于结束规则的执行并返回状态码给客户端
rewrite server,location,if 该指令根据表达式来重定向URI,或者修改字符串。指令根据配置文件中的顺序来执行。注意重写表达式只对相对路径有效。语法: rewrite regex replacement flag

有几个用于判断文件及目录匹配的,如下表所示:

指令 说明
-f和!-f 用来判断是否存在文件
-d和!-d 用来判断是否存在目录
-e和!-e 用来判断是否存在文件或目录
-x和!-x 用来判断文件是否可执行

rewrite指令的最后一项参数为flag标记,flag标记有:

rewrite的flag标记 说明
last 如果一个location中有多个rewrite,表示停止本location后面rewrite的匹配,继续新一轮location匹配
break 本条规则匹配完成后,终止匹配,整个匹配流程结束
redirect 302临时重定向
permanent 301永久重定向

学习rewrite相关的内容最简单就是通过示例来说明:
示例1:

server {
    listen  80;
    server_name static.test.com;
    if ($request_uri ~ /static/my) {
        rewrite ^/static/my/(.*)$ /static2/my/$1;
    }
    location /static2/my {
        root D:/resource/;
        rewrite ^/static2/my/(.*)/(.*)$ /static3/my/$2.$1 break;
    }
}

访问:http://static.test.com/static/my/txt/a 结果访问的是: D:/resource/static3/my/a.txt

解析:
首先,请求路径/static/my/txt/a 匹配上了if指令,所以被rewrite成了/static2/my/txt/a,接着,执行location匹配,匹配上了 location /static2/my,再次被rewrite成了/static3/my/a.txt,由于最后有break标识,终止整个流程,再结合root D:/resource/配置,最终就找到了 D:/resource/static3/my/a.txt。

示例2:

server {
    listen  80;
    server_name static.test.com;
    if ($request_uri ~ /static/my) {
        rewrite ^/static/my/(.*)$ /static2/my/$1;
    }
    location /static2/my {      
        rewrite ^/static2/my/(.*)/(.*)$ /static3/my/$2.$1 break;
    }
    location /static3 {
        root D:/resource/;
    }
}

访问:http://static.test.com/static/my/txt/a ,结果返回了 404。

解析:
本示例跟示例1差不多,不同的就是 location /static2/my 中的 root被单独抽取出来了,结果就访问不了啦,说明,location中,如果匹配的rewrite以break为标识,要定义好路径映射。如果把location /static2/my 中的rewrite标识改为last,则又可以访问了,原因在于nginx的执行流程,步骤大致如下:

a. 先执行一次 server中的各类指令(过滤location)

b. 得到目前的路径(可能被rewrite过了),匹配location(前面部分已经详细说明过匹配规则),匹配location中的rewrite,当匹配上的rewrite以break结尾时,命中,结束整个流程;如果匹配上的rewrite以last结尾,那么中断当前location匹配,重新执行步骤b,一直到最大上限次数10次为止。(如果匹配上的location没有rewrite,那么提前中断,就像上面的 location /static3一样,直接就可以找到资源了)

示例3:

server {
    listen  80;
    server_name static.test.com;
    if ($request_uri ~ /static/my) {
        rewrite ^/static/my/(.*)$ /static4/my/$1;
    }
    rewrite ^/static4/my/(.*)$ /static2/my/$1;

    location /static2/my {      
        root D:/resource/;
        rewrite ^/static2/my/(.*)/(.*)$ /static3/my/$2.$1 break;
    }
}

访问:http://static.test.com/static/my/txt/a 结果访问的是: D:/resource/static3/my/a.txt
注意,在 if 提令中的rewrite并没有任何的flag,所以rewrite ^/static4/my/(.*)/static2/my/1;才能够执行,反之则不会执行,也就得不到我们想要的结果。

小小总结:

a. server上下文中,非location中的指令会先执行, 这时候注意rewrite的flag,如果为last或者break,那么会中断其他非locatoin中的rewrite配置执行

b. 当执行完非location中的指令,接着匹配location,如果匹配到的location中命中了rewrite,这时候,如果命中的rewrite以break结尾,则整个匹配流程结束,如果以last结尾,则要重新匹配location,最大执行10次(为避免死循环),所以要注意last和break的使用场景。

防盗链

有时候,我们要使用图片防盗链功能,nginx提供了简单便捷的防盗链使用方式。
图片防盗链主要是利用http referer头进行判断,这种方式是阻止不了写代码抓取图片的,但一般我们主要是防止图片被他人直接内嵌在网页中。
一个简单的配置如下:

server {
    listen  80;
    server_name static.test.com;
    valid_referers none  blocked  *.test.com  ~.*\.test2\.com;
    if ($invalid_referer) {
        return 403;
    }
    location / {        
        root D:/resource/;
    }
}

直接在浏览器访问:http://static.test3.com/fbb.jpg 是可以访问的,因为这时候没有referer头,符合none配置。

写个简单的html,包括如下内容:
<img src=”http://static.test3.com/fbb.jpg” />
访问html页面,发现图片无法出来,被403了。
把img内容改为 <img src=”http://static.test2.com/fbb.jpg” />这时候就可以正常访问了。
当referer验证不合法的时候,内置变量 $invalid_referer为1,所以会返回 403。

反向代理

反向代理使用proxy_pass指令来实现,也是非常好用的功能。出现上下文: http、server、location。
先来研究下最简单的proxy_pass使用:

示例1:
proxy_pass为单纯的域名,并且后缀没有带 /

server {
    listen  80;
    server_name static.test.com;
    location /web/ {
        proxy_pass  http://static.test2.com;
    }
}
server {
    listen  80;
    server_name static.test2.com;
    location / {        
        root D:/resource/;
    }
}

访问http://static.test.com/web/test.html 是正常的。
提取路径: /web/test.html,直接添加到 proxy_pass后面,就是最终访问路径。

示例2:
proxy_pass为单纯的域名,并且后缀带了/

server {
    listen  80;
    server_name static.test.com;
    location /web/ {
        proxy_pass  http://static.test2.com/;
    }
}
server {
    listen  80;
    server_name static.test2.com;
    location / {        
        root D:/resource/web;
    }
}

以上配置同样可以访问: http://static.test.com/web/test.html
当proxy_pass带了/的时候,解析如下 :
提取路径: /web/test.html,去掉 /web/, 得到 test.html,跟proxy_pass拼在一起,得到
http://static.test2.com/test.html

示例3:
proxy_pass除了域名,还带了路径,这种情况下,不管路径后面有没有/,都使用跟示例2一样的规则,配置如下:

server {
    listen  80;
    server_name static.test.com;
    location /web {
        proxy_pass  http://static.test2.com/web;
    }
}
server {
    listen  80;
    server_name static.test2.com;
    location / {        
        root D:/resource/;
    }
}

以上配置可以访问: http://static.test.com/web/test.html
解析如下 :
提取路径: /web/test.html,去掉 /web, 得到 /test.html,跟proxy_pass拼在一起,得到
http://static.test2.com/web/test.html

示例4:
如果location使用正则匹配,则proxy_pass只允许使用没有带/后缀的域名配置,否则会报错。

server {
    listen  80;
    server_name static.test.com;
    location ~/web {
        proxy_pass  http://static.test2.com;
    }
}
server {
    listen  80;
    server_name static.test2.com;
    location / {        
        root D:/resource/;
    }
}

小结:
1. 当proxy_pass只配置域名,而且没有以/结尾,原始路径会保留,否则会截取掉再拼装路径。
2. 如果proxy_pass上下文用了正则,那么proxy_pass只允许使用不带/的域名配置。

在配置反向代理的时候,通常还会这样配置:

location ~/web {
    proxy_set_header            Host $host;
    proxy_set_header            X-real-ip $remote_addr;
    proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass  http://static.test2.com;
}   

这主要是为了跟踪发起请求的客户端的真正ip地址,后端语言从header中获取ip地址。

nginx的全局变量

变量名称 说明
args 请求中的参数部分
content_length 请求头中的Content-length字段
content_type 请求头中的Content-Type字段
cookie_COOKIE cookie COOKIE变量的值
document_root 当前请求在root指令中指定的值
host 请求主机头字段,否则为服务器名称
http_HEADER http某个请求头,跟cookie_COOKIE使用类似
is_args 如果有args参数,这个变量等于”?”,否则等于””,空值
http_user_agent 客户端agent信息
http_cookie 客户端cookie信息
query_string 与args相同
request_method 客户端请求的动作,通常为GET或POST
remote_addr 客户端的IP地址
remote_port 客户端的端口
request_uri 包含请求参数的原始URI,不包含主机名,如:”/path/hellp.jsp?item=1”。不能修改schemeHTTP方法(如http,https)
server_protocol 请求使用的协议,通常是HTTP/1.0或HTTP/1.1server_addr服务器地址,在完成一次系统调用后可以确定这个值server_name服务器名称server_port请求到达服务器的端口号

更详细的见官方文档: http://nginx.org/en/docs/varindex.html

参考

http://nginx.org/en/docs/varindex.html
http://www.cnblogs.com/lidabo/p/4169396.html
http://yuanhsh.iteye.com/blog/1321982
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html
http://www.linuxidc.com/Linux/2014-01/95493.htm