Nginx配置文件location配置详解

文章目录

  • Nginx配置文件location配置详解
  • location介绍
  • nginx文件结构
  • 访问控制
  • 基于用户认证
  • 开启状态页面
  • https配置
  • rewrite
  • if
  • 基于浏览器实现分离案例
  • 防盗链案例

location介绍

官方文档 location 指令是 nginx 中最关键的指令之一,location 指令的功能是用来匹配不同的 URI 请求,进而对请求做不同的处理和响应,这其中较难理解的是多个 location 的匹配顺序,本文会作为重点来解释和说明。

开始之前先明确一些约定,我们输入的网址叫做请求 URI,nginx 用请求 URI 与 location 中配置的 URI 做匹配。

nginx文件结构

首先我们先简单了解 nginx 的文件结构,nginx 的 HTTP 配置,由ngx_http_core_module模块引入。nginx的HTTP配置主要包括四个区块,结构如下:

http {//协议级别
  include mime.types;
  default_type application/octet-stream;
  keepalive_timeout 65;
  gzip on;
  upstream {//负载均衡配置
    ...
  }
  server {//服务器级别,每个server类似于httpd中的一个<VirtualHost>
    listen 80;
    server_name localhost;
    location / {//请求级别,类似于httpd中的<Location>,用于定义URL与本地文件系统的映射关系
      root html;
      index index.html index.htm;
    }
  }
}

http{}段配置指令:
server {}:定义一个虚拟主机,示例如下:

server {
  listen 80;
  server_name www.idfsoft.com;
  root "/vhosts/web";
}

listen:指定监听的地址和端口

listen address[:port];
listen port;

server_name NAME […]; 后面可跟多个主机,名称可使用正则表达式或通配符

当有多个server时,匹配顺序如下:

  • 先做精确匹配检查
  • 左侧通配符匹配检查,如*.idfsoft.com
  • 右侧通配符匹配检查,如mail.*
  • 正则表达式匹配检查,如~ ^.*.idfsoft.com$
    default_server

root path; 设置资源路径映射,用于指明请求的URL所对应的资源所在的文件系统上的起始路径

alias path; 用于location配置段,定义路径别名
index file; 默认主页面

index index.php index.html;

error_page code […] [=code] URI | @name 根据http响应状态码来指明特用的错误页面,例如 error_page 404 /404_customed.html

[=code]:以指定的响应码进行响应,而不是默认的原来的响应,默认表示以新资源的响应码为其响应码,例如 error_page 404 =200 /404_customed.html

log_format 定义日志格式

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
access_log  logs/access.log  main;

//注意:此处可用变量为nginx各模块内建变量

location区段,通过指定模式来与客户端请求的URI相匹配

//功能:允许根据用户请求的URI来匹配定义的各location,匹配到时,
//此请求将被相应的location配置块中的配置所处理,
//例如做访问控制等功能

//语法:location [ 修饰符 ] pattern {......}

常用修饰符说明:

修饰符

功能

=

精确匹配

~

正则表达式模式匹配,区分大小写

~*

正则表达式模式匹配,不区分大小写

^~

前缀匹配,类似于无修饰符的行为,也是以指定模块开始,不同的是,如果模式匹配,那么就停止搜索其他模式了,不支持正则表达式

@

定义命名location区段,这些区段客户端不能访问,只可以由内部产生的请求来访问,如try_files或error_page等

没有修饰符表示必须以指定模式开始,如:

server {
  server_name www.idfsoft.com;
  location /abc {
    ......
  }
}

那么如下内容就可正确匹配:

=:表示必须与指定的模式精确匹配,如:

server {
  server_name www.idfsoft.com;
  location = /abc {
    ......
  }
}

那么如下内容就可正确匹配:

如下内容则无法匹配:

~:表示指定的正则表达式要区分大小写,如:

server {
  server_name www.idfsoft.com;
  location ~ ^/abc$ {
  ......
  }
}

那么如下内容就可正确匹配:

如下内容则无法匹配:

~*:表示指定的正则表达式不区分大小写,如:

server {
  server_name www.idfsoft.com;
  location ~* ^/abc$ {
    ......
  }
}

那么如下内容就可正确匹配:

如下内容则无法匹配:

