Nginx配置文件详解

1、location 的匹配规则

location 的语法规则:

location [=|~|~*|^~] /uri/ {
      ...
}

符号含义:

符号 含义
=

表示精确匹配。只有完全相等于才能匹配上,比如 locating = /web/ 只有访问的url为 http://ip/web/ 才能匹配上,/web 和 /web/main 类似这些都无法匹配到。

^~ 表示 uri 以某个常规字符串开头。nginx 不对 url 做编码,因此请求为/static/20%/aa,可以被规则 ^~ /static/ /aa匹配到(注意是空格)
~ 表示区分大小写的正则匹配。正则匹配则意味着location ~后面的都是一个正则表达式,比如:location ~ /web/.*.html$  表示匹配符合前面是 /web/,以 .html 结尾的字符
~* 表示不区分大小写的正则匹配。同上。
/ 通用匹配,任何请求都会匹配到

同一个 server 中有多个 location 配置的情况下的匹配顺序为:

  1. 首先匹配 =

  2. 其次匹配 ^~

  3. 其次是按文件中顺序的正则匹配

  4. 最后是交给 / 通用匹配

  5. 当匹配成功时候会立即停止匹配,按当前匹配规则的 location 来处理请求

示例:

location = / {
   #规则A
}
location = /login {
   #规则B
}
location ^~ /static/ {
   #规则C
}
location ~ .(gif|jpg|png|js|css)$ {
   #规则D
}
location ~* .png$ {
   #规则E
}
location / {
   #规则F
}

效果:

访问根目录 /, 比如 http://localhost/ 将匹配规则 A
访问 http://localhost/login 将匹配规则 B,http://localhost/register 则匹配规则 F
访问 http://localhost/static/a.html 将匹配规则 C
访问 http://localhost/a.gif, http://localhost/b.jpg 将匹配规则 D和规则 E,但是规则 D 顺序优先,规则 E不起作用,而 http://localhost/static/c.png则优先匹配到规则 C
访问 http://localhost/a.PNG 则匹配规则 E,而不会匹配规则 D,因为规则 E 不区分大小写
访问 http://localhost/category/id/1111 则最终匹配到规则 F,因为以上规则都不匹配。这个时候一般可以配置 nginx 转发请求给后端应用服务器,比如 FastCGI(PHP),tomcat(jsp),nginx 作为反向代理服务器存在

1.1、实际使用示例

在实际使用中,一般会至少配置三个匹配规则,如下:

# 直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
# 这里匹配我们的静态首页,也可以转发给后端应用服务器
# 第一个必选规则
location = / {
    root    /usr/appname;
    index    index.html;   
    #proxy_pass http://tomcat:8080/index
}

# 第二个必选规则是处理静态文件请求,这是 nginx 作为 http 服务器的强项
# 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ~* .(html|gif|jpg|jpeg|png|css|js|ico)$ {
    root  /usr/appname;
    expires 1m;
}
location ^~ /static/ {
    root /webroot/static/;
}


# 第三个规则就是通用规则,用来转发动态请求到后端应用服务器
# 非静态文件请求就默认是动态请求,自己根据实际把握
location / {
    proxy_pass http://tomcat:8080/
}

一个推荐可供参考的配置文件:

    upstream myserver {
        hash $http_x_forwarded_for;
        #hash $remote_addr;
        #sticky;
        #server 192.168.118.128:9080;
        server 192.168.118.129:9080;
        check_interval=3000 rise=2 fall=5 timeout=1000 type=http;
        check_http_send "GET / HTTP/1.1
Connection:keep-alive

";
        check_http_expect_alive http_2xx http_3xx http_4xx;
        keepalive 100;
    }

    server {
        listen 8090;
        sever_name localhost;

        if($request_method !~ ^(GET|POST)) {
            return 444;
        }

        location =/ {
            root /root/myweb;
            index login/index.html;
        }

        location ~* .(html|gif|jpg|jpeg|css|js|png|ico|eot|ttf|woff|svg)$ {
            root /root/myweb;
            expires 1m;
        }

        location / {
            proxy_pass http://myserver;
            real_ip_header X-http_x_forwarded_for;
            proxy_set_header Connection "";
            proxy_set_header X-Real-IP $remote_addr;
        }
    }

1.2、精准匹配出现的问题

当配置的 location 的 URI 是目录而不是资源文件时,并且命中该 location 最后实际会访问资源文件,此时 Nginx 会再次接收到一个获取资源文件的请求,Nginx 会再次根据资源文件的请求的路径来匹配 location 并作出相应。

比如:

