跳到主要内容
注册无需实名认证
安云主机 AnYun VPS

教程 · 建站与 Web

用 Nginx 反向代理后端应用(含 WebSocket 与真实 IP)

难度

进阶

预计时长

20 分钟

步骤

7

最近修订

基准系统

Debian 12

要点

用 Nginx 反向代理后端应用(含 WebSocket 与真实 IP)

反向代理让 Nginx 在 80/443 上接收请求,再转发给只监听 127.0.0.1 的后端应用。关键是四个 proxy_set_header:Host、X-Real-IP、X-Forwarded-For、X-Forwarded-Proto,WebSocket 还需要 Upgrade 与 Connection 两个头。后端只绑回环地址,公网就无法绕过代理直连。

前置条件

开始之前,先确认这些都具备

  • 一个已经在本机某端口跑起来的后端应用(Node.js、Python、Go 均可)
  • 已安装 Nginx,并且域名已解析到本机

操作步骤

7

  1. 步骤 01 / 07

    先确认后端只监听回环地址 #

    这是反向代理最容易被忽略的安全前提:如果应用监听 0.0.0.0:3000,那么公网可以直接访问 3000 端口,你在 Nginx 上做的限速、认证、日志全部被绕过。ss 的输出里应当看到 127.0.0.1:3000 而不是 *:3000。

    Shell
    sudo ss -tlnp | grep 3000
    
    # 期望:127.0.0.1:3000
    # 如果是 0.0.0.0:3000,去改应用的监听地址,而不是靠防火墙补救
  2. 步骤 02 / 07

    为 WebSocket 准备一个 map #

    Connection 头不能写死成 upgrade,否则普通 HTTP 请求也会带上这个头,部分后端会因此报错。用 map 根据请求是否携带 Upgrade 来决定取值,这是官方文档给出的标准写法。map 必须放在 http 上下文里,所以单独放一个文件。

    Nginx 配置
    # /etc/nginx/conf.d/websocket-upgrade.conf
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }
  3. 步骤 03 / 07

    写代理 server 块 #

    四个转发头缺一不可:Host 让后端知道原始域名,X-Real-IP 与 X-Forwarded-For 让日志里不再全是 127.0.0.1,X-Forwarded-Proto 让后端知道外面走的是 HTTPS —— 少了最后一个,很多框架会生成 http 开头的绝对链接,在浏览器里表现为无限重定向。

    Nginx 配置
    # /etc/nginx/sites-available/app.example.com
    server {
        listen 80;
        server_name app.example.com;
    
        client_max_body_size 32m;
    
        location / {
            proxy_pass http://127.0.0.1:3000;
            proxy_http_version 1.1;
    
            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 Upgrade    $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
    
            proxy_connect_timeout 5s;
            proxy_read_timeout    300s;
        }
    }
  4. 步骤 04 / 07

    启用并验证 #

    先用本机 curl 带 Host 头测试,把「代理配置」与「DNS/防火墙」两类问题分开。502 通常意味着后端没起来或端口写错,504 意味着后端太慢。

    Shell
    sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
    sudo nginx -t && sudo systemctl reload nginx
    
    curl -I -H "Host: app.example.com" http://127.0.0.1
    sudo tail -f /var/log/nginx/error.log
  5. 步骤 05 / 07

    加上 HTTPS #

    和静态站点一样用 certbot 签发;插件会把 443 监听与证书行写进同一个 server 块。上线之后记得确认后端收到的 X-Forwarded-Proto 是 https。

    Shell
    sudo certbot --nginx -d app.example.com --agree-tos -m [email protected] --no-eff-email --redirect
    curl -sI https://app.example.com | head -n 1
  6. 步骤 06 / 07

    如果前面还有一层 CDN,需要还原真实 IP #

    套了 CDN 之后,Nginx 看到的 $remote_addr 是 CDN 边缘节点的地址。用 real_ip 模块把它还原成真实访客 IP,但 set_real_ip_from 必须逐段写明 CDN 官方公布的 IP 段 —— 写成 0.0.0.0/0 等于允许任何人伪造自己的来源 IP,把限速和封禁全部架空。

    Nginx 配置
    # /etc/nginx/conf.d/realip.conf
    # 下面的网段请从 CDN 官方公布的列表逐段填写,并定期更新
    set_real_ip_from 203.0.113.0/24;
    real_ip_header CF-Connecting-IP;
    real_ip_recursive on;
  7. 步骤 07 / 07

    长连接与大文件的两处调整 #

    服务端推送(SSE)和流式响应需要关掉缓冲,否则消息会被 Nginx 攒着不发;上传大文件要调高 client_max_body_size,默认 1 MB,超过就是 413。

    Nginx 配置
    location /events {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Connection '';
        proxy_buffering off;
        proxy_cache off;
        chunked_transfer_encoding off;
    }

常见错误

这一步最容易踩的坑

下面每一条都对应一个真实会发生的故障。先读完再动手,比出问题之后再回来查要省时间。

  • 后端监听 0.0.0.0,公网可以绕过代理直连端口。这是反向代理场景里最常见的安全漏洞。
  • 缺少 X-Forwarded-Proto,框架生成 http 链接,浏览器陷入重定向循环。排查半天才发现是一行 header 的事。
  • WebSocket 握手返回 400 或 426,几乎总是缺 Upgrade/Connection 头或忘了 proxy_http_version 1.1。
  • 上传报 413,是 client_max_body_size 没调;注意 Nginx 和后端框架两边都可能有各自的限制。
  • set_real_ip_from 写成 0.0.0.0/0。任何人都能伪造 X-Forwarded-For,你的限速与封禁形同虚设。
  • 502 时只盯着 Nginx 看。先确认后端进程还活着、端口没变 —— pm2 list 或 systemctl status 一眼就知道。
  • SSE/流式接口忘了关 proxy_buffering,表现为消息卡住不动直到连接结束。

这篇教程的边界

  • 命令以 Debian 12 为准。Ubuntu 与 Rocky Linux 的差异只在正文明确标注之处,未标注的部分请以你所用发行版的官方文档为准。
  • 示例中的 IP 来自文档保留段 203.0.113.0/24,域名为 example.com,端口为示意值。复制后必须替换成自己的值, 原样执行不会有任何效果。
  • 教程不能替代备份。任何会改动数据或线上流量的步骤,执行前先确认有一份验证过能恢复的备份。
  • 本站不提供任何用于绕过网络审查的配置或说明,这篇也不例外。

发现命令过时或有误,请发邮件到 [email protected]。 指出错误的邮件比沉默的旧文档有价值得多。

联系 工单
扫码
手机访问

扫码在手机上打开