~:类似于无修饰符的行为,也是以指定模式开始,不同的是,如果模式匹配,则停止搜索其他模式

查找顺序和优先级:由高到底依次为

1.先精准匹配 = ,精准匹配成功则会立即停止其他类型匹配;

2.没有精准匹配成功时,进行前缀匹配。先查找带有 ^~ 的前缀匹配,带有 ^~ 的前缀匹配成功则立即停止其他类型匹配,普通前缀匹配(不带参数 ^~ )成功则会暂存,继续查找正则匹配;

3.= 和 ^~ 均未匹配成功前提下,查找正则匹配 ~ 和 ~* 。当同时有多个正则匹配时,按其在配置文件中出现的先后顺序优先匹配,命中则立即停止其他类型匹配;

4.所有正则匹配均未成功时,返回步骤 2 中暂存的普通前缀匹配(不带参数 ^~ )结果

以上规则简单总结就是优先级从高到低依次为(序号越小优先级越高)

1. location =    # 精准匹配
2. location ^~   # 带参前缀匹配
3. location ~    # 正则匹配(区分大小写)
4. location ~*   # 正则匹配(不区分大小写)
5. location /a   # 普通前缀匹配,优先级低于带参数前缀匹配。
6. location /    # 任何没有匹配成功的,都会匹配这里处

#案例分析

//修改配置文件
//删除原来location的内容添加新的内容
[root@Masters ~]# vim /usr/local/nginx/conf/nginx.conf
 42 
 43         location = / {
 45             echo "[ configuration A ]";				//绝对引用根访问时IP打印"[ configuration A ]"
 46          }
 47         
 48          location  / {
 49             echo "[ configuration B ]";				//在根下的文件打印"[ configuration B ]"
 50          }
 51         
 52          location /documents/ {
 53             echo "[ configuration C ]";				//在根下的/documents/目录下文件及目录打印"[ configuration C ]"
 54          }  
 55 
 56           location ^~ /images/ {
 57             echo "[ configuration D ]";				//在根下的/images/目录下的文件及目录打印"[ configuration D ]"
 58          }
 59 
 60          location ~* \.(gif|jpg|jpeg)$ {			//在根下的以.(gif|jpg|jpeg)结尾的文件打印"[ configuration E ]"
 61              echo "[ configuration E ]";
 62          }
[root@Masters ~]# nginx -s reload
[root@Masters ~]# systemctl restart nginx.service
[root@Masters ~]# ss -anlt
State       Recv-Q      Send-Q            Local Address:Port             Peer Address:Port      Process      
LISTEN      0           128                     0.0.0.0:80                    0.0.0.0:*                      
LISTEN      0           128                     0.0.0.0:22                    0.0.0.0:*                      
LISTEN      0           128                        [::]:22                       [::]:*

详细注解:

location = / {
# 只精准匹配 / 的查询.
[ configuration A ]
}
#匹配成功: /
location / {
# 匹配任何请求,因为所有请求都是以”/“开始
# 但是更长字符匹配或者正则表达式匹配会优先匹配
[ configuration B ]
}
#匹配成功:/index.html
location /documents {
# 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索/
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条/
[ configuration C ]
}
#匹配成功:/documents/document.html
#匹配成功:/documents/abc
location ~ /documents/ABC {
# 区分大小写的正则匹配
# 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索/
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条/
[ configuration CC ]
}
location ^~ /images/ {
# 匹配任何以 /images/ 开头的地址,匹配符合以后,立即停止往下搜索正则,采用这一条。/
[ configuration D ]
}
#成功匹配:/images/a.gif

location ~* .(gif|jpg|jpeg)$ {
# 匹配所有以 .gif、.jpg 或 .jpeg 结尾的请求,不区分大小写
# 然而,所有请求 /images/ 下的图片会被 [ config D ] 处理,因为 ^~ 到达不了这一条正则/
[ configuration E ]
}
#成功匹配:/documents/a.jpg

location /images/ {
# 字符匹配到 /images/,继续往下,会发现 ^~ 存在/
[ configuration F ]
}

location /images/abc {
# 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在/
# F与G的放置顺序是没有关系的/
[ configuration G ]
}

location ~ /images/abc/ {
# 只有去掉 [ config D ] 才有效:先最长匹配 [ config G ] 开头的地址,继续往下搜索,匹配到这一条正则,采用/
[ configuration H ]
}

