Nginx 反向代理

Nginx 反向代理配置和使用详解


📋 目录


反向代理基础

什么是反向代理

正向代理(Forward Proxy):
客户端 → 代理服务器 → 互联网 → 目标服务器
(客户端知道目标服务器,目标服务器不知道真实客户端)

反向代理(Reverse Proxy):
客户端 → 反向代理 → 后端服务器
(客户端不知道后端服务器,后端服务器不知道真实客户端)

反向代理的作用:

  • 隐藏后端服务器
  • 负载均衡
  • SSL/TLS 终端
  • 缓存加速
  • 安全防护
  • 统一入口

Nginx 反向代理架构

客户端请求
    ↓
Nginx 反向代理
    ↓
后端服务器(Web 应用、API 服务等)
    ↓
响应返回 Nginx
    ↓
返回给客户端

基本配置

最简单的反向代理

server {
    listen 80;
    server_name example.com;
 
    location / {
        proxy_pass http://backend_server:8080;
    }
}

带路径的反向代理

# 后端服务器: http://backend:8080/
 
# 方式 1: 不带 URI(保留原始路径)
location /api/ {
    proxy_pass http://backend:8080;  # 请求 /api/users → http://backend:8080/api/users
}
 
# 方式 2: 带 URI(替换路径)
location /api/ {
    proxy_pass http://backend:8080/;  # 请求 /api/users → http://backend:8080/users
}
 
# 方式 3: 自定义路径
location /old-api/ {
    proxy_pass http://backend:8080/new-api/;  # 请求 /old-api/users → http://backend:8080/new-api/users
}

多后端代理

# 定义 upstream
upstream backend {
    server app1.example.com:8080;
    server app2.example.com:8080;
    server app3.example.com:8080;
}
 
server {
    listen 80;
    server_name api.example.com;
 
    location / {
        proxy_pass http://backend;
    }
}

请求头设置

基本请求头

server {
    listen 80;
    server_name example.com;
 
    location / {
        # 设置 Host 头(重要!)
        proxy_set_header Host $host;
 
        # 设置真实 IP
        proxy_set_header X-Real-IP $remote_addr;
 
        # 设置 X-Forwarded-For
        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;
 
        # 设置原始 Host
        proxy_set_header X-Forwarded-Host $server_name;
 
        # 传递后端
        proxy_pass http://backend;
    }
}

完整请求头示例

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_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Forwarded-Host $server_name;
 
    # 附加信息
    proxy_set_header X-Request-ID $request_id;
    proxy_set_header X-Request-Start "t=${msec}";
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Original-Method $request_method;
 
    # 客户端信息
    proxy_set_header User-Agent $http_user_agent;
    proxy_set_header Accept-Language $http_accept_language;
    proxy_set_header Accept-Encoding $http_accept_encoding;
 
    proxy_pass http://backend;
}

条件设置请求头

location / {
    # 仅对特定请求设置请求头
    if ($request_method = POST) {
        proxy_set_header X-Request-Type "form-submit";
    }
 
    if ($http_user_agent ~* "mobile") {
        proxy_set_header X-Device-Type "mobile";
    }
 
    proxy_pass http://backend;
}
 
# 使用 map 更优雅的实现
map $http_user_agent $device_type {
    default "desktop";
    ~*mobile|android|iphone|ipad "mobile";
    ~*tablet|ipad "tablet";
}
 
server {
    location / {
        proxy_set_header X-Device-Type $device_type;
        proxy_pass http://backend;
    }
}

超时配置

连接超时

server {
    listen 80;
    server_name example.com;
 
    location / {
        # 连接超时(连接到后端)
        proxy_connect_timeout 5s;
 
        # 发送超时(发送请求到后端)
        proxy_send_timeout 60s;
 
        # 读取超时(等待后端响应)
        proxy_read_timeout 60s;
 
        proxy_pass http://backend;
    }
}

超时说明

指令说明推荐值
proxy_connect_timeout与后端建立连接的超时3-5s(短)
10-30s(长)
proxy_send_timeout发送请求到后端的超时60s
proxy_read_timeout等待后端响应的超时60s(普通)
300s(长轮询)

不同场景的超时配置

# 1. API 接口(短超时)
location /api/ {
    proxy_connect_timeout 3s;
    proxy_send_timeout 10s;
    proxy_read_timeout 10s;
    proxy_pass http://api_backend;
}
 