server {
    listen       80;
    server_name  localhost;

    location = /abc/ {
        root   /usr/webProjects/webFirst;
        index  abc.html;
    }
}

假设 Nginx 服务器上的 ip 为 192.168.118.128,我们通过浏览器请求 http://192.168.118.128/abc/,此时首先会命中 “location = /abc/” 规则,但你会发现浏览器可能会报 404,查看 Nginx 日志可以看到实际上并没有访问到 /usr/webProjects/webFirst/abc/abc.html 资源,而实际上是访问了 "/usr/local/nginx/html/abc/abc.html"  下的资源。报错日志如下:

 这是因为上面的配置中当命中 /abc/ 路径时,最后会访问到 abc.html ,Nginx 会再次接收到一个访问 /abc/abc.html 的请求,此时会再次根据 /abc/abc.html 来进行匹配。但是上面我们并没有配置该路径,所以最后会匹配到一个默认配置,即路径是 /,root 是 Nginx 安装目录下的 /usr/local/nginx/html 目录,所以最后访问了 "/usr/local/nginx/html/abc/abc.html"  下的资源而导致报错。

所以我们最好要加上一个匹配 /abc/abc.html 的配置,以便最后能访问到我们希望访问的资源:

server {
    listen       80;
    server_name  localhost;

    location = /abc/ {
        root   /usr/webProjects/webFirst;
        index  abc.html;
    }

    location = /abc/abc.html {   #上面的配置最后会命中到这里
        alias   /usr/webProjects/webFirst/user/user.html;
    }

    location = /abc/index.html {  #当上面的location=/abc/没有配置index时,最后会匹配到这里
        alias   /usr/webProjects/webFirst/user/user.html;
    }

    location ~* .(html|gif|jpg|jpeg|png|css|js|ico)$ {  #这里取代Nginx中的默认配置,即location路径为 /,root 为Nginx安装目录下的html文件夹
        root   /usr/webProjects/web01;
        expires 1m;
    }
}

1.3、正则匹配

Nginx 常见正则符合:

  • ^:匹配字符串的开始位置
  • $:匹配字符串的结束位置
  • .*: .匹配任意字符,*匹配数量0到正无穷
  • . 斜杠用来转义,. 表示匹配点符号 "."
  • (值1|值2|值3|值4):表示或匹配。例:(jpg|gif|png|bmp)匹配jpg或gif或png或bmp

2、root(服务器资源路径)

Nginx 中的 root 可以在 location 或者直接在 server 中配置,root 指定的是资源存放在服务器中的路径。root 既可以是绝对路径,也可以是相对路径,以 / 开头即为绝对路径。比如 location 中的 root 指定的是这个 location 规则所匹配的资源所存放的资源路径。

相对路径使用示例:

server {
        listen       80;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }
}

上面 location 中 root 所指向的 html 就是一个相对路径,相对的是当前这个配置文件的路径。假设此配置文件的位置是 /etc/nginx/conf.d,那么这个 html 的绝对路径就是 /etc/nginx/conf.d/html/。因此为避免出现不必要的麻烦,在配置 root 路径的过程中最好用绝对路径。

绝对路径使用示例:

server {
        listen       80;
        server_name  localhost;

        location / {
            root   /usr/local/nginx/html;
            index  index.html index.htm;
        }

        location /webTestProject/ {
            root   /usr/myTestData/;
            index  index.html index.htm;
        }
}

请注意,上面当我们访问 http://ip/webTestProject 时,实际上是访问了服务器中的 /usr/myTestData/webTestProject 路径。也就是说,当配置 root 时,最后访问到的资源路径会加上 location 中匹配到的 url。

Nginx中, 如果浏览器访问的 URI 最后带斜杠,比如:http://localhost/product/ ,则默认查找 product下的index页面,存在就返回;不存在且未开启自动索引目录选项(指令是:autoindex on),则报403错。如果浏览器访问的 URI 最后不带斜杠,比如:http://localhost/product,则会查找 product 文件,存在就返回。否则会自动将 uri 补全为 http://localhost/product/ ,浏览器自动发生 301 重定向跳转。

2.1、server中的root和location的root的区别

如果我们同时在 server 和 location 中都设置了 root 路径,例如:

server {
        listen       80;
        server_name  localhost;

        root   /usr/local/nginx2/html;

        location / {
            root   /usr/local/nginx/html;
            index  index.html index.htm;
        }
}

当我们访问服务器命中了 location 的配置时,nginx 的 location 会优先匹配到此代码块,会指向 location 中所配置的 root , server 中的 root 不会生效。当 nginx 找不到匹配到的 location 或者 location 中没有配置 root 时,此时才会使用 server 中的 root 配置。

3、alias