Nginx配置文件配置详解_运维


Nginx配置文件配置详解_bc_02


Nginx配置文件配置详解_服务器_03

Nginx配置文件配置详解_运维_04


Nginx配置文件配置详解_nginx_05

访问控制

用于location段
allow:设定允许哪台或哪些主机访问,多个参数间用空格隔开
deny:设定禁止哪台或哪些主机访问,多个参数间用空格隔开
示例:

allow 192.168.1.1/32 172.16.0.0/16;
deny all;

实践:

//拒接本机访问

location / {
            echo "GUI";
            deny 192.168.79.1;
        }

Nginx配置文件配置详解_服务器_06

//除本主机外拒接所有访问
注意!deny all要写在后面,因为是依次检查规则的,如果第一条直接写deny all,下面的就不会被匹配到了。

 location / {
            echo "GUI";
            allow 192.168.79.1;
            deny all;
        }

基于用户认证

auth_basic “欢迎信息”;
auth_basic_user_file “/path/to/user_auth_file”

user_auth_file内容格式为:

username:password

这里的密码为加密后的密码串,建议用htpasswd来创建此文件:

htpasswd -c -m /path/to/.user_auth_file USERNAME

实践:

//下载httpd-tools
[root@Masters ~]# yum -y install httpd-tools

//修改配置文件
 [root@Masters ~]# vim /usr/local/nginx/conf/nginx.conf 
        location = / {
            root html;
            auth_basic "Welcome home!"
            auth_basic_user_file ".htpasswd"
            echo "GHI";
        }
        
//创建密码文件
[root@Masters ~]# cd /usr/local/nginx/conf/
[root@Masters conf]# htpasswd -c -m /usr/local/nginx/conf/.htpasswd GUI
New password: 
Re-type new password: 
Adding password for user GUI
[root@Masters conf]# cat .htpasswd 
GUI:$apr1$DX3M6FYG$5U1/X02PWEaU.NGs2HjYA/

Nginx配置文件配置详解_服务器_07


Nginx配置文件配置详解_nginx_08

开启状态页面

官方文档开启status:

location /status {
stub_status {on | off};
allow 172.16.0.0/16;
deny all;
}

访问状态页面的方式:http://server_ip/status

状态页面信息详解:

状态码

表示的意义

Active connections 2

当前所有处于打开状态的连接数

accepts

总共处理了多少个连接

handled

成功创建多少握手

requests

总共处理了多少个请求

Reading

nginx读取到客户端的Header信息数,表示正处于接收请求状态的连接数

Writing

nginx返回给客户端的Header信息数,表示请求已经接收完成,且正处于处理请求或发送响应的过程中的连接数

Waiting

开启keep-alive的情况下,这个值等于active - (reading + writing),意思就是Nginx已处理完正在等候下一次请求指令的驻留连接

实践:

//开启状态页面
location = /status {
            stub_status;
        }

Nginx配置文件配置详解_nginx_09

//开启状态页面基于用户认证
location = /status {
            stub_status;
            auth_basic "GHI";
            auth_basic_user_file ".htpasswd";
        }

Nginx配置文件配置详解_运维_10


Nginx配置文件配置详解_nginx_11

https配置

生成私钥,生成证书签署请求并获得证书,然后在nginx.conf中配置如下内容:

server {
listen 443 ssl;
server_name www.idfsoft.com;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}

实践使用OpenSSL实现:

//创建存放位置
[root@Masters ~]# cd /etc/Gin/KI/
[root@Masters KI]# mkdir private

//生成密钥
[root@Masters KI]# umask 077;openssl genrsa -out private/cakey.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.....................................................+++++
.........................................................................................+++++
e is 65537 (0x010001)

//提取公钥
[root@Masters KI]# openssl rsa -in private/cakey.pem -pubout
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyrcm52Nt2eLvdNOnbGMy
yigtRYK+w9ZXanb/8dVvLrAtU3LQb3fBNUU8z3EBegNp+b8SXHbGIx5/3cYuv9tH
duhY7YjccVY+ldyj9zheodXsXctX251hZ6oUPONFM/QnRzBooH2TQTXhnyq6D/zx
71mAHVAf5DlZ8DoJlmxnx50rtPOlc/7LRVQs4edUQiUaHSS93+CmSer1ICS5WKfo
Psg2peL6GrHTsUyqY8Cf210qq62fL8BOpvHXzUIJiIZjxV8/cho4BxccnstvDMrt
RmWWVKvGTFlDoyJQvBFWmLYXFqAmAdOFMAe8KHnY9iVZLryRI/P0z00Ouk3JG2od
RQIDAQAB
-----END PUBLIC KEY-----

