Proxy Protocol v2 详解

前言

在四层TCP转发、内网穿透、负载均衡场景,流量经过中转服务器之后,后端只能获取代理本地IP,丢失原始访客IP。

HTTP服务可以依靠 X-Forwarded-For 请求头传递IP,但纯TCP、UDP、数据库、游戏、SSL透传这类无应用层协议头的业务,无法使用HTTP头部方案。

Proxy Protocol(代理协议)由HAProxy官方推出,用于TCP连接建立初期传递客户端真实连接信息,分为 v1(ASCII文本)v2(二进制) 两个版本。

Proxy Protocol v2 是当前生产环境首选标准,解决了v1性能差、不支持UDP、无法扩展的短板。本文结合 FRP内网穿透 + Nginx Windows环境实战,完整讲解原理、报文结构、部署配置、故障排查。

一、Proxy Protocol v2 核心概念

Proxy Protocol 工作机制:

TCP三次握手完成之后、正式业务数据传输之前,代理程序向目标后端发送一段协议头部;后端服务解析头部,还原原始客户端IP、端口信息,随后正常处理业务数据流。

Proxy Protocol v2 核心优势:

  1. 二进制编码,解析效率远高于v1文本协议,适合高并发集群;
  2. 同时支持 TCP / UDP,v1仅支持TCP;
  3. 内置 TLV扩展字段,可携带TLS信息、连接唯一ID、ALPN等附加数据;
  4. 固定魔数字节,协议识别更加可靠;
  5. 头部最小仅28字节,带宽开销更低。

⚠️ 重要红线:发送端版本与接收端版本必须匹配

如果frpc发送v2,Nginx只支持接收v1,直接导致TCP连接断开、业务无法访问。

二、Proxy Protocol v1 与 v2 横向对比

对比项 Proxy Protocol v1 Proxy Protocol v2
编码格式 ASCII明文文本 二进制结构
支持传输层 仅TCP(TCP4/TCP6) TCP、UDP全部支持
可读性 抓包直接可读,便于调试 二进制,需要工具解析
扩展性 无扩展字段,功能固定 支持TLV扩展(SSL、连接ID等)
最小头部长度 不固定,最长上限108字节 固定最小28字节
解析性能 文本分割,CPU开销高 二进制顺序解析,开销极低
适用场景 老旧硬件兼容、调试环境 线上生产集群、UDP业务、内网穿透、四层负载均衡

行业通用建议:新项目、新服务一律优先选用 Proxy Protocol v2

三、Proxy Protocol v2 报文结构

v2头部整体分为三大部分:12字节魔数签名 + 4字节基础头 + 可变负载(地址信息+可选TLV扩展)

1. 固定魔数字节(12字节)

复制代码
0x0D 0x0A 0x0D 0x0A 0x00 0x0D 0x0A 0x51 0x55 0x49 0x54 0x0A

魔数用于后端快速识别:当前数据包是Proxy Protocol v2头部,避免和正常业务数据混淆。

2. 基础头部(4字节)

  1. 第13字节:版本+命令
    • 高4位:版本固定 0x2(代表v2)
    • 低4位:命令 PROXY(真实连接)/ LOCAL(本地健康检查,忽略IP信息)
  2. 第14字节:地址族 + 传输协议
    • IPv4 / IPv6 / Unix域套接字
    • TCP / UDP
  3. 第15、16字节(大端序):后续负载总长度

3. 地址负载(可变长度)

  • IPv4:源IP(4B)、目标IP(4B)、源端口(2B)、目标端口(2B)
  • IPv6:源IP(16B)、目标IP(16B)、源端口(2B)、目标端口(2B)

4. TLV 可选扩展段(Type-Length-Value)

地址信息之后可追加多条TLV数据,用于传递额外元信息,常用标准类型:

  • PP2_TYPE_SSL:SSL连接相关信息(加密套件、TLS版本)
  • PP2_TYPE_UNIQUE_ID:连接全局唯一标识
  • PP2_TYPE_ALPN:应用层协商协议(h2/http/1.1)

