lolly/docs/04-nginx-proxy-loadbalancing.md
xfy d8ac807cb7 docs(nginx): 更新代理与 stream 文档,新增 njs/可观测性/ACME 指南
- 04: 新增 random 负载均衡、upstream 响应时间变量详解
- 10: 新增访问控制、连接限制、地理/真实IP模块、高级日志配置
- 24: 新增 worker_aio_requests、EPOLLEXCLUSIVE 详解
- 30: njs JavaScript 模块完整指南
- 31: OpenTelemetry 可观测性集成指南
- 32: ACME 自动证书管理指南

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-07 17:06:38 +08:00

25 KiB
Raw Blame History

NGINX 反向代理与负载均衡指南

1. 反向代理基础

什么是反向代理

反向代理服务器接收客户端请求将请求转发给后端服务器获取响应后返回给客户端。NGINX 作为反向代理可以:

  • 隐藏后端服务器真实地址
  • 实现负载均衡
  • 缓存响应内容
  • SSL 终端加密
  • 压缩响应内容
  • 请求路由与重写

基础配置示例

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend.example.com: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;
    }
}

2. proxy_pass 指令详解

语法

proxy_pass URL;

URL 可以是:

  • HTTP 地址:http://backend:8080
  • HTTPS 地址:https://backend:8443
  • Unix Socketunix:/tmp/backend.socket
  • upstream 组:http://backend_group
  • 变量:http://$backend

URI 传递规则

带 URI 的 proxy_pass:请求 URI 中匹配 location 的部分会被替换。

location /name/ {
    proxy_pass http://127.0.0.1/remote/;
    # /name/test -> /remote/test
}

location /api/ {
    proxy_pass http://backend/v1/;
    # /api/users -> /v1/users
}

不带 URI 的 proxy_pass:请求 URI 以原始形式传递。

location /some/path/ {
    proxy_pass http://127.0.0.1;
    # /some/path/test -> /some/path/test
}

使用变量

location / {
    proxy_pass http://$backend;
    # 需要配合 resolver 指令解析域名
}

resolver 10.0.0.1 valid=300s;

3. 请求头设置

proxy_set_header

设置传递给后端服务器的请求头。

proxy_set_header Host $host;                   # 传递原始 Host
proxy_set_header Host $http_host;              # 传递 Host 头(含端口)
proxy_set_header Host backend.example.com;     # 固定 Host 值

proxy_set_header X-Real-IP $remote_addr;       # 客户端真实 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 代理链
proxy_set_header X-Forwarded-Proto $scheme;    # 原始协议

# 删除请求头
proxy_set_header Accept-Encoding "";           # 删除该字段

默认行为

头字段 默认值
Host $proxy_hostproxy_pass 中的地址)
Connection close

4. 负载均衡配置

upstream 块定义

