SSH隧道问题:如何在远程ServerB获取客户端真实IP?
解决SSH本地端口转发无法获取客户端真实IP的问题
问题根源
你当前使用的-L本地端口转发模式中,ServerA接收的客户端流量会通过SSH连接转发到ServerB。此时ServerB上的服务接收到的连接源是ServerB自身的SSH客户端进程(通常是127.0.0.1或ServerB内网IP),而非客户端真实IP——因为SSH隧道默认不会传递源IP信息。
可行解决方案
1. 借助socat传递源IP(无需修改后端服务)
这是最简易的方案,通过socat作为中间层捕获并传递客户端真实IP:
- 在ServerB上:停止原服务对30238端口的监听,启动
socat监听该端口,捕获客户端IP后转发到实际服务端口(假设服务运行在30239):
这里socat TCP-LISTEN:30238,fork,reuseaddr EXEC:"/bin/sh -c 'echo 客户端真实IP: \$SOCAT_PEERADDR >> /var/log/client_ip.log; nc 127.0.0.1 30239'"$SOCAT_PEERADDR就是客户端的真实IP,可写入日志或通过脚本传递给后端服务(比如HTTP服务可添加X-Forwarded-For请求头)。 - 在ServerA上:替换原SSH命令为
socat转发+SSH隧道,确保源IP被传递:socat TCP-LISTEN:30238,fork,reuseaddr EXEC:"ssh user@ServerB socat STDIO TCP-CONNECT:127.0.0.1:30238"
2. 启用代理协议(需后端服务支持)
如果你的后端服务支持Proxy Protocol(如Nginx、HAProxy、部分Java服务),可通过SSH配合代理协议传递源IP:
- 在ServerA上:使用
socat监听端口并通过SSH转发到ServerB,同时添加代理协议头:socat TCP-LISTEN:30238,fork,reuseaddr EXEC:"ssh user@ServerB socat STDIO TCP-CONNECT:127.0.0.1:30238,proxyprotocol" - 在ServerB上:开启后端服务的代理协议支持(比如Nginx需添加
proxy_protocol on;到监听配置),即可直接获取客户端真实IP。
3. 使用HAProxy转发(适合生产环境)
对于生产环境,推荐用HAProxy做中间层处理代理协议:
- ServerA的HAProxy配置:
frontend tunnel_front bind *:30238 mode tcp option tcplog default_backend serverb_backend backend serverb_backend mode tcp server serverb <ServerB_IP>:30238 send-proxy - ServerB的HAProxy配置:
配置完成后,ServerB的HAProxy会解析代理协议头,将客户端真实IP传递给后端服务。frontend service_front bind *:30238 accept-proxy mode tcp option tcplog default_backend actual_service backend actual_service mode tcp server service 127.0.0.1:<实际服务端口>
内容的提问来源于stack exchange,提问作者Ali Nazari
相关产品推荐
相关产品推荐