四、Nginx 接收 Proxy Protocol v2 配置详解

关键指令说明

nginx 复制代码
listen 81 proxy_protocol;

这条指令同时兼容 v1、v2,Nginx自动识别协议版本,无需额外区分配置。

⚠️ 致命特性:

端口开启 proxy_protocol 参数后,所有TCP连接首个数据包必须携带合法Proxy Protocol头部 。没有PP头部的连接会被Nginx直接强制断开。

👉 禁止和普通局域网访问共用同一个端口,必须端口隔离!

Nginx两个核心变量(Windows官方Nginx重点)

  1. $proxy_protocol_addr

    Nginx原生内置变量。成功解析v1/v2协议头后,变量等于原始访客公网IP

    Windows官方原版nginx 1.24.0默认支持,不需要额外模块

  2. $remote_addr

    TCP直连对端地址。FRP内网穿透场景下,永远是 127.0.0.1,不能用来获取真实访客IP。

重要避坑:realip模块限制

nginx 复制代码
set_real_ip_from 127.0.0.1;
real_ip_header proxy_protocol;

以上指令依赖 ngx_http_realip_module

Windows官方编译版Nginx不包含此模块,写入配置直接启动报错 unknown directive

Windows环境解决方案:放弃realip模块,直接使用 $proxy_protocol_addr 传递IP给后端程序

Windows Nginx 完整可用配置示例