# 2. 文件上传(长超时)
location /upload/ {
    proxy_connect_timeout 5s;
    proxy_send_timeout 300s;      # 上传可能需要很长时间
    proxy_read_timeout 60s;
    proxy_pass http://upload_backend;
}
 
# 3. 长轮询/Websocket(非常长)
location /ws/ {
    proxy_connect_timeout 5s;
    proxy_send_timeout 3600s;     # 1 小时
    proxy_read_timeout 3600s;     # 1 小时
    proxy_pass http://ws_backend;
}
 
# 4. 普通网页(中等超时)
location / {
    proxy_connect_timeout 5s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    proxy_pass http://web_backend;
}

缓冲配置

请求缓冲

server {
    location / {
        # 是否缓冲客户端请求体
        proxy_request_buffering on;    # 默认 on
 
        # 客户端请求体大小限制
        client_max_body_size 10m;
 
        # 请求体缓冲区大小
        client_body_buffer_size 128k;
 
        proxy_pass http://backend;
    }
}

响应缓冲

server {
    location / {
        # 是否缓冲后端响应
        proxy_buffering on;            # 默认 on
 
        # 响应缓冲区数量和大小
        proxy_buffers 8 4k;            # 8 个 4k 缓冲区
 
        # 响应头缓冲区大小
        proxy_buffer_size 4k;          # 默认大小
 
        # 第一个响应包的超时
        proxy_buffering on;
 
        # 是否缓存到磁盘
        proxy_max_temp_file_size 1024m;  # 最大临时文件大小
        proxy_temp_file_write_size 8k;   # 每次写入大小
        proxy_temp_path /var/tmp/nginx;  # 临时文件路径
 
        proxy_pass http://backend;
    }
}

缓冲配置说明

指令说明推荐值
proxy_buffering是否启用响应缓冲on(默认)
proxy_buffers响应缓冲区数量和大小8 4k 或 8 8k
proxy_buffer_size响应头缓冲区大小4k 或 8k
proxy_busy_buffers_size忙缓冲区大小8k 或 16k
proxy_max_temp_file_size临时文件最大大小1024m
proxy_temp_file_write_size临时文件写入大小8k

不同场景的缓冲配置

# 1. 大文件下载(关闭缓冲)
location /download/ {
    proxy_buffering off;           # 关闭缓冲,直接转发
    proxy_pass http://file_backend;
}
 
# 2. SSE (Server-Sent Events)
location /events/ {
    proxy_buffering off;           # 关闭缓冲,实时转发
    proxy_cache off;
    proxy_pass http://sse_backend;
}
 
# 3. 普通网页(开启缓冲)
location / {
    proxy_buffering on;            # 开启缓冲
    proxy_buffers 16 4k;
    proxy_buffer_size 8k;
    proxy_pass http://web_backend;
}
 
# 4. API 接口(适度缓冲)
location /api/ {
    proxy_buffering on;
    proxy_buffers 4 4k;
    proxy_buffer_size 4k;
    proxy_pass http://api_backend;
}

错误处理

错误页面配置

server {
    listen 80;
    server_name example.com;
 
    location / {
        proxy_pass http://backend;
 
        # 拦截后端错误
        proxy_intercept_errors on;
 
        # 自定义错误页面
        error_page 404 /404.html;
        error_page 500 502 503 504 /50x.html;
 
        # 错误页面位置
        location = /50x.html {
            root /usr/share/nginx/html;
        }
 
        location = /404.html {
            root /usr/share/nginx/html;
        }
    }
}

后端错误重试

server {
    location / {
        proxy_pass http://backend;
 
        # 重试设置
        proxy_next_upstream error timeout;  # 在哪些情况下重试
        proxy_next_upstream_tries 3;        # 最大重试次数
        proxy_next_upstream_timeout 10s;    # 重试超时
 
        # 或者显示错误页面
        proxy_intercept_errors on;
        error_page 502 503 504 /error.html;
    }
}

健康检查(需要 nginx-plus 或第三方模块)

upstream backend {
    server backend1.example.com:8080 max_fails=3 fail_timeout=30s;
    server backend2.example.com:8080 max_fails=3 fail_timeout=30s;
    server backend3.example.com:8080 max_fails=3 fail_timeout=30s backup;
}
 
server {
    location / {
        proxy_pass http://backend;
 
        # 健康检查参数
        proxy_connect_timeout 3s;
        proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    }
}

负载均衡

基本负载均衡

