解决一些常见且通用的业务及规则配置问题
URL 最后的斜杠
如果访问的URL最后没有斜杠,Nginx会自动给补上后面的斜杠并且301跳转
如果使用了proxy_pass
等流量转发手段,则必须要加上关闭绝对路径:
否则会越过Router直接跳转到Backend
如果你的Nginx版本较低(1.11.8 以下),则需要使用禁止端口跳转:
或者是自己写判断规则,判断无斜杠是不是文件,如果不是,加一个斜杠
1 2 3 4 5 6 7 8 9
| if ( -d $request_filename ){ rewrite ^/(.*)([^/])$ https://api.myserver.com/$1$2/ permanent; }
if (-d $request_filename) { rewrite [^/]$ $scheme://$http_host$uri/ permanent; }
|
但是后面这种方案会使得一些API的URL被强行加上斜杠,即:
1 2 3 4 5 6 7 8 9 10
|
location /api { proxy_pass http://127.0.0.1:1111/; }
location /api/ { proxy_pass http://127.0.0.1:1111/; }
|
basic_auth
准备工具:
apache2-utils
(Debian, Ubuntu) or httpd-tools
(RHEL/CentOS/Oracle Linux)
生成密码文件:
1
| htpasswd -c /etc/apache2/.htpasswd user1
|
添加用户:
1
| htpasswd /etc/apache2/.htpasswd user2
|
加锁:
1 2 3 4
| location /api { auth_basic "Administrator’s Area"; auth_basic_user_file /etc/apache2/.htpasswd; }
|
不加锁:
1 2 3
| location /public/ { auth_basic off; }
|
IP控制
1 2 3 4 5 6 7 8 9 10 11 12
| location /api { satisfy all;
deny 192.168.1.2; allow 192.168.1.1/24; allow 127.0.0.1; deny all;
auth_basic "Administrator’s Area"; auth_basic_user_file conf/htpasswd; }
|
satisfy 可选 all (全部满足)或者 any(密码 ip 满足一个即可)
按路径反代
即将对应路径的流量转发至下级服务
1 2 3 4 5 6 7 8 9
| location /path/ { proxy_pass http://127.0.0.1:4444; }
location /path/ { proxy_pass http://127.0.0.1:9000/; }
|
案例1
设置路径为
1 2 3
| location /path { proxy_pass http://127.0.0.1:4444/; }
|
则有
1 2 3 4 5 6 7 8 9 10 11
| OK
301 -> myserver.com/?param=1 -> 404
OK
301 -> myserver.com/?param=1 -> 404
|
案例2
设置路径为
1 2 3
| location /path/ { proxy_pass http://127.0.0.1:4444/; }
|
则有
1 2 3 4 5 6 7 8 9 10 11
| 301 myserver.com/path/ -> OK
OK
301 myserver.com/path/?param=1 -> OK
OK
|
案例3
设置路径为
1 2 3
| location = /path { proxy_pass http://127.0.0.1:4444/; }
|
则有
总结
RESTful API 就直接用 location = /path
,没有 301
网站就用 location /path/
可以正确 301
网站别用 location /path
,跳转不正确导致 404,API 的话随意
WebSocket
如果需要反代至 WebSocket 协议,则 Header 中必须添加 “Upgrade” 字段,具体参见 Nginx 文档 WebSocket proxying:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| http { map $http_upgrade $connection_upgrade { default upgrade; '' close; }
server { ...
location /chat/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } } }
|
拉一个 docker
有了 Nginx 来统一管理 API 之后,使用 docker 来部署服务变得非常简单
1 2 3 4 5
| docker pull someimage
docker run
-v 映射空间,-p 本地端口:docker端口
|
完整配置示例
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
| user root; worker_processes 1; load_module /usr/lib/nginx/modules/ngx_stream_module.so; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; }
stream { map $ssl_preread_server_name $backend_name { myserver.com myserver; api.myserver.com api; cdn.myserver.com cdn; default bad; }
upstream myserver { server 127.0.0.1:666; } upstream api { server 127.0.0.1:777; }
upstream cdn { server 127.0.0.1:888; }
upstream bad { server 127.0.0.1:400; }
server { listen 443 reuseport; listen [::]:443 reuseport; proxy_pass $backend_name; ssl_preread on; } }
http { include /etc/nginx/mime.types; default_type application/octet-stream; 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 /var/log/nginx/access.log main; sendfile on; tcp_nopush on; keepalive_timeout 120; client_max_body_size 20m; gzip on; ssl_protocols TLSv1.2 TLSv1.3;
server { listen 80; listen [::]:80; server_name myserver.com api.myserver.com cdn.myserver.com; return 301 https://$host$request_uri; }
server { listen 80 default_server; listen [::]:80 default_server; server_name _; return 400; }
server { listen 127.0.0.1:888 ssl http2;
ssl_certificate /path/to/my/public.cer; ssl_certificate_key /path/to/my/private.key;
ssl_client_certificate /etc/nginx/ssl/cert/cloudflare.crt; ssl_verify_client on;
root /share; }
server { listen 127.0.0.1:777 ssl http2; root /path/to/api; index index.html; absolute_redirect off;
if (-d $request_filename) { rewrite [^/]$ $scheme://$http_host$uri/ permanent; }
location /private/ { auth_basic "Login required"; auth_basic_user_file /etc/nginx/passwd/.htpasswd; autoindex on; }
location /public/ { autoindex on; }
location /service/ { proxy_pass http://127.0.0.1:8080/; }
ssl_certificate /path/to/my/public.cer; ssl_certificate_key /path/to/my/private.key; }
server { listen 400 ssl; ssl_reject_handshake on; } }
|
其他配置参考
Nginx 正确安装姿势
Nginx 配置:业务部分
Nginx 配置:证书
Nginx 配置:基于 SNI 的分流
Nginx 配置:安全