nginx 复制代码
# 独立server,专门接收frpc携带Proxy Protocol v2流量
server {
    listen       81 proxy_protocol;
    server_name  detayun.cn;

    # 开启日志,用于排查PP头部是否正常解析
    log_format pp_log '$proxy_protocol_addr | $remote_addr | $time_local "$request" $status';
    access_log logs/access_81.log pp_log;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $proxy_protocol_addr;
        proxy_set_header X-Forwarded-For $proxy_protocol_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass   http://detayun_server;
    }

    location /static {
        alias E:/Python/lixin_project/lixin/static;
        expires 1d;
        add_header Cache-Control "public, no-transform";
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

❌ 错误示范:不要使用 $proxy_add_x_forwarded_for

该变量只能读取HTTP代理链路IP,无法识别Proxy Protocol二进制头部。

原有普通访问 listen 80; 保持不变,不添加 proxy_protocol,实现流量隔离。

五、FRP 内网穿透启用 Proxy Protocol v2 实战

业务链路:

外网访客 → frps公网服务器 → frpc客户端(TCP隧道) → Nginx:81 → Django后端

frpc代理配置(toml格式)

toml 复制代码
[[proxies]]
name = "detayun3"
type = "tcp"
serverAddr = "43.227.71.58"
serverPort = 7000
localIP = "127.0.0.1"
localPort = 81    # 和Nginx开启proxy_protocol端口严格一致
remotePort = 39001
proxyProtocolVersion = "v2"  # 启用v2二进制协议

三条强制规范

  1. localPort 必须与Nginx监听端口统一(示例81);
  2. 修改配置后完全重启frpc进程,单纯重载不生效;
  3. 多层代理场景,只需要在frpc与Nginx之间开启一次PP协议,不要重复嵌套。

补充:frp type=http / type=https 隧道依靠HTTP X-Forwarded-For不需要Proxy Protocol,不要混淆两种方案。

六、Django后端读取真实IP代码示例

Nginx已经将解析到的公网IP写入HTTP请求头,Django直接读取:

python 复制代码
def get_real_ip(request):
    # 优先读取Proxy Protocol传递过来的IP
    x_real_ip = request.META.get("HTTP_X_REAL_IP")
    if x_real_ip:
        return x_real_ip.strip()
    xff = request.META.get("HTTP_X_FORWARDED_FOR")
    if xff:
        return xff.split(",")[0].strip()
    return request.META.get("REMOTE_ADDR")

七、高频踩坑清单(FRP+Windows Nginx场景)

坑1:端口共用,普通流量与PP流量混合

直接在 listen 80 proxy_protocol;,局域网访问本机80不带PP头部,连接全部被Nginx拒绝。

✅ 解决方案:端口隔离,frpc对接独立端口81。

坑2:协议版本不匹配

frpc发送v2,后端服务仅支持v1 → 连接直接失败、网页打不开。

坑3:frpc配置忘记添加 proxyProtocolVersion = "v2"

frpc不会发送任何Proxy头部;Nginx收不到合法数据,拒绝连接。

坑4:Nginx变量写错,持续拿到127.0.0.1

nginx 复制代码
# 错误
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 正确
proxy_set_header X-Forwarded-For $proxy_protocol_addr;

坑5:Windows Nginx强行写入realip系列指令

set_real_ip_from 指令缺失模块,Nginx启动直接emerg报错。

坑6:修改frpc配置之后没有重启客户端

frpc加载旧配置,不会发送v2协议头部。

八、标准化故障排查流程

  1. 连通性初步判断

    公网地址能够正常打开网站 → frpc成功发送Proxy Protocol头部;

    浏览器转圈无法访问 → PP头部缺失、端口不匹配、协议版本不一致。

  2. 利用Nginx访问日志定位根源

    查看 logs/access_81.log

  • $proxy_protocol_addr 显示公网IP:Nginx解析正常,问题出在后端代码读取逻辑;
  • $proxy_protocol_addr 为空字符串:frpc未正常发送v2协议头部。
  1. 抓包验证
    可通过Wireshark抓取frpc与Nginx之间流量,查找v2魔数字节,确认头部是否正常传输。

九、安全风险提醒

  1. Proxy Protocol 没有内置签名校验,头部可以被恶意伪造
  2. 禁止对公网直接开放开启 proxy_protocol 的端口;仅在内网可信链路使用(frpc本地127.0.0.1连接Nginx属于安全场景);
  3. 多级代理架构严格控制信任链路,防止攻击者伪造IP绕过风控、访问限制。

十、方案选型总结

  1. 纯TCP/UDP内网穿透、四层负载均衡,优先 Proxy Protocol v2
  2. Windows官方Nginx环境,放弃realip模块,使用 $proxy_protocol_addr 方案;
  3. Web HTTP业务,如果条件允许,优先选用frp type=http 隧道,免去Proxy Protocol复杂配置;
  4. 架构最佳实践:端口隔离,不要将开启proxy_protocol的端口对外直接暴露,仅用于内网代理之间通信。
相关推荐
踏月的造梦星球1 小时前
DMDPC 学习:架构、部署、运维与调优
运维·数据库·学习·架构
潘正翔1 小时前
docker核心概念
linux·运维·服务器·docker·容器·centos·运维开发
renhongxia12 小时前
世界模型,是“空中楼阁”还是AGI的“最后一块拼图”?
运维·服务器·数据库·人工智能·算法·agi
Dovis(誓平步青云)4 小时前
远程办公软件文件传输实测:6 款工具的速度、稳定性和办公体验对比
linux·运维·服务器·后端·生成对抗网络
csdn_aspnet5 小时前
GitHub Actions自动化运维实战,用CI/CD流水线实现测试、部署、安全扫描一体化
运维·安全·ci/cd·自动化·github
Inhand陈工6 小时前
数据中心UPS无功补偿与智能化监控方案:基于IG502的Modbus RTU转IEC61850实战
运维·人工智能·物联网·信息与通信
qetfw6 小时前
CentOS 7 搭建 LDAP 目录服务
linux·运维·centos
IT方大同7 小时前
linux简介
linux·运维·服务器
Dear~yxy8 小时前
时间同步服务器搭建
运维·服务器