Nginx 反向代理与负载均衡配置

用 Nginx 把外部请求反代到后端应用,并用 upstream 做多实例负载均衡与 WebSocket 转发。

在你的服务器 / VPS 上,应用(Node.js、Python、Go 等)通常监听 3000、8080 这类端口。直接把这些端口暴露到公网并不理想:缺少 HTTPS、无法统一日志、也做不了多实例分流。更常见的做法是让 Nginx 监听 80/443,再把请求反向代理到后端。

安装 Nginx

Ubuntu / Debian:

sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx

站点配置放在 /etc/nginx/sites-available/,再软链到 /etc/nginx/sites-enabled/ 生效。

基础反向代理

把请求转发到本机 3000 端口的应用:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;

        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;
    }
}

这几个 proxysetheader 很关键:

  • Host:把原始域名带给后端,虚拟主机与重定向才正确。
  • X-Real-IP:后端看到的是真实客户端 IP,而非 Nginx 的 IP。
  • X-Forwarded-For:追加转发链,$proxyaddxforwardedfor 会保留已有值。
  • X-Forwarded-Proto:告诉后端原始协议是 http 还是 https。

改完先测试再重载,避免语法错误导致服务中断:

sudo nginx -t
sudo systemctl reload nginx

用 upstream 做负载均衡

当你把应用跑成多个实例(不同端口或不同机器)时,用 upstream 块把它们编成一组,proxypass 指向这个组名即可:

upstream backend {
    # least_conn;   # 可选:优先分给连接数最少的实例
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 10.0.0.12:3000 weight=2;   # 权重更高,分到更多流量
    server 10.0.0.13:3000 backup;     # 仅在其它实例都不可用时启用
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;
        proxy_set_header Host            $host;
        proxy_set_header X-Real-IP       $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

常见策略:

  • round-robin(默认):按顺序轮流分发,配合 weight 调整比例。
  • leastconn:把新请求发给当前活跃连接最少的实例,适合请求耗时不均的场景。
  • iphash:按客户端 IP 做哈希,让同一客户端固定落到同一实例(会话保持)。

Nginx 会被动探测后端:某个 server 连续失败会被临时摘除,过一段时间再试。

WebSocket 转发要点

WebSocket 依赖 HTTP 的 Upgrade 握手,默认不会被透传,必须显式补上:

location /ws/ {
    proxy_pass http://backend;

    proxy_http_version 1.1;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host       $host;

    proxy_read_timeout 3600s;   # 长连接避免被空闲超时切断
}

关键点:proxyhttpversion 1.1、透传 Upgrade 与 Connection 头,再把 proxyreadtimeout 调大,长连接才不会被过早断开。

小结

  • 反向代理让 Nginx 统一入口,proxypass 把流量转给后端端口。
  • Host / X-Real-IP / X-Forwarded-For / X-Forwarded-Proto 保证后端拿到真实客户端信息。
  • upstream 编组多实例,按 round-robin、leastconn 或 iphash 分流。
  • WebSocket 需显式透传 Upgrade/Connection 并放宽读超时。
  • 每次改完都先 nginx -t 再 reload,稳妥不断服。