Frp对于获取用户真实 IP↗处理如下:
HTTP X-Forwarded-For
目前只有 http 类型的代理或者启用了 https2http
或 https2https
插件的代理支持这一功能。
可以通过 HTTP/HTTPS 请求 header 中的 X-Forwarded-For
来获取用户真实 IP,默认启用。
Proxy Protocol
frp 支持通过 Proxy Protocol
协议来传递经过 frp 代理的请求的真实 IP,此功能支持所有以 TCP 为底层协议的类型,不支持 UDP。Proxy Protocol
功能启用后,frpc 在和本地服务建立连接后,会先发送一段 Proxy Protocol
的协议内容给本地服务,本地服务通过解析这一内容可以获得访问用户的真实 IP。所以不仅仅是 HTTP 服务,任何的 TCP 服务,只要支持这一协议,都可以获得用户的真实 IP 地址。
需要注意的是,在代理配置中如果要启用此功能,需要本地的服务能够支持 Proxy Protocol
这一协议,目前 nginx 和 haproxy 都能够很好的支持。Proxy Protocol v1
并未为 UDP 设计,在 UDP 隧道中您总是应该使用 v2。
这里以 HTTPS
类型为例:
frpc.toml
[[proxies]]
name = "web"
type = "https"
localPort = 443
customDomains = ["test.yourdomain.com"]
目前支持 v1 和 v2 两个版本的 proxy protocol 协议。
transport.proxyProtocolVersion = "v2"
只需要在代理配置中增加一行 transport.proxyProtocolVersion = "v2"
即可开启此功能。
本地的 HTTPS 服务可以通过在 nginx 的配置中启用 Proxy Protocol
的解析并将结果设置在 X-Real-IP
这个 Header 中就可以在自己的 Web 服务中通过 X-Real-IP
获取到用户的真实 IP。
根据 SakuraFrp 帮助文档 Proxy Protocol↗ :
对于Nginx,需要使虚拟机监听 Proxy Protocol
协议,形如:
listen 443 ssl proxy_protocol;
然后配置反向代理部分如下:
location ... {
proxy_set_header X-Real-IP $proxy_protocol_addr;
#proxy_set_header X-Forwarded-For $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
# 原有内容
proxy_pass ...;
}
原配置中对X-Forwarded-For
也使用$proxy_protocol_addr
并不合理,会导致中间转发过程丢失,使用$proxy_add_x_forwarded_for
更合理,可以看到转发经过地址。
对于Apache2则相对简单,如果您的 Apache 版本 >= 2.4.30,如下即可:
<VirtualHost *:80>
ServerName ...
# 需启用 mod_remoteip
RemoteIPProxyProtocol On
</VirtualHost>
在实践中,HTTP协议传输被硬性绑定不同端口,不能实现在一个端口上多个服务的复用,如下所示配置不能正常使用:
[[proxies]]
name = "https"
type = "tcp"
localIP = "10.0.0.14"
localPort = 443
customDomains = ["test.yourdomain.com"]
customDomains = ["test2.yourdomain.com"]
也就是不能使用HTTP作为底层传输协议,内网服务必须一服务一端口,不能复用端口,如欲复用则必须使用TCP
协议。
另外使用 Proxy Protocol
协议则会使服务无法直接通过浏览器访问,访问必须经过FRP,导致服务在内网无法正常使用,详见SakuraFrp 帮助文档关于 Proxy Protocol↗
一节。
而且,在某个 listen
端口启用 Proxy Protocol
后,该端口(包括其他配置文件中的相同端口)的所有连接都会按 Proxy Protocol
协议处理。
也就是实际应用中共用 80/443
端口的所有虚拟机在这个协议上强绑定。
FRP的配置是真的神秘,文档也真是能写多简略就写多简略。