//生成自签发证书
[root@Masters KI]# openssl rsa -in private/cakey.pem -pubout
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyrcm52Nt2eLvdNOnbGMy
yigtRYK+w9ZXanb/8dVvLrAtU3LQb3fBNUU8z3EBegNp+b8SXHbGIx5/3cYuv9tH
duhY7YjccVY+ldyj9zheodXsXctX251hZ6oUPONFM/QnRzBooH2TQTXhnyq6D/zx
71mAHVAf5DlZ8DoJlmxnx50rtPOlc/7LRVQs4edUQiUaHSS93+CmSer1ICS5WKfo
Psg2peL6GrHTsUyqY8Cf210qq62fL8BOpvHXzUIJiIZjxV8/cho4BxccnstvDMrt
RmWWVKvGTFlDoyJQvBFWmLYXFqAmAdOFMAe8KHnY9iVZLryRI/P0z00Ouk3JG2od
RQIDAQAB
-----END PUBLIC KEY-----
[root@Masters KI]# openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 365
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:HB
Locality Name (eg, city) [Default City]:WH
Organization Name (eg, company) [Default Company Ltd]:www.Gin.com
Organizational Unit Name (eg, section) []:www.Gin.com
Common Name (eg, your name or your server's hostname) []:www.Gin.com
Email Address []:123@5.com   
[root@Masters KI]# ls
cacert.pem  private
[root@Masters KI]# mkdir certs newcerts crl
[root@Masters KI]# touch index.txt && echo 01 > serial
[root@Masters KI]# ls
cacert.pem  certs  crl  index.txt  newcerts  private  serial
[root@Masters KI]# cd /usr/local/nginx/conf/
[root@Masters conf]# mkdir ssl
[root@Masters conf]# cd ssl/

//客户端证书
[root@Masters ssl]# umask 077;openssl genrsa -out nginx.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
...........................+++++
.............................................+++++
e is 65537 (0x010001)
[root@Masters ssl]# openssl req -new -key nginx.key -days 365 -out nginx.csr
Ignoring -days; not generating a certificate
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:^C
[root@Masters ssl]# openssl req -new -key nginx.key -days 365 -out nginx.csr
Ignoring -days; not generating a certificate
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:HB
Locality Name (eg, city) [Default City]:WH
Organization Name (eg, company) [Default Company Ltd]:www.Gin.com
Organizational Unit Name (eg, section) []:www.Gin.com
Common Name (eg, your name or your server's hostname) []:www.Gin.com   
Email Address []:123@5.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123
string is too short, it needs to be at least 4 bytes long
A challenge password []:
An optional company name []:
[root@Masters ssl]# ls
nginx.csr  nginx.key

//部署
[root@Masters ssl]# openssl ca -in nginx.csr -out nginx.crt -days 365
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Oct 13 20:35:41 2022 GMT
            Not After : Oct 13 20:35:41 2023 GMT
        Subject:
            countryName               = CN
            stateOrProvinceName       = HB
            organizationName          = www.Gin.com
            organizationalUnitName    = www.Gin.com
            commonName                = www.Gin.com
            emailAddress              = 123@5.com
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:
                04:7E:A7:7C:55:34:E8:B8:52:D0:C5:CE:FA:C4:14:E2:A5:96:08:A2
            X509v3 Authority Key Identifier:
                keyid:76:81:2D:69:5B:17:F6:52:4C:C4:91:7C:BC:FD:90:21:01:C0:49:F7

Certificate is to be certified until Oct 13 12:38:41 2023 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
[root@Masters ssl]# ls
nginx.crt  nginx.csr  nginx.key

[root@Masters ssl]# rm -f nginx.csr
[root@localhost ssl]# ls
nginx.crt  nginx.key

rewrite

语法:rewrite regex replacement flag;,如:

rewrite ^/images/(.*.jpg)$ /imgs/$1 break;

此处的$1用于引用(.*.jpg)匹配到的内容,又如:

rewrite ^/bbs/(.*)$ http://www.idfsoft.com/index.html redirect;

如上例所示,replacement可以是某个路径,也可以是某个URL

常见的flag

|flag |作用|
|–|–|–|
|last |基本上都用这个flag,表示当前的匹配结束,继续下一个匹配,最多匹配10个到20个 一旦此rewrite规则重写完成后,就不再被后面其它的rewrite规则进行处理 而是由UserAgent重新对重写后的URL再一次发起请求,并从头开始执行类似的过程|
|break |中止Rewrite,不再继续匹配 一旦此rewrite规则重写完成后,由UserAgent对新的URL重新发起请求, 且不再会被当前location内的任何rewrite规则所检查|
|redirect |以临时重定向的HTTP状态302返回新的URL|
|permanent |以永久重定向的HTTP状态301返回新的URL|

rewrite模块的作用是用来执行URL重定向。这个机制有利于去掉恶意访问的url,也有利于搜索引擎优化(SEO)

nginx使用的语法源于Perl兼容正则表达式(PCRE)库,基本语法如下:

标识符

意义

^

必须以^后的实体开头

$

必须以$前的实体结尾

.

匹配任意字符

[]

匹配指定字符集内的任意字符

[^]

匹配任何不包括在指定字符集内的任意字符串

()

分组,组成一组用于匹配的实体,通常会有

捕获子表达式,可以捕获放在()之间的任何文本,比如:

^(hello|sir)$       //字符串为“hi sir”捕获的结果:$1=hi$2=sir

//这些被捕获的数据,在后面就可以当变量一样使用了

示例:

案例1:将匹配到的URI重写至其它本机下的其它资源位置

#匹配到以images开头,以.jpg结尾的URI,重定向到imgs目录下的以.jpg结尾的文件
#$1是引用都第一个挂号内匹配到的内容
[root@nginx conf]# vim nginx.conf
..............
        location /images {
            rewrite ^/images/(.*\.jpg)$  /images/$1 break;
        }
...............
[root@Masters ~]# cd /usr/local/nginx/html/
[root@Masters html]# mkdir images
[root@Masters html]# cd images/
[root@Masters images]# ls
test.jpg
[root@Masters ~]# systemctl reload nginx.service

Nginx配置文件配置详解_服务器_12

案例2:将匹配到的URI重写至其它网页

#匹配到以ll开头的,/后面是任意内容的URI时,将重定向至www.zealf.red

[root@nginx conf]# vim nginx.conf
.............
        location /ll {
            rewrite ^/ll/.*$   https://www.zealf.red;
        }
.............
[root@Masters ~]# cd /usr/local/nginx/html/
[root@Masters html]# mkdir ll
[root@Masters html]# systemctl reload nginx.service

Nginx配置文件配置详解_运维_13

if

语法:if (condition) {…}

应用场景:

  • server段
  • location段

常见的condition

  • 变量名(变量值为空串,或者以“0”开始,则为false,其它的均为true)
  • 以变量为操作数构成的比较表达式(可使用=,!=类似的比较操作符进行测试)
  • 正则表达式的模式匹配操作
  • ~:区分大小写的模式匹配检查
  • ~*:不区分大小写的模式匹配检查
  • !和!*:对上面两种测试取反
  • 测试指定路径为文件的可能性(-f,!-f)
  • 测试指定路径为目录的可能性(-d,!-d)
  • 测试文件的存在性(-e,!-e)
  • 检查文件是否有执行权限(-x,!-x)

基于浏览器实现分离案例

if ($http_user_agent ~ Firefox) {
  rewrite ^(.*)$ /firefox/$1 break;
}

if ($http_user_agent ~ MSIE) {
  rewrite ^(.*)$ /msie/$1 break;
}

if ($http_user_agent ~ Chrome) {
  rewrite ^(.*)$ /chrome/$1 break;

防盗链案例

location ~* \.(jpg|gif|jpeg|png)$ {
  valid_referers none blocked www.idfsoft.com;
  if ($invalid_referer) {
    rewrite ^/ http://www.idfsoft.com/403.html;
  }
}