声明:本文部分内容使用AI辅助生成,经人工编辑、审核和补充个人经验。
更新说明:技术栈版本信息基于 Nginx 1.24+ / OpenSSL 3.x。
Nginx配置踩坑记录Nginx用了很多年了,从简单的静态站点到复杂的反向代理,踩过不少坑。记录一下常见配置和遇到的问题。
基础配置配置文件结构Nginx主配置文件通常位于/etc/nginx/nginx.conf:
1234567891011121314151617181920212223242526user nginx;worker_processes auto;events { worker_connections 1024;}http { include 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; error_log /var/log/nginx/error.log; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*;}
核心指令
指令
上下文
说明
示例
server
http
定义虚拟主机
server { ... }
location
server
定义请求处理规则
location / { ... }
listen
server
监听端口
listen 80;
server_name
server
服务器名称
server_name example.com;
root
location
网站根目录
root /var/www/html;
proxy_pass
location
反向代理地址
proxy_pass http://backend;
虚拟主机配置单站点配置12345678910111213141516171819202122232425server { listen 80; server_name example.com www.example.com; root /var/www/example.com; index index.html index.htm; # 静态文件缓存 location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { expires 30d; add_header Cache-Control "public, immutable"; } # 主location location / { try_files $uri $uri/ /index.html; } # 安全:禁止访问隐藏文件 location ~ /\. { deny all; access_log off; log_not_found off; }}
多虚拟主机12345678910111213141516171819202122232425262728293031323334# 站点1 - 主站server { listen 80; server_name example.com; root /var/www/example.com; index index.html;}# 站点2 - 博客server { listen 80; server_name blog.example.com; root /var/www/blog; index index.php; location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }}# 站点3 - API服务server { listen 80; server_name api.example.com; location / { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}
反向代理基础反向代理12345678910111213141516171819server { listen 80; server_name app.example.com; location / { proxy_pass http://localhost:8080; # 设置请求头 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; # 超时设置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; }}
WebSocket代理12345678910111213141516171819server { listen 80; server_name ws.example.com; location /socket.io/ { proxy_pass http://localhost:3000; proxy_http_version 1.1; # WebSocket必需头 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 长连接设置 proxy_read_timeout 86400; }}
代理第三方CDN资源123456789101112131415server { listen 80; server_name myapp.example.com; # 代理LinkedIn头像 location ^~ /third_image/ { add_header 'Access-Control-Allow-Origin' '$http_origin' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always; proxy_pass https://media.licdn.com/; proxy_set_header Referer ""; proxy_hide_header X-Frame-Options; }}
负载均衡负载均衡算法1234567891011121314151617181920212223242526upstream backend { # 轮询(默认) server 192.168.1.10:8080 weight=5; server 192.168.1.11:8080 weight=5; # IP哈希(会话保持) ip_hash; # 最少连接 least_conn; # 健康检查 server 192.168.1.12:8080 backup; server 192.168.1.13:8080 down;}server { listen 80; server_name lb.example.com; location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}
负载均衡策略对比
策略
指令
适用场景
轮询
默认
无状态服务,服务器性能相近
加权轮询
weight=
服务器性能不均衡
IP哈希
ip_hash
需要会话保持
最少连接
least_conn
长连接服务
一致性哈希
hash $request_uri
缓存场景
HTTPS配置HTTP跳转HTTPS1234567891011121314151617181920212223242526server { listen 80; server_name example.com www.example.com; # 所有HTTP请求跳转到HTTPS return 301 https://$server_name$request_uri;}server { listen 443 ssl http2; server_name example.com www.example.com; # SSL证书配置 ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; # SSL优化配置 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; root /var/www/example.com; index index.html;}
自动升级不安全请求123456789101112server { listen 443 ssl; server_name example.com; # 自动将HTTP资源升级为HTTPS add_header Content-Security-Policy "upgrade-insecure-requests" always; location / { root /var/www/example.com; try_files $uri $uri/ /index.html; }}
错误页面处理自定义错误页面12345678910111213141516171819202122server { listen 80; server_name example.com; error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /404.html { root /var/www/errors; internal; } location = /50x.html { root /var/www/errors; internal; } location / { root /var/www/example.com; try_files $uri $uri/ =404; }}
代理后端错误页面1234567891011121314151617server { listen 80; server_name app.example.com; proxy_intercept_errors on; location / { proxy_pass http://backend; proxy_set_header Host $host; } # 自定义404跳转 error_page 404 = @notfound; location @notfound { return 301 https://www.baidu.com; }}
URL重写与重定向rewrite指令12345678910111213141516171819server { listen 80; server_name example.com; # 内部代理(URL不变) location = /play { proxy_pass http://example.com/play.html; } # 301永久重定向(URL变化) location = /old-page { return 301 /new-page; } # rewrite重写 location /products/ { rewrite ^/products/(.*)$ /items/$1 last; }}
rewrite标志
标志
说明
last
重写后重新匹配location
break
重写后停止处理
redirect
302临时重定向
permanent
301永久重定向
跨域处理(CORS)基础跨域配置123456789101112131415161718server { listen 80; server_name api.example.com; location / { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Max-Age' 1728000 always; if ($request_method = 'OPTIONS') { return 204; } proxy_pass http://localhost:3000; }}
动态跨域配置12345678910111213141516171819202122map $http_origin $cors_origin { default ""; "~^https?://localhost(:[0-9]+)?$" $http_origin; "~^https?://.*\.example\.com$" $http_origin; "https://trusted-site.com" $http_origin;}server { listen 80; server_name api.example.com; location / { add_header 'Access-Control-Allow-Origin' $cors_origin always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; if ($request_method = 'OPTIONS') { return 204; } proxy_pass http://localhost:3000; }}
性能优化静态文件优化12345678910111213141516171819202122232425262728293031server { listen 80; server_name static.example.com; root /var/www/static; # 启用gzip压缩 gzip on; gzip_vary on; gzip_types text/plain text/css application/json application/javascript text/xml; gzip_min_length 1000; # 静态文件缓存 location ~* \.(jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # CSS/JS缓存 location ~* \.(css|js)$ { expires 30d; add_header Cache-Control "public"; access_log off; } # HTML不缓存 location ~* \.html$ { expires -1; add_header Cache-Control "no-store, no-cache, must-revalidate"; }}
连接优化123456789101112131415161718192021222324events { worker_processes auto; worker_connections 4096; use epoll; multi_accept on;}http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 30; keepalive_requests 1000; client_max_body_size 50m; client_body_buffer_size 128k; client_header_buffer_size 1k; open_file_cache max=1000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on;}
安全加固安全响应头123456789101112131415server { listen 443 ssl; server_name example.com; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; location / { root /var/www/example.com; index index.html; }}
访问控制1234567891011121314151617181920212223242526272829server { listen 80; server_name admin.example.com; # IP白名单 allow 192.168.1.0/24; allow 10.0.0.0/8; deny all; # 基础认证 location /admin { auth_basic "Admin Area"; auth_basic_user_file /etc/nginx/.htpasswd; try_files $uri $uri/ =404; } # 限速 location /api/ { limit_req zone=api_limit burst=10 nodelay; limit_conn addr_limit 10; proxy_pass http://backend; }}# 限流配置(http块中)http { limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; limit_conn_zone $binary_remote_addr zone=addr_limit:10m;}
坑1:location匹配顺序Nginx location匹配顺序很重要:
= 精确匹配
^~ 前缀匹配(匹配后不再检查正则)
~ 和 ~* 正则匹配
普通前缀匹配
12345location = /exact { # 精确匹配 }location ^~ /static { # 前缀匹配 }location ~ \.php$ { # 正则匹配 }location / { # 通用匹配 }}
坑2:proxy_pass斜杠问题123456789# 带斜杠 - 替换location部分location /api/ { proxy_pass http://backend/; # /api/users -> /users}# 不带斜杠 - 保留完整路径location /api/ { proxy_pass http://backend; # /api/users -> /api/users}
坑3:配置重载不生效有时候改了配置重载没效果:
12345678# 测试配置语法nginx -t# 完整重启sudo systemctl restart nginx# 或者强制重载sudo nginx -s reload
总结Nginx配置常见坑点:
location匹配顺序要注意,精确匹配放前面
proxy_pass斜杠有无区别大
HTTPS配置要配全,包括中间证书
静态文件缓存要合理设置过期时间
跨域配置要注意预检请求(OPTIONS)处理
配置修改后要restart,reload有时候不生效
Nginx配置看着简单,但细节很多。建议每次修改后都用nginx -t检查语法。