upstream backend {
    server backend1.example.com weight=5;
    server backend2.example.com:8080;
    server 192.168.0.1:8080 max_fails=3 fail_timeout=30s;
    server backend3.example.com backup;        # 备份服务器
    server unix:/tmp/backend4;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

负载均衡算法

算法 指令 说明
轮询 默认 请求依次分发(加权)
最少连接 least_conn; 分配给活动连接最少的服务器
IP Hash ip_hash; 同一客户端 IP 始终路由到同一服务器
Hash hash key [consistent]; 基于指定键哈希,支持一致性哈希
随机 random [two [method]]; 随机选择two 表示选两台再择优

配置示例

轮询(默认)

upstream backend {
    server srv1.example.com;
    server srv2.example.com;
    server srv3.example.com;
}

加权轮询

upstream backend {
    server srv1.example.com weight=5;  # 5/7 的请求
    server srv2.example.com weight=2;  # 2/7 的请求
    server srv3.example.com;           # 1/7 的请求(默认 weight=1
}

最少连接

upstream backend {
    least_conn;
    server srv1.example.com;
    server srv2.example.com;
    server srv3.example.com;
}

IP Hash会话持久性

upstream backend {
    ip_hash;
    server srv1.example.com;
    server srv2.example.com;
    server srv3.example.com;
}

一致性哈希

upstream backend {
    hash $request_uri consistent;
    server srv1.example.com;
    server srv2.example.com;
    server srv3.example.com;
}

随机负载均衡1.15.1+

upstream backend {
    random;                              # 纯随机选择
    server srv1.example.com;
    server srv2.example.com;
    server srv3.example.com;
}

# Power of Two Choices 算法(更智能)
upstream backend {
    random two;                          # 随机选两台,按权重择优
    server srv1.example.com;
    server srv2.example.com;
    server srv3.example.com;
}

# 结合最少连接策略
upstream backend {
    random two least_conn;               # 随机选两台,选连接数少的
    server srv1.example.com;
    server srv2.example.com;
}

random 算法参数说明

参数 说明
two 随机选择两台服务器,再根据策略择优
least_conn two 配合,选择连接数较少的服务器
least_time=header two 配合选择响应头时间最短的服务器NGINX Plus
least_time=last_byte two 配合选择完整响应时间最短的服务器NGINX Plus

适用场景

  • 多个负载均衡器共享后端时避免锁竞争
  • 对一致性要求不高但需要低延迟的场景
  • 配合 zone 实现无锁负载均衡

server 指令参数

参数 说明 默认值
weight=N 权重值 1
max_conns=N 最大并发连接数 0无限制
max_fails=N 失败次数阈值 1
fail_timeout=T 失败统计时间及不可用持续时间 10s
backup 备份服务器(主服务器不可用时使用) -
down 标记为永久不可用 -
resolve 监控域名 IP 变化(需 zone + resolver -
upstream backend {
    zone backend 64k;
    resolver 10.0.0.1;

    server backend1.example.com weight=5 max_fails=3 fail_timeout=30s;
    server backend2.example.com resolve;
    server backup1.example.com backup;
}

5. 健康检查

被动健康检查(内置)

upstream backend {
    server srv1.example.com max_fails=3 fail_timeout=30s;
    server srv2.example.com max_fails=3 fail_timeout=30s;
}

机制

  • fail_timeout 时间内连续失败 max_fails 次,服务器标记为不可用
  • fail_timeout 时间后再次尝试

主动健康检查NGINX Plus

upstream backend {
    zone backend 64k;

    server srv1.example.com;
    server srv2.example.com;

    health_check interval=5s fails=3 passes=2;
    health_check uri=/health;
}

6. 超时配置

主要超时指令

指令 说明 默认值
proxy_connect_timeout 建立连接超时 60s
proxy_send_timeout 传输请求超时 60s
proxy_read_timeout 读取响应超时 60s
location / {
    proxy_connect_timeout 5s;
    proxy_send_timeout 10s;
    proxy_read_timeout 30s;
    proxy_pass http://backend;
}

7. 缓冲配置

响应缓冲

proxy_buffering on;                  # 默认 on
proxy_buffer_size 4k;                # 响应头缓冲区大小
proxy_buffers 8 16k;                 # 响应体缓冲区数量和大小
proxy_busy_buffers_size 32k;         # 同时发送给客户端的缓冲区总大小
proxy_max_temp_file_size 1024m;      # 临时文件最大大小
proxy_temp_file_write_size 64k;      # 每次写入临时文件大小

禁用缓冲(实时传输)

location /stream/ {
    proxy_buffering off;
    proxy_pass http://backend;
}

8. 缓存配置

缓存路径定义

http {
    proxy_cache_path /data/nginx/cache
        levels=1:2                    # 目录层级1:2 表示 16*256 个子目录)
        keys_zone=one:10m             # 共享内存区名称和大小1MB 约 8000 个键)
        inactive=60m                  # 非活动数据保留时间
        max_size=1g                   # 缓存最大大小
        use_temp_path=off;            # 临时文件存放位置
}

启用缓存

server {
    location / {
        proxy_cache one;              # 使用定义的缓存区
        proxy_cache_key "$host$request_uri";  # 缓存键
        proxy_cache_valid 200 302 10m;        # 200/302 响应缓存 10 分钟
        proxy_cache_valid 404 1m;             # 404 响应缓存 1 分钟
        proxy_cache_valid any 1m;             # 其他响应缓存 1 分钟
        proxy_pass http://backend;
    }
}

缓存条件控制

# 不从缓存获取响应的条件
proxy_cache_bypass $cookie_nocache $arg_nocache;

# 不将响应保存到缓存的条件
proxy_no_cache $http_pragma $http_authorization;

使用过期缓存

proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# 在后端错误、超时、正在更新时使用过期缓存

缓存锁

proxy_cache_lock on;                 # 同时刻只允许一个请求填充缓存
proxy_cache_lock_timeout 5s;         # 锁超时时间

9. 故障转移

proxy_next_upstream

定义在何种情况下将请求传递给下一台服务器。

proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_next_upstream_timeout 30s;     # 限制总时间
proxy_next_upstream_tries 3;         # 限制尝试次数

条件类型

条件 说明
error 与后端建立连接出错
timeout 连接、传输或读取超时
invalid_header 后端返回空或无效响应头
http_XXX 后端返回指定状态码
non_idempotent 非幂等请求POST、LOCK也进行重试

10. SSL/HTTPS 代理

代理到 HTTPS 后端

location / {
    proxy_pass https://backend.example.com;
    proxy_ssl_verify on;                         # 验证后端证书
    proxy_ssl_trusted_certificate /path/to/ca.crt;
    proxy_ssl_verify_depth 2;
    proxy_ssl_server_name on;                    # 启用 SNI
}

代理 SSL 配置

指令 说明 默认值
proxy_ssl 启用 HTTPS 代理 off
proxy_ssl_protocols 启用的协议 TLSv1.2 TLSv1.3
proxy_ssl_ciphers 加密套件 DEFAULT
proxy_ssl_verify 验证后端证书 off
proxy_ssl_verify_depth 验证深度 1
proxy_ssl_server_name 启用 SNI off
proxy_ssl_certificate 客户端证书 -
proxy_ssl_certificate_key 客户端密钥 -

11. WebSocket 代理

基础配置

location /chat/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

动态处理

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;
            proxy_read_timeout 3600s;  # 增加超时时间
        }
    }
}

