侧边栏壁纸
博主头像
いちごみるく

行动起来,活在当下

  • 累计撰写 70 篇文章
  • 累计创建 48 个标签
  • 累计收到 55 条评论

目 录CONTENT

文章目录

nginx使用stream转发传递真实IP

PROXY protocol 需要发送端和接收端配套,不能只添加一行开关。下面以本机 HTTPS 转发为例;SSH 的限制见相关故障记录。

一、明确三种不同职责

  • proxy_protocol on;:在 Nginx 到后端的新连接开头发送 PROXY protocol v1 信息。
  • listen ... proxy_protocol;:要求该监听端口收到的连接先提供 PROXY protocol,再处理 TLS/HTTP 等后续数据。
  • set_real_ip_from 与 real_ip_header proxy_protocol:只信任指定代理提供的地址,并将 HTTP 请求的 $remote_addr 改为该地址。

它传递的是连接元数据,不是 HTTP 请求头,也不会自动让不支持协议的后端使用真实地址。HTTP 日志还可以记录 $proxy_protocol_addr;“收到地址”和“信任地址”应分别配置。NGINX 官方说明解释了这一区别。

检查实际运行的 Nginx,而不是系统里另一份同名二进制:

nginx -V 2>&1

这个例子需要 stream、stream_ssl_preread、http_ssl 和 http_realip 模块。只有接收的也是 stream 且需要改写其客户端地址时,才额外需要 stream_realip;发送 PROXY protocol 本身不要求两个 realip 模块都存在。

二、前端 TCP 443 转发

stream {
    server {
        listen 443;
        listen [::]:443;
        ssl_preread on;
        proxy_protocol on;
        proxy_pass 127.0.0.1:8443;
    }
}

前端是普通 TLS 客户端入口,listen 443 上没有 proxy_protocol 参数。普通浏览器不会发送 PROXY protocol。如果入口上游已经是受信任负载均衡器,则需要另行设计接收与传递流程。

三、HTTPS 后端接收并恢复地址

下面放在 http 上下文中。示例使用支持 http2 on 的 Nginx 1.25.1 或以后版本;证书文件与站点内容替换为实际值。

server {
    listen 127.0.0.1:8443 ssl proxy_protocol;
    http2 on;
    server_name www.example.com;

    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    set_real_ip_from 127.0.0.1;
    real_ip_header proxy_protocol;

    location / {
        root /var/www/example;
    }
}

后端绑定 loopback,使公网用户不能绕过前端直接给这个端口发送伪造的地址。若代理与后端在不同机器上,监听内部地址、用防火墙限制来源,再把 set_real_ip_from 改为实际代理 IP;不要信任 0.0.0.0/0 或 ::/0。经过 IPv6 loopback 转发时,还应相应使用并信任 ::1。

旧版 Nginx 的 HTTP/2 写法是 listen ... ssl http2 proxy_protocol。版本升级到支持新指令后可改为上面的写法。前后端必须对应:一端发送另一端未接收会破坏握手;后端要求接收但前端未发送同样会失败。

四、验证与边界

配置检查通过后 reload。用正确域名从外部访问 HTTPS,确认页面、证书和日志地址;再确认后端端口没有意外开放公网。访问应用时若还经过 Cloudflare 等代理,这里传递的是 Nginx 前端看到的连接地址,可能仍是 CDN 地址;恢复 CDN 的最终用户地址需要另外限定 CDN 来源并按其官方请求头规则处理。

普通 OpenSSH sshd 不直接解析 PROXY protocol。若 SSH 与 HTTPS 共用入口,需让 SSH 分支不发送该前缀,或由仅在本地监听的中转层先去掉前缀。这只能恢复兼容性,不能自动让 sshd 日志拥有最初的客户端 IP。

0

评论区