upstream backend {
    # 轮询(默认)
    server backend1.example.com:8080;
    server backend2.example.com:8080;
    server backend3.example.com:8080;
}
 
server {
    location / {
        proxy_pass http://backend;
    }
}

加权轮询

upstream backend {
    server backend1.example.com:8080 weight=3;  # 3/6 的请求
    server backend2.example.com:8080 weight=2;  # 2/6 的请求
    server backend3.example.com:8080 weight=1;  # 1/6 的请求
}

IP 哈希

upstream backend {
    ip_hash;  # 根据客户端 IP 哈希
 
    server backend1.example.com:8080;
    server backend2.example.com:8080;
    server backend3.example.com:8080;
}

最少连接

upstream backend {
    least_conn;  # 选择连接数最少的后端
 
    server backend1.example.com:8080;
    server backend2.example.com:8080;
    server backend3.example.com:8080;
}

后端参数配置

upstream backend {
    server backend1.example.com:8080 max_fails=3 fail_timeout=30s weight=3;
    server backend2.example.com:8080 max_fails=3 fail_timeout=30s weight=2;
    server backend3.example.com:8080 max_fails=3 fail_timeout=30s backup;  # 备用
 
    keepalive 32;              # 长连接数
    keepalive_timeout 60s;     # 长连接超时
    keepalive_requests 100;    # 长连接最大请求数
}
 
server {
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;  # HTTP 1.1
        proxy_set_header Connection "";
    }
}

WebSocket 代理

WebSocket 基础配置

server {
    listen 80;
    server_name ws.example.com;
 
    location /ws/ {
        proxy_pass http://ws_backend;
 
        # WebSocket 支持
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
 
        # 超时设置(WebSocket 需要长连接)
        proxy_connect_timeout 7d;
        proxy_send_timeout 7d;
        proxy_read_timeout 7d;
 
        # 关闭缓冲
        proxy_buffering off;
    }
}

WebSocket 负载均衡

upstream ws_backend {
    # IP 哈希(WebSocket 需要会话保持)
    ip_hash;
 
    server ws1.example.com:8080;
    server ws2.example.com:8080;
}
 
server {
    listen 80;
    server_name ws.example.com;
 
    location /ws/ {
        proxy_pass http://ws_backend;
 
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
 
        # WebSocket 超时
        proxy_connect_timeout 7d;
        proxy_send_timeout 7d;
        proxy_read_timeout 7d;
        proxy_buffering off;
    }
}

🔧 高级技巧

动态后端选择

# 使用变量选择后端
upstream backend_a {
    server backend-a.example.com:8080;
}
 
upstream backend_b {
    server backend-b.example.com:8080;
}
 
server {
    listen 80;
    server_name example.com;
 
    location / {
        set $backend "backend_a";
 
        if ($http_user_agent ~* "mobile") {
            set $backend "backend_b";
        }
 
        proxy_pass http://$backend;
    }
}
 
# 使用 map 更优雅的实现
map $http_user_agent $backend {
    default "backend_a";
    ~*mobile "backend_b";
}
 
server {
    location / {
        proxy_pass http://$backend;
    }
}
upstream backend {
    server backend1.example.com:8080;
    server backend2.example.com:8080;
 
    # 根据 Cookie 选择后端(需要第三方模块)
    # hash $cookie_sessionid consistent;
}
 
server {
    location / {
        proxy_pass http://backend;
 
        # 设置会话 Cookie
        add_header Set-Cookie "backend=$upstream_addr; Path=/; HttpOnly";
    }
}

API 网关模式

# 多个后端服务
upstream user_service {
    server user1.example.com:8080;
    server user2.example.com:8080;
}
 
upstream order_service {
    server order1.example.com:8080;
    server order2.example.com:8080;
}
 
upstream product_service {
    server product1.example.com:8080;
    server product2.example.com:8080;
}
 
server {
    listen 80;
    server_name api.example.com;
 
    # API 网关路由
    location /api/users/ {
        proxy_pass http://user_service;
        proxy_set_header X-Service-Name "user-service";
    }
 
    location /api/orders/ {
        proxy_pass http://order_service;
        proxy_set_header X-Service-Name "order-service";
    }
 
    location /api/products/ {
        proxy_pass http://product_service;
        proxy_set_header X-Service-Name "product-service";
    }
 
    # 健康检查接口
    location /health {
        access_log off;
        return 200 "OK\n";
        add_header Content-Type text/plain;
    }
}

📚 相关链接


相关笔记