12. 高级代理指令

proxy_bind

指定连接后端时使用的源地址用于多网卡服务器选择出口IP。

语法: proxy_bind address [transparent];
默认: 
上下文: http, server, location
proxy_bind $server_addr;              # 使用服务器IP
proxy_bind 192.168.1.1 transparent;   # 透明代理需要root权限

proxy_intercept_errors

拦截后端错误响应,配合 error_page 自定义错误页面。

语法: proxy_intercept_errors on | off;
默认: off
上下文: http, server, location
proxy_intercept_errors on;
error_page 500 502 503 504 /50x.html;

proxy_hide_header / proxy_pass_header

控制后端响应头的传递行为:

# 隐藏后端返回的特定头
proxy_hide_header X-Powered-By;
proxy_hide_header X-Runtime;

# 传递被默认隐藏的头
proxy_pass_header X-Accel-Redirect;
proxy_pass_header X-Accel-Limit-Rate;

proxy_ignore_headers

忽略后端的特定响应头如缓存控制允许NGINX处理这些头

proxy_ignore_headers Cache-Control Expires X-Accel-Redirect X-Accel-Expires;

修改后端返回的 Set-Cookie 头:

# 修改域名
proxy_cookie_domain localhost example.com;
proxy_cookie_domain off;              # 禁用域名修改

# 修改路径
proxy_cookie_path /foo/ /bar/;
proxy_cookie_path off;                # 禁用路径修改

# 添加安全标志
proxy_cookie_flags session httponly secure samesite=strict;
proxy_cookie_flags * samesite=lax;    # 应用到所有cookie

proxy_limit_rate

限制从后端读取响应的传输速率:

proxy_limit_rate 100k;                # 100KB/s

proxy_request_buffering

控制请求是否先完整缓冲再发送到后端:

proxy_request_buffering on;           # 默认,完整缓冲
proxy_request_buffering off;          # 流式传输,支持上传进度

proxy_redirect

修改后端返回的重定向头 Location 和 Refresh

proxy_redirect default;                                    # 使用默认替换
proxy_redirect off;                                        # 禁用替换
proxy_redirect http://localhost:8080/ http://$host/;       # 自定义替换
proxy_redirect ~^http://([^/]+)/(.+)$ http://$host/$2;      # 使用正则

13. SSL 客户端证书认证 (proxy_ssl_*)

用于 mTLS 双向认证场景NGINX 作为客户端向后端提供证书:

location / {
    proxy_pass https://backend.example.com;

    # mTLS 双向认证
    proxy_ssl_certificate /path/to/client.crt;
    proxy_ssl_certificate_key /path/to/client.key;

    # 验证后端证书
    proxy_ssl_verify on;
    proxy_ssl_trusted_certificate /path/to/ca.crt;
    proxy_ssl_verify_depth 2;

    # SSL协议和加密套件
    proxy_ssl_protocols TLSv1.2 TLSv1.3;
    proxy_ssl_ciphers HIGH:!aNULL;

    # 会话复用
    proxy_ssl_session_reuse on;

    # SNI支持
    proxy_ssl_server_name on;
    proxy_ssl_name backend.example.com;
}
指令 说明 默认值
proxy_ssl_certificate 客户端证书路径
proxy_ssl_certificate_key 客户端私钥路径
proxy_ssl_verify 验证后端证书 off
proxy_ssl_trusted_certificate 受信任CA证书
proxy_ssl_verify_depth 验证深度 1
proxy_ssl_protocols 启用的协议 TLSv1.2 TLSv1.3
proxy_ssl_ciphers 加密套件 DEFAULT
proxy_ssl_session_reuse 会话复用 on
proxy_ssl_name SNI名称

