Nginx 反向代理深度解析与场景实践指南
一、反向代理核心概念
1.1 工作原理图解
| 流程节点 | 说明 |
|---------|------|
| Client(浏览器/APP) | 发起请求 |
| Nginx(反向代理服务器) | 接收请求并代理转发 |
| Backend(Node.js/Tomcat) | 处理请求并返回响应 |
请求链路:
Client(浏览器/APP)→ 发送请求 → Nginx(反向代理服务器)→ 代理转发 → Backend(Node.js/Tomcat)
响应链路:
Backend(Node.js/Tomcat)→ 返回响应 → Nginx(反向代理服务器)→ 返回响应 → Client(浏览器/APP)
1.2 关键优势特性
- IP隐藏:保护后端服务器真实地址
- 负载均衡:多实例流量分发
- SSL终结:集中管理HTTPS证书
- 请求过滤:WAF级安全防护
- 缓存加速:静态资源优化
二、核心配置指令精解
2.1 proxy_pass
location /api/ {
# 基础形态(带URI)
proxy_pass http://backend_server/app_context/;
# 高级形态(变量拼接)
proxy_pass http://$upstream$request_uri;
# 协议升级
proxy_pass https://secure_backend;
}
路径匹配规则表
| 原始路径 | proxy_pass 目标 | 最终请求路径 |
|---|---|---|
| /api/ | http://backend/ | /api/ |
| /api/ | http://backend/new_context/ | /new_context/ |
| /user/1 | http://backend/v2/ | /v2/user/1 |
2.2 proxy_set_header
proxy_set_header Header-Name "HeaderValue";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
标准头配置模板
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_set_header X-Forwarded-Port $server_port;
三、典型场景配置方案
3.1 Node.js 应用代理
upstream node_cluster {
server 127.0.0.1:3000 weight=5; # 主实例
server 192.168.1.10:3000 backup; # 热备节点
keepalive 32; # 长连接池
}
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/ssl/api.example.com.crt;
ssl_certificate_key /etc/ssl/api.example.com.key;
# WebSocket 支持
location /socket.io/ {
proxy_pass http://node_cluster;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s; # 长连接超时
}
# REST API 路由
location /api/v2/ {
proxy_pass http://node_cluster/v3/; # 路径重写
proxy_set_header X-API-Version "2.0";
proxy_redirect off;
}
}
3.2 Tomcat Java应用代理
upstream tomcat_servers {
least_conn; # 最小连接数策略
server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;
server 10.0.0.3:8080;
server 10.0.0.4:8080 down; # 维护节点
}
server {
listen 80;
server_name shop.example.com;
# JSP请求代理
location ~ \.jsp$ {
proxy_pass http://tomcat_servers;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_cookie_path / /; # 解决路径cookie问题
}
# 静态资源直通
location ~* \.(jpg|css|js)$ {
root /opt/static;
expires 30d;
access_log off;
}
# AJP协议支持
location /java-app/ {
proxy_pass ajp://tomcat_servers;
proxy_connect_timeout 5s;
}
}
四、进阶配置技巧
4.1 多协议支持
# gRPC 代理配置
location /grpc/ {
grpc_pass grpc://backend_grpc;
grpc_set_header Authorization $http_authorization;
}
# FastCGI 代理
location /php-app/ {
fastcgi_pass php_backend;
include fastcgi_params;
}
4.2 安全增强配置
proxy_hide_header X-Powered-By; # 隐藏敏感头
proxy_set_header X-Content-Type-Options "nosniff";
proxy_set_header Content-Security-Policy "default-src 'self'";
4.3 性能优化参数
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 256 8k;
proxy_busy_buffers_size 16k;
proxy_temp_path /var/nginx/proxy_temp;
proxy_connect_timeout 75s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
五、调试与排错指南
5.1 日志诊断配置
log_format proxy_debug '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'proxy: $upstream_addr time=$upstream_response_time';
access_log /var/log/nginx/proxy.log proxy_debug;
5.2 常见故障处理表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 502 Bad Gateway | 后端服务未启动或连接超时 | 检查后端状态,调整proxy_connect_timeout |
| 404 Not Found | proxy_pass路径配置错误 | 检查location匹配和proxy_pass URI |
| 丢失客户端真实IP | 未配置X-Forwarded-For头 | 添加proxy_set_header配置 |
| WebSocket连接失败 | 未设置Upgrade头 | 配置HTTP/1.1和Upgrade头 |
| Cookie路径错误 | 未设置proxy_cookie_path | 添加proxy_cookie_path / /; |
六、行业最佳实践
- 安全基线配置
# 强制头信息清理
proxy_hide_header Server;
proxy_hide_header X-AspNet-Version;
# 安全头设置
add_header Strict-Transport-Security "max-age=31536000" always;
- 灰度发布方案
map $cookie_user_type $backend {
default canary_backend;
"internal" production_backend;
}
server {
location / {
proxy_pass http://$backend;
}
}
- 多CDN源验证
location /verify/ {
proxy_pass http://cdn_origin;
proxy_cache_bypass $arg_nocache;
proxy_ssl_verify on;
proxy_ssl_name $proxy_host;
}