Nginx配置看起来简单,但坑真的多。
有些错误你可能永远发现不了(直到出事),有些错误会让你排查半天。整理一下常见的坑和调优经验。
proxy_pass结尾的斜杠
这个坑很常见。
# 前端请求 /api/users # 写法1 location /api { proxy_pass http://backend; } # 后端收到:/api/users # 写法2(多了个斜杠) location /api { proxy_pass http://backend/; } # 后端收到:/users ← /api没了!就差一个斜杠,效果完全不一样。
简单记:proxy_pass后面带路径(包括单独的/),location匹配的部分会被替换掉;不带路径,原样转发。
location匹配不是你想的那样
location /api { proxy_pass http://backend; } location ~ /api/v[0-9]+ { proxy_pass http://backend-new; }访问/api/v2/users,你觉得走哪个?
很多人以为按顺序,其实不是。正则匹配~优先于普通前缀匹配。所以走的是第二个。
但如果你想让某个路径不走正则:
location ^~ /api/internal { # ^~ 会阻止后面的正则匹配 proxy_pass http://internal-backend; } location ~ /api { proxy_pass http://backend; }^~前缀匹配的优先级比正则高。
完整优先级:=精确 >^~前缀 >~正则 > 普通前缀(取最长)
Vue/React项目刷新404
单页应用部署后,直接访问首页没问题,但刷新或直接访问子路由就404。
location / { root /var/www/dist; try_files $uri $uri/ /index.html; }这个配置应该没问题,但还是404?
检查这几个:
1、index.html存在吗?
ls-la/var/www/dist/index.html2、SELinux(CentOS的大坑)
getenforce# 如果是Enforcing# 临时关闭测试setenforce0# 或者正确设置contextchcon-R-thttpd_sys_content_t /var/www/distSELinux是CentOS上的常见坑。
502 Bad Gateway
高并发的时候出现502,后端其实没挂。
通常是upstream的连接数不够了。加上keepalive:
upstream backend { server 127.0.0.1:8080; keepalive 100; # 保持100个空闲连接 } location / { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Connection ""; # 这行很重要 }Connection ""是为了让Nginx用HTTP/1.1的keepalive,不然每次请求都新建连接。
上传大文件413
413 Request Entity Too LargeNginx默认只允许1M的请求体:
client_max_body_size 100m;放在http、server或location块都行。
WebSocket老断
WebSocket连上没多久就断了,通常是超时:
location /ws { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # 关键:超时设成长一点 proxy_read_timeout 3600s; proxy_send_timeout 3600s; }默认60秒没数据就断了,WebSocket要设长一点。
缓存设了不生效
location ~* \.(js|css|png)$ { expires 30d; }配置了但浏览器还是每次都请求?
检查后端有没有返回Cache-Control: no-cache,这会覆盖你的设置。
location ~* \.(js|css|png)$ { proxy_pass http://backend; proxy_ignore_headers Cache-Control Expires; # 忽略后端的 expires 30d; }性能调优
worker数量
worker_processes auto; # 自动等于CPU核数 events { worker_connections 10240; use epoll; multi_accept on; }Gzip
gzip on; gzip_min_length 1k; # 太小的不压缩 gzip_comp_level 5; # 压缩级别,5够用了 gzip_types text/plain text/css application/json application/javascript;静态文件
location ~* \.(js|css|png|jpg|gif|ico)$ { expires 1y; access_log off; # 静态文件不记日志,省IO }sendfile
sendfile on; # 零拷贝 tcp_nopush on; # 合并小包 tcp_nodelay on;常用配置模板
反向代理模板
server { listen 80; server_name api.example.com; location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; 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_set_header X-Forwarded-Proto $scheme; } }前端SPA模板
server { listen 80; server_name www.example.com; root /var/www/dist; location / { try_files $uri $uri/ /index.html; } location /api { proxy_pass http://127.0.0.1:8080; } location ~* \.(js|css|png|jpg|svg|woff2)$ { expires 1y; } }调试技巧
检查配置
nginx-t# 语法检查nginx-T# 打印完整配置打印变量
不确定变量值是什么的时候:
location /debug { return 200 "uri=$uri\nhost=$host\nargs=$args\n"; }看连接状态
location /status { stub_status on; allow 127.0.0.1; deny all; }然后curl localhost/status看当前连接数。
Nginx的坑基本就这些,配置的时候多注意斜杠、匹配顺序、超时时间,能避免大部分问题。