概括
我使用 Nginx 作为反向代理,特别是它的功能,proxy_bind
以便将真实的客户端 IP 发送到后端。我遵循本文档来自 nginx.com。
当 HTTP 服务器托管在另一台机器上或直接托管在反向代理上时,它都能很好地运行,除非在第二种情况下 HTTP 服务器在本地主机上监听。
=> 我无法使这个配置起作用:
# /etc/nginx/conf.d/nginx-revprox-test.conf
server {
listen 80;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_bind $remote_addr transparent;
}
}
细节
假设:
- IP 地址:
- 反向代理/本地后端:
192.168.1.90 (eth0)
&172.17.0.1 (eth1)
- 外部后端:
172.17.0.2
- 客户:
192.168.1.91
- 端口:
- 前端:(
80
无 TLS)- 后端:
8080
案例一:HTTP 服务器托管在外部后端(http://172.17.0.2:8080)。
# /etc/nginx/conf.d/nginx-revprox-test.conf server { listen 192.168.1.90:80; location / { proxy_pass http://172.17.0.2:8080; proxy_bind $remote_addr transparent; } }
这手动的说我们必须配置 iptables:
iptables -t mangle -A PREROUTING -p tcp -s 172.17.0.2 --sport 8080 -j MARK --set-xmark 0x1/0xffffffff ip rule add fwmark 1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100
=> 它运行良好。
案例二:HTTP 服务器与反向代理托管在同一台计算机上,并侦听
eth1
(http://172.17.0.1:8080)。# /etc/nginx/conf.d/nginx-revprox-test.conf server { listen 192.168.1.90:80; location / { proxy_pass http://172.17.0.1:8080; proxy_bind $remote_addr transparent; } }
根据这个答案和此图, 仅有的输出和路由后适用于本地生成的数据包。我们需要更改 iptables 规则:
iptables -t mangle -A OUTPUT -p tcp -s 172.17.0.2 --sport 8080 -j MARK --set-xmark 0x1/0xffffffff
=> 它也有效。
案例三:HTTP 服务器托管在本地,但监听
lo
(http://127.0.0.1:8080)。# /etc/nginx/conf.d/nginx-revprox-test.conf server { listen 192.168.1.90:80; location / { proxy_pass http://127.0.0.1:8080; proxy_bind $remote_addr transparent; } }
=>[!]我无法让它工作,即使有一个输出iptables 中的规则。
curl http://192.168.1.90:80
在客户端上不起作用(它只能在服务器上起作用,但这不是重点)。
我遗漏了一些有关 iptables 的信息。你能帮助我吗?
答案1
对于情况 3,您可以避免 Netfilter 标记 - 必要的过滤也直接由 提供支持ip rule
。以下命令会将所有流量从后端服务器路由到 nginx 前端:
# add a new routing table that routes all packets back to this server
ip route add local 0.0.0.0/0 dev lo table 100
# add a rule for choosing that routing table:
ip rule add from 127.0.0.1/32 ipproto 6 sport 8080 iif lo lookup 100
# ^ individual parts:
# from 127.0.0.1/32 - select just one loopback IP, the one with nginx on it
# ipproto 6 - select just TCP
# sport 8080 - select just traffic from the backend HTTP server port
# iif lo - select just traffic originating from this machine
# lookup 100 - route these matching packets via routing table 100
我在以下方法的帮助下反复试验,找到了ip rule
手册页和数据包流图(1,2)。
您也可以使用 Netfilter 标记,但我建议使用上述解决方案,因为它可以避免启用route_localnet
(这可能会导致安全问题)。为了完整起见,下面是使其工作的方法:
- 在本地接口上启用路由(按照https://unix.stackexchange.com/a/158256/72419):
sysctl -w net.ipv4.conf.all.route_localnet=0
- 配置路由表:
ip rule add fwmark 1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100
- 让 Netfilter 在 OUTPUT 链中标记数据包:
OUTPUT 链至关重要 - 本地生成的数据包不会经过 PREROUTING 表。iptables -t mangle -A OUTPUT -p tcp -s 127.0.0.1 --sport 8080 -j MARK --set-xmark 0x1/0xffffffff
不过,您也许能够避免与之相关的安全问题route_localnet
-https://github.com/yrutschle/sslh/blob/master/doc/tproxy.md#transparent-proxy-to-one-host修复了这个问题
iptables -t raw -A PREROUTING ! -i lo -d 127.0.0.0/8 -j DROP
iptables -t mangle -A POSTROUTING ! -o lo -s 127.0.0.0/8 -j DROP