1. Nginx是什么?Nginx (engine x) 是一个高性能的HTTP静态页面服务器,更是一个常用的反向代理服务器,同时还可以作为IMAP/POP3/SMTP代理服务器。
经常使用Nginx服务器,进行一些简单配置,但只是从网上照抄,知其然不知其所以然。 本文,我们主要学习一下nginx的目录结构和基础规则,补一补nginx基础。
2. 安装Nginxlinux中安装nginx,参考文档《CentOS7设置Nginx开机自启动》
docker安装nginx,参考文档《使用Docker安装配置Nginx》
3. 目录结构因为nginx目录是可以指定的,所以真实使用的目录结构请以命令查看。
3.1. 程序目录可能的程序目录:
3.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.3. 根目录可能的默认根目录:
根目录下一般会有nginx自带的index.html和50x.html。
curl ${nginx_server}
时看到内容,就是index.html文件中的内容。
我们自己的静态页面项目,最好不要放到默认根目录下,因为默认根目录可以通过ip和路径访问到,这往往是不符合预期的。 推荐的静态页面项目目录为:/usr/share/nginx/work
3.4. 日志目录可能的默认日志目录:
日志文件中一般有两个日志文件,error.log和access.log。
4. 常用命令4.1. 测试配置4.2. 重新加载配置4.3. 重启nginx1 2 3 4 5 systemctl restart nginx ps -ef | grep nginx kill -9 xxx/usr/sbin/nginx -c /etc/nginx/conf/nginx.conf
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目录,专门放置四层代理配置。
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; } ... }
6. 配置文件优先级conf.d中的配置文件,是按照名称顺序有优先级的,第一个匹配到的配置文件会作为default。 如果一个域名指向了nginx,但是nginx中没有这个域名的配置,那么就会走default配置。 详情参考《使用Docker安装配置Nginx》 文中的【重定向问题排查】一节。
7. 基础规则7.1. location规则在常见配置中,我们看到了一个叫 location 的关键字。location规则为:
1 location [ = | ~ | ~* | ^~ ] /uri / { ... }
紧跟在location后面的,是可选的修饰符,uri是要匹配的字符串。
常见匹配:
location = /uri
精确匹配location ^~ /uri
前缀匹配,在正则匹配之前location ~ pattern
正则匹配,区分大小写location ~* pattern
正则匹配,不区分大小写location /uri
前缀匹配,在正则匹配之后location /
通用匹配,未匹配到其它location的请求会匹配到它详情参考location 匹配规则
7.2. 匹配规则匹配过程: 1、精确匹配 2、前缀匹配(^~
) 3、正则匹配(按配置顺序) 4、前缀匹配(/xxx
) 5、通用匹配
其中前缀匹配如果有包含关系时,遵循最大匹配原则。
7.3. proxy_pass规则如果nginx作为反向代理使用,那么必须要搞明白的就是proxy_pass的规则,这关系到请求能否打到正确的接口。 proxy_pass规则:
如果proxy_pass后面没有路径,那么转发时带上uri 如果proxy_pass后面有路径,那么转发时使用该路径替换匹配到的uri 7.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
被保留转发给了后端服务。
7.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
被去掉了。
7.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
,然后转发给了后端服务。
8. 配置日志格式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
9. 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 使用详解
10. 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的重定向配置与实践
11. 状态码1xx:信息响应类,表示接收到请求并且继续处理 2xx:处理成功响应类,表示动作被成功接收、理解和接受 3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理 4xx:客户端错误,客户请求包含语法错误或者是不能正确执行 5xx:服务端错误,服务器不能正确执行一个正确的请求 详情参考HTTP 状态码详解与选用