在构建高可用和高并发的Web架构时,CDN(内容分发网络)已经成为不可或缺的组件。它不仅能加速静态资源的分发,还能隐藏源站服务器的真实IP地址,从而有效抵御DDoS攻击。然而,这种架构也带来了一个显著的副作用:源站服务器接收到的TCP连接源IP地址全部变成了CDN节点的内部IP。对于需要进行精准地域访问控制、用户行为审计以及风控拦截的业务来说,丢失客户端真实IP是一个严重的痛点。为了解决这一问题,业界推出了Proxy-Protocol协议,它能够在不修改现有应用层协议(如HTTP、TLS)的前提下,将客户端的真实IP和端口信息透传给源站。

Proxy-Protocol协议的工作原理与版本差异
Proxy-Protocol是一种在网络代理和负载均衡领域广泛使用的协议,其核心目的是在代理服务器与后端服务器之间传递客户端的原始连接信息。传统的HTTP反向代理通常通过添加X-Forwarded-For或X-Real-IP等HTTP头部来实现这一目标,但这仅限于HTTP协议。当面对非HTTP协议(如数据库连接、SMTP邮件传输或纯TCP流)时,HTTP头部就无能为力了。Proxy-Protocol通过在TCP数据流的最前面插入一段额外的数据来解决这个问题,这段数据包含了客户端的源IP、源端口以及目标IP和目标端口。
该协议主要分为两个版本:版本1(v1)和版本2(v2)。版本1采用人类可读的文本格式,以PROXY字符串开头,后面紧跟TCP4或TCP6表示IPv4或IPv6,接着就是源IP、目标IP、源端口和目标端口,最后以CRLF结尾。这种格式易于调试,但会占用更多的网络带宽,且解析效率相对较低。版本2则采用了二进制格式,不仅大幅减少了头部数据的大小,提升了解析性能,还支持UDP协议和Unix域套接字。在实际的CDN配置中,通常建议优先使用版本2以获得更好的性能和兼容性。
Proxy-Protocol的工作机制非常精巧。当客户端与CDN节点建立TCP连接后,CDN节点不会立即将应用层数据(如HTTP请求)转发给源站。相反,它会先构造一个包含客户端真实网络信息的Proxy-Protocol头部,并将其作为TCP流的第一个数据包发送给源站。源站服务器在接收到连接后,首先读取并解析这个特殊的头部,剥离出真实IP和端口,然后再将后续的数据流交给上层的应用服务(如Nginx、HAProxy)进行处理。这种机制对应用层是完全透明的,不需要修改现有的业务代码。
Nginx源站接收并解析真实IP的配置实践
Nginx作为最流行的Web服务器之一,对Proxy-Protocol提供了良好的原生支持。要让Nginx正确解析CDN传递过来的真实IP,需要在配置文件中进行相应的设置。首先,在server块或http块的listen指令中添加proxy_protocol参数,告知Nginx该监听端口将接收带有Proxy-Protocol头部的连接。同时,需要使用set_real_ip_from指令将CDN节点的IP地址段设置为受信任的来源,这样Nginx才会尝试从Proxy-Protocol头部中提取真实IP并覆盖连接的源IP。
下面是一个典型的Nginx配置示例。在这个示例中,我们不仅开启了proxy_protocol,还使用了real_ip_header指令来指定从哪个字段获取真实IP。对于Proxy-Protocol,Nginx会自动解析头部,因此只需配置信任的代理IP段即可。需要注意的是,如果CDN节点和源站之间是通过HTTPS(TLS)连接的,还需要在listen指令中同时加上ssl和proxy_protocol参数,并正确配置证书。
http {
# 设置信任的CDN回源IP段,请根据实际CDN服务商提供的IP段进行替换
set_real_ip_from 192.168.1.0/24;
set_real_ip_from 10.0.0.0/8;
# 告诉Nginx从Proxy-Protocol头部获取真实IP
real_ip_header proxy_protocol;
server {
# 监听443端口,开启SSL和Proxy-Protocol支持
listen 443 ssl proxy_protocol;
server_name www.ipipp.com;
# SSL证书配置
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
location / {
proxy_pass http://backend_server;
# 将解析出的真实IP传递给后端应用
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
在配置过程中,有一个常见的误区需要特别注意:如果CDN端开启了Proxy-Protocol而源站Nginx没有配置相应的接收参数,或者源站配置了接收参数但CDN端没有发送,都会导致连接握手失败或HTTP请求解析报错。因为Nginx会把Proxy-Protocol的头部数据当作普通的HTTP请求数据来解析,从而返回400 Bad Request错误。因此,在上线前必须确保两端配置的一致性,并且建议在CDN控制台配置回源IP段白名单,防止恶意用户直接绕过CDN伪造Proxy-Protocol头部攻击源站。
HAProxy与四层负载均衡场景下的应用
在更复杂的网络架构中,源站前端往往会部署一层四层负载均衡器(L4 Load Balancer),如HAProxy或LVS。四层负载均衡基于IP和端口进行转发,无法像七层负载均衡那样修改HTTP头部。在这种场景下,Proxy-Protocol的优势更加明显,因为它工作在传输层之上、应用层之下,非常适合在四层代理链路中透传客户端信息。
以HAProxy为例,它既可以作为发送Proxy-Protocol头部的客户端,也可以作为接收和解析该头部的服务端。当HAProxy作为前端负载均衡器接收来自CDN的流量时,需要在backend配置中开启accept-proxy参数,使其能够解析CDN发送过来的Proxy-Protocol头部。随后,当HAProxy将流量转发给后端的Nginx应用服务器时,它又可以再次通过send-proxy参数将解析出的真实IP信息以Proxy-Protocol格式发送给后端,从而形成一条完整的真实IP透传链路。
frontend cdn_incoming
bind *:80
# 接收来自CDN的Proxy-Protocol头部
accept-proxy
default_backend nginx_servers
backend nginx_servers
balance roundrobin
server nginx1 192.168.2.10:80 check
server nginx2 192.168.2.11:80 check
# 向后端Nginx发送Proxy-Protocol头部
send-proxy
在多层代理架构中,Proxy-Protocol的链式传递需要特别注意性能损耗和兼容性问题。每一次代理节点的解析和重新封装都会消耗一定的CPU资源。虽然版本2的二进制格式已经极大地优化了解析效率,但在极高并发的场景下,仍然需要评估服务器的处理能力。此外,并非所有的四层负载均衡设备和云服务商都支持Proxy-Protocol,因此在设计架构时需要确认链路中所有节点都具备处理该协议的能力。如果中间某一层不支持,可能会导致连接中断,此时需要考虑退回到传统的HTTP层透传方案,或者在不支持的节点上终止Proxy-Protocol并转换为其他传递方式。
CDNProxy-Protocol源站配置修改时间:2026-08-28 21:52:48