14. 高级缓存指令

proxy_cache_methods

指定可缓存的请求方法:

proxy_cache_methods GET HEAD POST;    # 可缓存 POST 请求

proxy_cache_min_uses

设置最小访问次数才开始缓存,避免缓存低频请求:

proxy_cache_min_uses 3;               # 第3次访问才开始缓存

proxy_cache_background_update

后台异步更新过期缓存(类似 stale-while-revalidate

proxy_cache_background_update on;

proxy_cache_revalidate

使用 If-Modified-Since 和 If-None-Match 重新验证缓存:

proxy_cache_revalidate on;            # 减少数据传输

proxy_cache_convert_head

自动将 HEAD 请求转为 GET 以获取响应体:

proxy_cache_convert_head on;          # 默认启用

proxy_cache_purge

支持 PURGE 方法清除缓存(需编译时启用):

location ~ /purge(/.*) {
    proxy_cache_purge cache_zone $1;
}

15. FastCGI 代理

基础配置

location ~ \.php$ {
    fastcgi_pass  localhost:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

FastCGI 指令完整列表

指令 语法 默认值 上下文
fastcgi_pass fastcgi_pass address; location
fastcgi_index fastcgi_index name; http, server, location
fastcgi_param fastcgi_param parameter value [if_not_empty]; http, server, location
fastcgi_split_path_info fastcgi_split_path_info regex; location
fastcgi_buffer_size fastcgi_buffer_size size; 4k/8k http, server, location
fastcgi_buffers fastcgi_buffers number size; 8 4k/8k http, server, location
fastcgi_busy_buffers_size fastcgi_busy_buffers_size size; 8k/16k http, server, location
fastcgi_temp_file_write_size fastcgi_temp_file_write_size size; 8k/16k http, server, location
fastcgi_temp_path fastcgi_temp_path path [level1 [level2 [level3]]]; http, server, location
fastcgi_cache fastcgi_cache zone; http, server, location
fastcgi_cache_key fastcgi_cache_key string; http, server, location
fastcgi_cache_valid fastcgi_cache_valid [code...] time; http, server, location
fastcgi_cache_methods fastcgi_cache_methods method...; GET HEAD http, server, location
fastcgi_cache_min_uses fastcgi_cache_min_uses number; 1 http, server, location
fastcgi_cache_bypass fastcgi_cache_bypass string...; http, server, location
fastcgi_no_cache fastcgi_no_cache string...; http, server, location
fastcgi_cache_use_stale fastcgi_cache_use_stale condition...; http, server, location
fastcgi_cache_background_update fastcgi_cache_background_update on/off; off http, server, location
fastcgi_cache_revalidate fastcgi_cache_revalidate on/off; off http, server, location
fastcgi_cache_lock fastcgi_cache_lock on/off; off http, server, location
fastcgi_cache_lock_timeout fastcgi_cache_lock_timeout time; 5s http, server, location
fastcgi_cache_convert_head fastcgi_cache_convert_head on/off; on http, server, location
fastcgi_connect_timeout fastcgi_connect_timeout time; 60s http, server, location
fastcgi_send_timeout fastcgi_send_timeout time; 60s http, server, location
fastcgi_read_timeout fastcgi_read_timeout time; 60s http, server, location
fastcgi_send_lowat fastcgi_send_lowat size; 0 http, server, location
fastcgi_request_buffering fastcgi_request_buffering on/off; on http, server, location
fastcgi_intercept_errors fastcgi_intercept_errors on/off; off http, server, location
fastcgi_hide_header fastcgi_hide_header field; http, server, location
fastcgi_pass_header fastcgi_pass_header field; http, server, location
fastcgi_ignore_headers fastcgi_ignore_headers field...; http, server, location
fastcgi_limit_rate fastcgi_limit_rate rate; 0 http, server, location

FastCGI 缓存完整配置示例

http {
    # 缓存路径定义
    fastcgi_cache_path /var/cache/nginx/php
        levels=1:2
        keys_zone=php:10m
        max_size=100m
        inactive=60m
        use_temp_path=off;

    server {
        listen 80;
        server_name example.com;

        location ~ \.php$ {
            # 启用缓存
            fastcgi_cache php;
            fastcgi_cache_key "$scheme$request_method$host$request_uri";

            # 缓存有效期
            fastcgi_cache_valid 200 302 1h;
            fastcgi_cache_valid 404 1m;
            fastcgi_cache_valid any 5m;

            # 使用过期缓存
            fastcgi_cache_use_stale error timeout updating http_500 http_503;

            # 后台更新
            fastcgi_cache_background_update on;

            # 重新验证
            fastcgi_cache_revalidate on;

            # 缓存锁
            fastcgi_cache_lock on;
            fastcgi_cache_lock_timeout 5s;

            # 绕过缓存条件
            fastcgi_cache_bypass $cookie_nocache $arg_nocache;
            fastcgi_no_cache $http_pragma $http_authorization;

            # FastCGI 后端
            fastcgi_pass unix:/run/php/php-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

            # 超时设置
            fastcgi_connect_timeout 5s;
            fastcgi_send_timeout 60s;
            fastcgi_read_timeout 60s;

            # 缓冲配置
            fastcgi_buffer_size 16k;
            fastcgi_buffers 8 16k;
            fastcgi_busy_buffers_size 32k;

            # 错误处理
            fastcgi_intercept_errors on;

            include fastcgi_params;
        }
    }
}

16. 内置变量

代理相关变量

变量 说明
$proxy_host proxy_pass 中的服务器名称和端口
$proxy_port proxy_pass 中的端口
$proxy_add_x_forwarded_for X-Forwarded-For 头 + 客户端 IP

Upstream 响应时间变量(用于性能监控)

变量 说明 单位
$upstream_addr 上游服务器地址IP:端口) -
$upstream_connect_time 与上游建立连接的时间(含 SSL 握手)
$upstream_header_time 接收到上游响应头的时间
$upstream_response_time 完整响应时间(从建立连接到接收完成)
$upstream_response_length 上游响应体长度 字节
$upstream_bytes_received 从上游接收的总字节数 字节
$upstream_bytes_sent 发送到上游的总字节数 字节
$upstream_status 上游返回的 HTTP 状态码 -
$upstream_cache_status 缓存命中状态HIT/MISS/EXPIRED 等) -
$upstream_queue_time 请求在队列中等待的时间NGINX Plus