如下:

3.1、root 和 alias 的区别

root 和 alias 的区别在于 nginx 如何解释 location 后面的 uri,这会使两者分别以不同的方式将请求映射到服务器文件上。

  • root 的处理结果是:root路径 + location路径
  • alias 的处理结果是:使用 alias 路径替换 location 路径

alias是一个目录别名的定义,root则是最上层目录的定义。还有一个重要的区别是 alias 后面必须要用 “/” 结束,否则会找不到文件的,而 root 则可有可无。

当我们使用 root 指定资源的路径时,root 会将 location 后代的路径完整保留,映射进文件路径中。而 alias 会先过滤掉 location 后面的路径,然后再将 alias 路径 + 访问资源路径,就是最后所访问的资源路径。

比如:

# root 配置如下。如果此时一个请求的URI是 /t/a.html 时,web服务器将会返回服务器上的/www/root/html/t/a.html的文件。
location ^~ /t/ {
    root /www/root/html/;
}

# alias 配置如下。如果此时一个请求的URI是/t/a.html时,web服务器将会返回服务器上的/www/root/html/new_t/a.html的文件。
# 注意这里是new_t,因为alias会把location后面配置的路径丢弃掉,把当前匹配到的目录指向到指定的目录。
location ^~ /t/ {
    alias /www/root/html/new_t/;
}

使用alias时,目录名后面必须要加 "/"。alias只能位于location块中,root可以不放在 location 中。

alias 在使用正则匹配时,必须捕捉要匹配的内容并在指定的内容处使用。比如:

location ~ /mytest/(.*) {
      alias /usr/local/nginx/html/$1;
}

3、index(默认页面)

Nginx 可以在 location 中配置 index,index 配置的是网站初始页,也就是默认页面。该指令拥有默认值,index   index.html ,即如果没有给出index,默认初始页为index.html

比如配置如下:

server {
    listen       80;
    server_name  localhost;

    location /webTestProject/ {
        root   /usr/myTestData/;
        index  index.html index.htm;
    }
}

我们可以直接访问 http://ip//webTestProject/,会默认命中服务器中的 /usr/myTestData/webTestProject/index.html 资源。

4、proxy_pass

语法规则:

proxy_pass URL;      #URL必须以http://或者https://开头

proxy_pass 的作用域在 location。特点如下:

  1. 不影响浏览器地址栏的url
  2. 设置被代理server的协议和地址
  3. 协议可以为http或https
  4. 地址可以为域名或IP

4.1、proxy_pass 后面的路径带 / 和不带的区别

在 proxy_pass 中的代理 url 后加上 /,代理转发的 url 中就不会带上 location 中匹配路径(注意,只是不带location中匹配的,即只是截取掉location中指定的,剩下的还是会带到代理转发的 url 中)。如果后面没有/,代理转发的 url 中就会带上 location 中的匹配路径。

示例如下:

