问题背景
最近在配置FRP反向代理服务时,为了让后端服务能够获取到客户端的真实IP地址,我按照常规做法在FRP服务端配置了proxy_protocol_version = v2
,并在OpenResty配置中添加了 set_real_ip_from
和 real_ip_header
等指令。配置完成后,网站功能一切正常,客户端IP也能正确获取,但OpenResty的监控系统却开始频繁报错。
错误现象
错误代码:服务内部错误: Get "http://127.0.0.1/nginx_status": EOF
排查过程
理解PROXY协议
首先我查阅了PROXY协议的文档,了解到这是HAProxy开发的一种协议,用于在代理服务器和后端服务器之间传递客户端原始信息。樱花FRP支持v1、v2和simple三个版本的PROXY协议,我使用的是v2版本协议。
检查配置
检查我的站点OpenResty配置:
listen 80 proxy_protocol default_server;
listen [::]:80 default_server;
listen 443 ssl http2 proxy_protocol default_server;
listen [::]:443 ssl http2 default_server;
...
real_ip_header proxy_protocol; # 启用 PROXY 协议支持
real_ip_recursive on; # 递归处理 PROXY 协议中的 IP 地址
set_real_ip_from 127.0.0.1; # 这里的127.0.0.1表示可信的代理服务器 IP 地址
...
FRP服务端的配置:
[common]
proxy_protocol_version = v2
看起来配置是正确的,但为什么监控会报错?
分析监控组件
我使用的OpenResty是1Panel运维面板提供的,查看其文档发现它默认不支持PROXY协议。当监控请求到达时,监控模块尝试解析请求头,但遇到了PROXY协议头而不是常规的HTTP请求头,因此报错。
解决方案
为FRP流量单独配置监听端口
因为OpenResty监控流量来源于127.0.0.1:80这个地址和端口且1Panel的OpenResty只占用80和443端口,所以我只需要避免在这个80端口启用PROXY协议就行,因此我们可以有两种做法。
这两种做法的前提是配置穿透地址为本地IP127.0.0.1端口为443:
网站服务的443端口启用PROXY协议,80端口保持默认配置不变。
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl http2 proxy_protocol default_server; # 因为樱花FRP只提供IPV4穿透,所以这需要监听IPV4的443端口 proxy_protocol
listen [::]:443 ssl http2 default_server;
...
real_ip_header proxy_protocol; # 启用 PROXY 协议支持
real_ip_recursive on; # 递归处理 PROXY 协议中的 IP 地址
set_real_ip_from 127.0.0.1; # 这里的127.0.0.1表示可信的代理服务器 IP 地址
...
单独监听127.0.0.1:443这个地址,将其作为FRP的专属监听配置(更推荐这种做法)。
将下面这几行代码添加到网站的server块中:
listen 127.0.0.1:443 ssl http2 proxy_protocol; # 这里监听FRP代理的本地端口
real_ip_header proxy_protocol; # 启用 PROXY 协议支持
real_ip_recursive on; # 递归处理 PROXY 协议中的 IP 地址
set_real_ip_from 127.0.0.1; # 这里的127.0.0.1表示可信的代理服务器 IP 地址
示例:
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
listen 127.0.0.1:443 ssl http2 proxy_protocol; # 这里监听FRP代理的本地端口 proxy_protocol
proxy_set_header X-Real-IP $remote_addr;
...
real_ip_header proxy_protocol; # 启用 PROXY 协议支持
real_ip_recursive on; # 递归处理 PROXY 协议中的 IP 地址
set_real_ip_from 127.0.0.1; # 这里的127.0.0.1表示可信的代理服务器 IP 地址
...
proxy_http_version 1.1;
为监控单独配置监听端口
修改网站配置文件,在配置文件最末端添加下列server块(一定要在末端添加这个server块,不然1Panel内网站的基本设置会有部分失效)
server {
listen 127.0.0.1:80;
server_name localhost;
location /nginx_status {
stub_status on; # 启用状态模块
access_log off; # 关闭访问日志
allow 127.0.0.1; # 仅允许本机访问
deny all; # 禁止其他IP
}
}
配置文件总览:
server {
listen 80 proxy_protocol default_server;
listen [::]:80 default_server;
listen 443 ssl http2 proxy_protocol default_server;
listen [::]:443 ssl http2 default_server;
...
real_ip_header proxy_protocol; # 启用 PROXY 协议支持
real_ip_recursive on; # 递归处理 PROXY 协议中的 IP 地址
set_real_ip_from 127.0.0.1; # 这里的127.0.0.1表示可信的代理服务器 IP 地址
...
# 粘贴在配置文件最末端
server {
listen 127.0.0.1:80;
server_name localhost;
location /nginx_status {
stub_status on; # 启用状态模块
access_log off; # 关闭访问日志
allow 127.0.0.1; # 仅允许本机访问
deny all; # 禁止其他IP
}
}
验证结果
可以看到通过配置这个server块之后,OpenResty已经可以正常监控全部的网站服务了。
经验总结
协议兼容性:在引入新协议时要考虑所有相关组件的兼容性
监控隔离:监控端点最好与业务端点分离,避免相互影响
逐步排查:从错误日志出发,逐步分析各组件的行为,能更快定位问题
希望这篇折腾日记能帮助遇到类似问题的朋友。如果你有更好的解决方案,欢迎在评论区分享!