1. 前言Nginx是一个功能强大的服务器软件,通过合理的配置可以实现多种网络服务。 本文系统学习Nginx配置方法,备忘。
2. 配置文件目录可能的默认配置目录:
1 2 /etc/nginx/ /etc/nginx/conf
nginx.conf一般放在这两个目录中,nginx.conf中会写清楚子配置目录,比如:
1 2 3 http { include /etc/nginx/conf.d/*.conf; }
那么,子配置文件就放在 /etc/nginx/conf.d/ 目录中,并且子配置文件必须以 .conf 结尾。一般情况下,我们比较少修改 nginx.conf,大部分时候都是修改子配置文件。
3. 配置文件结构配置文件由指令和指令块组成,指令块通常以大括号{}包围。
基本指令:
worker_processes:设置工作进程数。 events:配置事件模块。 http:配置HTTP模块。 stream:配置STREAM模块。 指令块:
server:定义一个服务器块,可以包含多个location块。 location:定义请求的处理规则。 4. 配置文件优先级conf.d中的配置文件,是按照名称顺序有优先级的,第一个匹配到的配置文件会作为default。 如果一个域名指向了nginx,但是nginx中没有这个域名的配置,那么就会走default配置。 详情参考《使用Docker安装配置Nginx》 文中的【重定向问题排查】一节。
5. 常用配置5.1. 静态页面服务器配置1 2 3 4 5 6 7 8 9 10 11 12 13 14 server { listen 80; server_name www.voidking.com; charset utf-8; location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; root /usr/share/nginx/html/; index index.html; } }
这个配置,是一个标准的静态页面服务器配置。 使用以上配置,如果已经配置好了域名解析,那么访问 www.voidking.com 时,就会看到nginx首页,也就是 index.html。
5.2. 反向代理到其他域名1 2 3 4 5 6 7 8 9 10 11 12 13 server { listen 80; server_name www.voidking.com; charset utf-8; location / { 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://voidking.coding.me; } }
使用以上配置,访问 www.voidking.com 时,实际上看到的是 voidking.coding.me 这个域名返回的内容。
5.3. 反向代理到一个服务1 2 3 4 5 6 7 8 9 10 11 12 13 server { listen 80; server_name www.voidking.com; charset utf-8; location / { 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://192.168.56.101:8080; } }
使用以上配置,访问 www.voidking.com 时,实际上看到的是 192.168.56.101:8080 这个服务返回的内容。
5.4. 反向代理到upstream1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 upstream www_voidking_com{ server 192.168.56.101:8080 weight=5; server 192.168.56.102:8081 weight=2; server 192.168.56.103:8000; } server { listen 80; server_name www.voidking.com; charset utf-8; location / { 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://www_voidking_com; } }
使用以上配置,访问 www.voidking.com 时,实际上看到的是upstream里的服务返回的内容。 但是问题来了,upstream里有三个服务,到底是哪个服务返回的内容呢?答:不一定,这就要用到传说中的加权轮询算法了。 三个服务的权值分别为 5、2、1(默认),从权值来看,最大可能打到第一个服务。 有没有想到什么知识点?没错,负载均衡,使用了加权轮询算法的负载均衡。
5.5. 反向代理到websocket服务Connection值硬编码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 http { server { listen 80; server_name www.voidking.com; charset utf-8; location ^~ /ws { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # websocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_pass http://192.168.56.101:8080; } location / { 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://192.168.56.101:8080; } } }
这种写法中,Connection的值直接被硬编码为upgrade。
动态设置Connection值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 http { map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name www.voidking.com; charset utf-8; location ^~ /ws { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # websocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_pass http://192.168.56.101:8080; } location / { 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://192.168.56.101:8080; } } }
这种写法中,Connection的值是变量$connection_upgrade
。该变量的值是根据请求头中的$http_upgrade
来决定的。如果$http_upgrad
e的值是默认值(即空),那么Connection的值会被设置为close,否则会被设置为upgrade。
更多内容参考一篇带给你Nginx代理WebSocket方法 和NGINX as a WebSocket Proxy
5.6. 配置域名证书1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 server { listen 80 ; listen 443 ssl; server_name www.voidking.com; charset utf-8 ; ssl_certificate /etc/nginx/ssl/1_www.voidking.com_bundle.crt; ssl_certificate_key /etc/nginx/ssl/2_www.voidking.com.key; ssl_session_timeout 5m ; ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2 ; ssl_ciphers HIGH:!ADH:!EXPORT56:RC4+RSA:+MEDIUM; ssl_prefer_server_ciphers on ; if ($ssl_protocol = "" ) { return 301 https://$host $request_uri ; } location / { proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; root /usr/share/nginx/work/voidking/; index index.html; } error_page 404 /404 .html; location = /404 .html { root /usr/share/nginx/work/voidking/; index 404 .html; } location ~ /\.git { return 404 ; } }
5.7. 四层代理5.7.1. 加载stream模块nginx四层代理依赖ngx_stream_core_module
模块(下面简称stream模块)。
1 2 nginx -V &> nginx_version.txt grep "stream" nginx_version.txt
如果看到--with-stream
,表明已经安装并开启stream模块。
nginx1.22.0以上版本默认支持并开启stream模块,一般配置路径为:/usr/share/nginx/modules/ ,在 nginx.conf 中include该路径。
如果是低版本的nginx,需要自行编译安装stream模块,或者使用包管理器安装stream模块。
1 yum install -y nginx-mod-stream
安装完成后,nginx.conf中加载ngx_stream_module.so
1 2 #load_module /usr/lib/nginx/modules/ngx_stream_module.so; load_module /usr/lib64/nginx/modules/ngx_stream_module.so;
5.7.2. 四层代理配置一个四层代理的实例:
1 2 3 4 5 6 7 8 9 10 11 12 stream { upstream remote_mysql { server 192.168.1.1:3306; } server { listen 3306 so_keepalive=on; # 开始TCP存活探测 proxy_connect_timeout 10s; # 连接超时时间 proxy_timeout 300s; # 端口保持时间 proxy_pass remote_mysql; } }
注意:stream是和http同一级的,不要配置到nginx/conf.d目录中。最好新建一个nginx/stream.d目录,专门放置四层代理配置。
1、修改 nginx.conf ,添加
1 2 3 stream { include /etc/nginx/stream.d/*.conf; }
2、添加一个 server 配置 stream.d/mysql.conf
1 2 3 4 5 6 7 8 9 10 upstream remote_mysql { server 192.168.1.1:3306; } server { listen 3306 so_keepalive=on; # 开始TCP存活探测 proxy_connect_timeout 10s; # 连接超时时间 proxy_timeout 300s; # 端口保持时间 proxy_pass remote_mysql; }
3、重新加载配置
1 2 nginx -t nginx -s reload
如果报错:nginx: [emerg] unknown directive “stream” in /etc/nginx/nginx.conf:17 那么需要安装 nginx-mod-stream
1 yum install nginx-mod-stream
5.8. 请求body大小1 2 3 Syntax: client_max_body_size size; Default: client_max_body_size 1m; Context: http, server, location
Sets the maximum allowed size of the client request body. If the size in a request exceeds the configured value, the 413 (Request Entity Too Large) error is returned to the client. Please be aware that browsers cannot correctly display this error. Setting size to 0 disables checking of client request body size.
参考文档ngx_http_core_module - client_max_body_size
5.9. 允许跨域允许某个域名跨域:
1 2 3 4 5 6 7 8 9 10 11 server { listen 80; server_name www.voidking.com; add_header Access-Control-Allow-Origin 'test.voidking.com'; add_header Access-Control-Allow-Headers '*'; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Allow-Methods "GET, POST, PUT, OPTIONS"; ... }
允许所有域名跨域:
1 2 3 4 5 6 7 8 9 10 11 server { listen 80; server_name www.voidking.com; add_header Access-Control-Allow-Origin '*'; add_header Access-Control-Allow-Headers '*'; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Allow-Methods "GET, POST, PUT, OPTIONS"; ... }
指定多个域名允许跨域:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 server { listen 80; server_name cdn.voidking.com; location /search.xml { if ($http_origin ~* (https?://(.+\.)?(voidking.com|www.voidking.com)$)) { set $allowed_origin $http_origin; } add_header 'Access-Control-Allow-Origin' $allowed_origin always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; root /usr/share/nginx/work/voidking/; index search.xml; } ... }
5.10. 支持SNI转发SNI(Server Name Indication)是一个TLS的扩展字段,对应nginx内置变量$ssl_preread_server_name
,可用于访问不同域名跳转到不同的后端地址,实现根据域名四层代理。
此外,还有两个常用的TLS扩展字段:
Protocol Version:对应nginx内置变量是 $ssl_preread_protocol
,可用于客户端不同TLS协议版本跳转到不同的后端地址,实现根据TLS协议版本四层代理。 ALPN(Application-Layer Protocol Negotiation),对应nginx内置变量是 $ssl_preread_alpn_protocols
,可用于根据客户端不同应用层协议版本跳转到不同后端地址,实现根据应用层协议的四层代理。 示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 stream { map $ssl_preread_server_name $name { ssltest.voidking.com backend; default backend2; } upstream backend { server 127.0.0.1:8888; } upstream backend2 { server 127.0.0.1:8889; } server { ssl_preread on; listen 443; proxy_pass $name ; } }
参考文档:
5.11. 404重定向到首页需求:访问URL test.voidking.com/x/y/z
时,如果路径不存在出现404,那么自定义404页面或者跳转到首页。
要将Nginx的404错误重定向到首页,我们可以使用error_page指令来捕获404错误,并使用rewrite指令或者location块来重定向到首页。
配置404重定向到首页,方法一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 server { listen 80; server_name test.voidking.com; root /path/to/your/webroot/; index index.html index.htm; location / { try_files $uri $uri/ =404; } error_page 404 /404.html; location = /404.html { internal; rewrite ^ / last; } }
在这个配置中,try_files指令用于尝试按顺序提供文件或目录。如果请求的文件或目录不存在,则返回404错误。error_page指令将404错误映射到/404.html,但请注意,实际上并不需要真实的/404.html文件。然后,我们定义了一个location块来处理/404.html请求,并使用rewrite指令将其重定向到首页(/)。internal指令确保该location块只能由Nginx内部调用,不能直接通过浏览器访问。
配置404重定向到首页,方法二:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 server { listen 80; server_name test.voidking.com; root /path/to/your/webroot/; index index.html index.htm; location / { try_files $uri $uri/ =404; } error_page 404 /index.html; location = /index.html { internal; } }
在这个配置中,我们直接将404错误重定向到/index.html(即首页)。同样,我们定义了一个location块来处理/index.html请求,并使用internal指令确保它只能由Nginx内部调用。
配置自定义404页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 server { listen 80; server_name test.voidking.com; root /path/to/your/webroot/; index index.html index.htm; location / { try_files $uri $uri/ =404; } error_page 404 /404.html; location = /404.html { root /path/to/your/webroot/; index 404.html; } }
5.12. 404重定向到不同路径需求:访问URL test.voidking.com/x/y/z
时,如果路径不存在出现404,那么跳转到 test.voidking.com/x
。其中 x
、y
、z
都代表一个字符串。
配置方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 server { listen 80; server_name test.voidking.com; root /usr/share/nginx/html/; index index.html index.htm; location / { # 尝试按照请求的URI提供文件,如果文件不存在,则尝试下一个选项 try_files $uri $uri/ @redirect; } # 定义命名location来处理404重定向,重定向到第一级目录,实际在浏览器中看不到跳转 location @redirect { # 提取URI的第一级目录 rewrite ^/([^/]+)/(.*)$ /$1/ last; } # 错误页面配置,适用于第一级目录是404的URL error_page 404 /404.html; location = /404.html { root /usr/share/nginx/html/; index 404.html; } }
6. Nginx基础规则6.1. location规则在常见配置中,我们看到了一个叫 location 的关键字。location规则为:
1 location [ = | ~ | ~* | ^~ ] /uri / { ... }
紧跟在location后面的,是可选的修饰符,uri是要匹配的字符串。
常见匹配:
location = /uri
精确匹配location ^~ /uri
前缀匹配,在正则匹配之前location ~ pattern
正则匹配,区分大小写location ~* pattern
正则匹配,不区分大小写location /uri
前缀匹配,在正则匹配之后location /
通用匹配,未匹配到其它location的请求会匹配到它详情参考location 匹配规则
6.2. 匹配规则匹配过程: 1、精确匹配 2、前缀匹配(^~
) 3、正则匹配(按配置顺序) 4、前缀匹配(/xxx
) 5、通用匹配
其中前缀匹配如果有包含关系时,遵循最大匹配原则。
6.3. proxy_pass规则如果nginx作为反向代理使用,那么必须要搞明白的就是proxy_pass的规则,这关系到请求能否打到正确的接口。 proxy_pass规则:
如果proxy_pass后面没有路径,那么转发时带上uri 如果proxy_pass后面有路径,那么转发时使用该路径替换匹配到的uri 6.3.1. 保留uri1 2 3 4 5 6 7 location /test { 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://192.168.56.101:8080; }
访问 www.voidking.com/test/index 会被代理到 http://192.168.56.101:8080/test/index 这个url,/test/index
被保留转发给了后端服务。
6.3.2. 去掉uri1 2 3 4 5 6 7 location /test { 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://192.168.56.101:8080/; }
访问 www.voidking.com/test/index 会被代理到 http://192.168.56.101:8080/index 这个url,/test
被去掉了。
6.3.3. 替换uri1 2 3 4 5 6 7 location /test { 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://192.168.56.101:8080/qa/; }
访问 www.voidking.com/test/index 会被代理到 http://192.168.56.101:8080/qa/index 这个url,/test/index
被替换成了 /qa/index
,然后转发给了后端服务。
1 2 3 4 5 6 7 location /test { 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://192.168.56.101:8080/qa; }
访问 www.voidking.com/test/index 会被代理到 http://192.168.56.101:8080/qaindex 这个url,/test/index
被替换成了 /qaindex
,然后转发给了后端服务。
7. 配置日志格式1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 http { ... #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #log_format main '$remote_addr - $remote_port [$time_local] ' # '"$http_user_agent" "$http_x_forwarded_for" ' # '$host $http_host $scheme ' # '"$http_referer" "$request" ' # '"$request_uri" "$request_method" ' # '$request_time $request_length ' # '$status $bytes_sent ' # '$body_bytes_sent ' # '$upstream_addr $upstream_response_time'; log_format main escape=json '{ "@timestamp": "$time_local", ' '"http_user_agent": "$http_user_agent",' '"http_x_forwarded_for": "$http_x_forwarded_for",' '"remote_addr": "$remote_addr",' '"remote_port": "$remote_port",' '"host": "$host",' '"http_host": "$http_host",' '"scheme": "$scheme",' '"http_referer": "$http_referer",' '"request": "$request",' '"request_uri": "$request_uri",' '"request_method": "$request_method",' '"request_time": "$request_time",' '"request_length": "$request_length",' '"response_status": "$status",' '"bytes_sent": "$bytes_sent",' '"body_bytes_sent": "$body_bytes_sent",' '"upstream_addr": "$upstream_addr",' '"upstream_response_time": "$upstream_response_time"}'; }
字段 含义 示例 body_bytes_sent 响应body字节数 3650 bytes_sent 响应总字节数 175 host IP或域名(不包括端口) 10.10.10.14 http_host IP或域名(包括端口) 10.10.10.14:81 http_referer referer信息 http://10.10.10.14/ http_user_agent UA信息 Mozilla/5.0 http_x_forwarded_for XFF信息 192.168.1.1 remote_addr 客户端地址 10.10.10.1 remote_user 客户端认证用户名 admin request 请求URI和协议 GET request_body 请求的body request_length 请求长度 571 request_method 请求方法 GET request_time 请求处理时间 0.000 response_body 返回的body,依赖lua,需要编写lua脚本来采集 response_header_data 响应头数据,依赖headers-more-nginx-module schema 协议 http server_name 虚拟主机名称 server_port 服务器端口 server_protocol 服务器协议 ssl_cipher 交换数据中的算法 ssl_protocol SSL协议版本 status 返回状态码 404 time_local 时间戳 16/Jun/2019:23:29:50 upstream_addr 后端提供服务地址 upstream_connect_time 与服务器连接所花费的时间 upstream_response_time 后端处理时间 upstream_status upstream状态 200
参考文档:
修改日志格式后,需要重启nginx,然后查看日志确认格式
1 tail -f /opt/nginx/log/access.log
8. map指令map 的作用是创建自定义变量。
语法:
map 的var1为源变量,通常是nginx的内置变量,var2 是自定义变量。 var2 的值取决于 var1 在对应表达式的匹配情况。如果一个都匹配不到则 var2 就是 default 对应的值。
例子:
1 2 3 4 map $args $foo { default 0 ; debug 1 ; }
args 是nginx内置变量,就是获取的请求 url 的参数。 如果 args 匹配到 debug 那么 foo 的值会被设为 1 ,如果 args 一个都匹配不到 foo 就是 default 定义的值,在这里就是 0
参考文档Nginx map 使用详解
9. rewrite指令rewrite指令的作用是重定向。
语法:
1 rewrite regex replacement [flag]
rewrite:该指令是实现URL重写的指令。 regex:用于匹配URI的正则表达式。 replacement:将regex正则匹配到的内容替换成 replacement。 flag: flag标记。 flag有如下值:
last: 本条规则匹配完成后,继续向下匹配新的location URI 规则。(不常用) break: 本条规则匹配完成即终止,不再匹配后面的任何规则(不常用)。 redirect: 返回302临时重定向,浏览器地址会显示跳转新的URL地址。 permanent: 返回301永久重定向。浏览器地址会显示跳转新的URL地址。 例子:
1 rewrite ^/(.*) http://www.baidu.com/$1 permanent ;
rewrite 是固定关键字,表示开始进行rewrite匹配规则。 regex 是 ^/(.*)
,这是一个正则表达式,匹配完整的域名和后面的路径地址。 replacement 是 http://www.baidu.com/$1
,其中$1
是取regex部分()里面的内容,如果匹配成功后跳转到的URL flag 是 permanent,代表永久重定向的含义,即跳转到 http://www.baidu.com/$1
参考文档Nginx中的Rewrite的重定向配置与实践
10. 状态码1xx:信息响应类,表示接收到请求并且继续处理 2xx:处理成功响应类,表示动作被成功接收、理解和接受 3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理 4xx:客户端错误,客户请求包含语法错误或者是不能正确执行 5xx:服务端错误,服务器不能正确执行一个正确的请求 详情参考HTTP 状态码详解与选用