# url 后带 /(则不会加上location中的匹配路径)
# 下面我们访问 http://ip/proxy/home.html,最终会访问到 http://myIp/home.html
location /proxy/ { proxy_pass http://myIp/; } # url中不带 /(则会加上location中的匹配路径)
# 下面我们访问 http://ip/proxy/home.html,最终会访问到http://myIp/proxy/home.html。这里会将 location 中匹配的 proxy 也自动加到代理转发的地址后面
location /proxy/ { proxy_pass http://myIp; }

代理转发的地址后面如果还带目录,此时最后面有没有 "/" 也不一样。

详情如下:

# 代理转发的地址后面带目录和 /
# 此时我们访问 http://ip/proxy/index.html,最终会访问到http://myIp/myFolder/index.html
location /proxy/ {
     proxy_pass http://myIp/myFolder/;
}

# 代理转发的地址后面带目录但没有 /
# 此时我们访问 http://ip/proxy/index.html,最终会访问到http://myIp/myFolderindex.html,比较奇怪
location /proxy/ {
     proxy_pass http://myIp/myFolder;
}

可参考:https://www.cnblogs.com/bigberg/p/7651197.html

4.2、proxy_cookie_path(修改cookie作用域)

语法结构:

proxy_cookie_path path replacement;   #将cookie的作用域由path改为replacement

在使用代理转发时,可能会发生 cookie 丢失的问题。

比如代理转发配置如下:

location /aaa/ {
     proxy_pass http://myIp/;
}

此时我们访问 http://ip/aaa/project/sigin.do,Nginx 会转发至 http://myIp/project/sigin.do,假设我们通过 sigin 接口来登录,并且返回 cookie,在该 cookie 里面存放着登录信息。登录过后我们通过 http://ip/aaa/project/getUser.do 来继续请求接口,此时你可能会发现后端拿不到 cookie 信息。

这是因为 sigin.do 接口返回的 cookie 的作用域会是 /project,而我们通过 http://ip/aaa/project/getUser.do 来发出接口浏览器是不会带上 cookie,因为 cookie 的作用域不是 /aaa。此时我们应该修改配置如下:

location /aaa/ {
     proxy_pass http://myIp/;
     proxy_cookie_path  /project /aaa;  #将cookie的作用域由/project改为/aaa
}

可参考:https://blog.csdn.net/isyoungboy/article/details/81382193 

5、rewrite(重定向)

基本语法结构如下:

rewrite regex replacement [flag];    # regex:指定需要匹配的URI的正则表达式   replacement:将正则表达式匹配到的内容替换成replacement  flag:标记,可不加

该指令就是通过正则表达式的使用来更改浏览器的 url 。也就是当匹配到指定的正则表达式后,会将 replacement 作为一个新的 URI,组成一个新的 URL 返回给客户端,客户端会自动进行重定向即自动请求返回的新的 URL。

示例如下:

# 此时不管我们访问 http://ip/aaa/bbb/ 或者是 http://ip/ccc/aaa/bbb/ ,浏览器都会重定向到 http://ip/portal/。也就是会将replacement直接作为新的URI返回给客户端
location ~ /aaa/bbb/ {
     rewrite /aaa/  /portal/  permanent;
}

如果 replacement 是以 http://、https:// 或 $scheme 开头的字符串,则处理流程会立即停止并将 replacement  作为新的 URL 返回并重定向客户端。

rewrite 只能放在 server{},、location{}、if{} 块中。默认情况下,rewrite 会将旧的 URL 的请求参数(也就是 ?符号之后的参数)也拼接到新的 URL 后面,如果我们不希望这么做,可以在 replacement 的最后面添加一个 ? 符号。当然,replacement 本身也是可以写请求参数的。

# 此时我们访问 http://ip/aaa/bbb/?name=wen ,浏览器会重定向到 http://ip/portal/?name=wen
location ~ /aaa/bbb/ {
     rewrite /aaa/  /portal/  permanent;
}

# 如果不希望默认拼接旧的url的请求参数,则可以在replacement的最后面加一个?符号,此时重定向后的url就不会拼接旧的url的请求参数
# 下面我们访问 http://ip/aaa/bbb/?name=wen ,浏览器会重定向到 http://ip/portal?myage=12
location ~ /aaa/bbb/ {
     rewrite /aaa/  /portal?myage=12?  permanent;
}

可以同时存在一个或多个 rewrite 指令,会按照在配置文件中出现的顺序依次对 URL 进行匹配和处理。

当 rewrite 写在 location 里时,它们的执行顺序是:执行 server 块的 rewrite 指令  -->  执行 location 匹配  -->  执行选定的 location 中的 rewrite 指令。如果在某步中 URI 被重写了,则会重新循环执行1-3,直到找到真实存在的文件为之;循环超过10次,则会返回 500 Internal Server Error错误。所以当 rewrite 写在 location 里时,最好要用 break 作为标记,否则可能会发生上述错误。

如果正则表达式有出现 } 或 ; 字符,则整个正则表达式应使用单引号 ' 或双引号 " 括起来。

可参考:https://www.cnblogs.com/tugenhua0707/p/10798762.html

5.1、flag(标记)

flag 有如下值:

  1. last:本条规则匹配完成后,不会再执行后面的 rewrite 指令,但会根据新的 URI 来匹配新的 location,然后可能再继续执行该 location 下的 rewrite 指令。(不常用)
  2. break:本条规则匹配完成即终止,新的 URI 也不会再匹配后面的任何规则。(不常用)。
  3. redirect:返回 302 临时重定向,浏览器地址会显示跳转后的新的URL地址。
  4. permanent:返回 301 永久重定向,浏览器地址会显示跳转后的新的URL地址。
这里 last 和 break 区别有点难以理解:
  1. last 一般写在 server 和 if 中,而 break 一般使用在 location 中
  2. last 不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配
  3. break 和 last 都能继续执行 rewrite 指令的后面的指令?

因为 301 和 302 不能只简单地返回状态码,还必须有重定向的URL,这就是 return 指令无法直接返回301、302的原因了。

6、return 指令

停止处理请求,直接返回状态码或重定向到其他 URL。执行 return 指令后,location 中后续指令将不会被执行。

# 语法
return code [text];
return code [URL];
return URL;

上下文为server、location、if。

原文地址:https://www.cnblogs.com/wenxuehai/p/15096973.html