日志格式中使用响应时间变量

log_format detailed '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    'rt=$request_time '
                    'uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" '
                    'urt="$upstream_response_time" '
                    'upstream=$upstream_addr '
                    'upstream_status=$upstream_status '
                    'upstream_bytes=$upstream_response_length';

access_log /var/log/nginx/access.log detailed;

响应时间变量解读

请求时间线:
客户端 ──▶ NGINX ──▶ 连接上游 ──▶ 发送请求 ──▶ 接收响应头 ──▶ 接收响应体 ──▶ 客户端
              │           │              │                │                │
              │           │              │                │                │
              └───────────┴──────────────┴────────────────┴────────────────┘
                          │              │                │
                    $upstream_     $upstream_       $upstream_
                    connect_time   header_time      response_time
  • $upstream_connect_timeTCP 连接 + SSL 握手时间
  • $upstream_header_time:从开始到收到响应头
  • $upstream_response_time:完整请求处理时间
  • $request_time:从客户端发起请求到响应完成(包含所有上游)

基于响应时间的告警配置示例

# 慢请求日志
map $upstream_response_time $slow_log {
    default 0;
    "~^[2-9]\." 1;    # 2秒以上
    "~^[0-9]{2,}" 1;  # 10秒以上
}

server {
    location /api/ {
        # 记录慢请求
        access_log /var/log/nginx/slow.log detailed if=$slow_log;
        proxy_pass http://backend;
    }
}

17. 综合配置示例

http {
    upstream backend {
        zone backend 64k;
        least_conn;

        server backend1.example.com weight=5 max_fails=3 fail_timeout=30s;
        server backend2.example.com resolve;
        server backup.example.com backup;

        keepalive 32;
    }

    proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=main:10m inactive=60m max_size=1g;

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Connection "";

            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_connect_timeout 5s;
            proxy_read_timeout 30s;

            proxy_cache main;
            proxy_cache_key "$host$request_uri";
            proxy_cache_valid 200 10m;

            proxy_next_upstream error timeout http_502 http_503;
        }

        location /api/ {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_buffering off;
        }

        location /ws/ {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_read_timeout 3600s;
        }
    }
}