Ubuntu桌面或服务器环境下,普通代理通常通过环境变量http_proxy、https_proxy或系统设置生效,但很多命令行工具和内部服务并不读取这些配置。透明代理不需要修改应用的代理设置,而是利用netfilter框架将发往外部网络的连接重定向到本地代理端口,由代理程序解析原始目标并转发。这种方案常用于网关设备、容器网络和需要全局流量管理的服务器。透明代理的核心价值在于对应用完全透明,无需逐个配置代理参数,同时可以接管DNS请求,避免域名解析泄漏。

透明代理的工作机制与前置条件
透明代理依赖Linux内核的netfilter子系统。当数据包经过内核的网络栈时,netfilter会在PREROUTING、OUTPUT等挂载点触发规则。普通代理要求应用主动连接代理端口,而透明代理则通过iptables或nftables规则在内核层拦截数据包,并将目标地址改写为本地代理端口。对于REDIRECT模式,内核使用DNAT将目标IP和端口改写为本机端口,代理程序再通过SO_ORIGINAL_DST套接字选项获取原始目标地址,从而知道数据包本来要发往哪里。
另一种更强大的方式是TPROXY。TPROXY不修改数据包的原始目标地址,而是通过策略路由和套接字选项让代理程序接收到非本地地址的数据包。这样代理程序可以直接使用原始目标地址发起连接,同时保留完整的源地址信息。TPROXY支持TCP和UDP,并且对IPv6也有较好的兼容性,适合需要同时接管UDP流量的场景,例如在线游戏、VoIP通话和QUIC协议。
在开始配置之前,需要确认系统满足以下条件:拥有root权限、内核支持xt_TPROXY或REDIRECT模块、已安装支持透明代理的代理程序。可以使用下面的命令检查内核模块是否加载:
# 检查TPROXY相关模块 lsmod | grep -E 'x_tables|xt_TPROXY|nf_tproxy_ipv4' # 查看IPv4转发状态 sysctl net.ipv4.ip_forward
如果输出中包含xt_TPROXY和nf_tproxy_ipv4,说明内核已经具备TPROXY能力。如果内核不支持,可以通过modprobe加载模块,或者升级内核。Ubuntu 20.04及之后的官方内核通常默认启用这些模块。需要注意的是,透明代理规则会改变系统网络行为,配置顺序错误可能导致连本机都无法访问,建议通过SSH远程操作,避免在只有物理访问权限的机器上直接测试。
使用iptables REDIRECT配置TCP透明代理
REDIRECT模式适合只需要接管TCP流量的场景,配置相对简单。它的原理是在OUTPUT链或PREROUTING链上将符合条件的TCP数据包重定向到本机某个端口,代理程序监听该端口并通过SO_ORIGINAL_DST恢复原始目标。这里以Xray的dokodemo-door入站为例,监听12345端口接收重定向流量。
首先创建iptables规则。如果只是让本机产生的TCP流量走透明代理,可以操作nat表的OUTPUT链;如果作为网关转发局域网设备的流量,则需要操作PREROUTING链并开启IP转发。下面给出一个只处理本机TCP流量的规则示例:
# 创建专用链,避免污染默认链 iptables -t nat -N V2RAY # 排除本机回环地址 iptables -t nat -A V2RAY -d 127.0.0.0/8 -j RETURN # 排除常见内网网段,避免局域网访问被代理 iptables -t nat -A V2RAY -d 192.168.0.0/16 -j RETURN iptables -t nat -A V2RAY -d 10.0.0.0/8 -j RETURN iptables -t nat -A V2RAY -d 172.16.0.0/12 -j RETURN # 将剩余TCP流量重定向到本地12345端口 iptables -t nat -A V2RAY -p tcp -j REDIRECT --to-ports 12345 # 将OUTPUT链的TCP流量导入专用链 iptables -t nat -A OUTPUT -p tcp -j V2RAY
上述规则中,RETURN动作用于跳过内网地址。如果不排除内网网段,局域网访问会被错误地重定向到代理程序,导致无法连接路由器、打印机或内网服务。REDIRECT只在nat表中生效,它会把目标地址改写成127.0.0.1:12345,因此代理程序必须启用透明代理模式才能获取原始目标地址。Xray的dokodemo-door入站需要设置followRedirect为true,参考配置如下:
{
"inbounds": [
{
"tag": "transparent-redirect",
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp",
"followRedirect": true
},
"streamSettings": {
"sockopt": {
"tproxy": "redirect"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
]
}
sockopt中的tproxy设置为redirect表示当前入站接收的是REDIRECT流量。如果代理程序不支持REDIRECT,也可以使用redsocks工具将透明代理流量转换成SOCKS5请求。REDIRECT的缺点是只能处理TCP,UDP流量无法通过REDIRECT接管。另外,当代理程序本身需要向外发起连接时,必须避免这些连接再次进入透明代理链,否则会形成回环。通常代理程序使用root用户运行,可以通过uid-owner匹配放行,或者将代理出口流量打上特殊标记并在规则中排除。
DNS请求也需要一并处理。普通DNS使用UDP 53端口,在只配置TCP透明代理的情况下,域名解析仍可能使用本地DNS服务器,导致部分IPv6地址或者被污染域名无法正确解析。可以将UDP 53流量也通过TPROXY或单独的DNS转发工具导入代理程序,或者使用Xray内置DNS功能,将远程解析交给代理出口节点完成,只在本地监听一个DNS端口供系统查询。
使用TPROXY实现TCP与UDP全流量透明代理
TPROXY适合需要同时接管TCP和UDP的场景。与REDIRECT不同,TPROXY不会修改数据包的原始目标地址,而是利用策略路由将带有特定fwmark标记的包交给本地套接字处理。代理程序监听一个TPROXY透明端口,内核将非本地目的地址的数据包直接投递到该端口,代理程序可以通过原始目标地址正常发起连接。这种方式可以完整保留源IP和目的IP,适用于UDP游戏、语音通讯以及需要精确路由控制的场合。
实现TPROXY需要先设置策略路由。以下命令创建一条新的路由表100,并将fwmark为1的数据包优先交给本地路由:
# 添加策略路由规则 ip rule add fwmark 1 lookup 100 # 在table 100中添加本地回环路由 ip route add local 0.0.0.0/0 dev lo table 100
然后需要在mangle表中设置TPROXY规则。对于已经建立的连接,需要先通过DIVERT链处理,避免重复投递。对于新连接,则使用TPROXY目标将数据包送到12345端口,并打上fwmark标记:
# 处理已建立的本地透明代理连接 iptables -t mangle -N DIVERT iptables -t mangle -A DIVERT -j MARK --set-mark 1 iptables -t mangle -A DIVERT -j ACCEPT iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT # 排除回环和内网地址 iptables -t mangle -A PREROUTING -d 127.0.0.0/8 -j RETURN iptables -t mangle -A PREROUTING -d 192.168.0.0/16 -j RETURN iptables -t mangle -A PREROUTING -d 10.0.0.0/8 -j RETURN iptables -t mangle -A PREROUTING -d 172.16.0.0/12 -j RETURN # 对TCP和UDP新连接执行TPROXY iptables -t mangle -A PREROUTING -p tcp -j TPROXY --on-port 12345 --tproxy-mark 0x1/0x1 iptables -t mangle -A PREROUTING -p udp -j TPROXY --on-port 12345 --tproxy-mark 0x1/0x1
这里使用PREROUTING链,因为TPROXY主要面向本机作为网关或本机产生的流量。对于本机出站流量,还需要在mangle表的OUTPUT链中添加类似规则,并注意排除代理程序自身产生的流量。很多教程建议使用gid-owner匹配代理进程所属的用户组,并在OUTPUT链中直接RETURN,使代理程序发出的连接不会被再次TPROXY。Xray的TPROXY入站配置同样使用dokodemo-door,但sockopt中的tproxy要设置为tproxy:
{
"inbounds": [
{
"tag": "transparent-tproxy",
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {}
}
]
}
TPROXY模式下的UDP处理需要特别注意。UDP没有连接状态,透明代理程序需要维护本地和远程地址之间的映射关系,才能正确回传数据包。Xray和Shadowsocks-libev的透明代理实现都支持UDP,但需要内核开启相应的socket选项。如果遇到UDP数据包无法回传或连接中断,可以检查内核参数net.ipv4.conf.all.forwarding和net.ipv4.conf.all.rp_filter,建议将rp_filter设置为0或2,避免反向路径过滤丢弃合法的TPROXY流量。
验证透明代理与常见故障排查
配置完成后,需要验证透明代理是否真正生效。最简单的方法是使用curl查看出口IP,确认返回的IP是否来自代理节点。如果要验证UDP是否被接管,可以使用dig指定UDP协议查询域名,或者使用支持UDP的网络工具发送测试包。透明代理只对经过iptables规则的数据包生效,因此本机直连127.0.0.1或内网地址不会受影响。
# 查看出口IP curl -4 ifconfig.me # 测试UDP DNS解析 dig +short @8.8.8.8 ipipp.com # 查看代理端口监听状态 ss -tunap | grep 12345 # 查看Xray日志 journalctl -u xray -f
如果发现透明代理没有生效,可以先检查iptables规则是否正确加载。使用iptables -t nat -L -n -v和iptables -t mangle -L -n -v可以查看每条规则的匹配计数,判断数据包是否被规则命中。对于TPROXY,还需要确认策略路由是否正确:
# 查看策略路由规则 ip rule list # 查看table 100路由 ip route show table 100 # 查看mangle表规则计数 iptables -t mangle -L PREROUTING -n -v
常见问题之一是代理程序自身流量被透明代理规则捕获,导致代理程序无法连接出口节点。解决办法是在mangle表的OUTPUT链中使用uid-owner匹配代理进程的用户ID,并直接RETURN。例如Xray以root运行时,可以先创建一个专用用户或用户组,让代理进程以该用户身份运行,然后在规则中放行该用户的所有出站连接。另一个常见问题是DNS污染或解析失败。透明代理接管了TCP流量,但系统仍使用本地DNS服务器,可能返回错误结果。此时可以让Xray内置DNS监听本地端口,并将系统的/etc/resolv.conf指向127.0.0.1。
规则持久化方面,iptables规则在重启后会丢失。Ubuntu可以通过安装iptables-persistent或netfilter-persistent来保存规则,策略路由则需要写入网络启动脚本或systemd单元。建议在测试环境反复验证规则顺序和排除条件,确认透明代理稳定后再应用到生产环境。透明代理的排错通常需要结合数据包计数、路由表和代理日志逐步定位,耐心检查每一层规则可以避免大部分网络中断问题。
Ubuntu透明代理iptables透明代理TPROXY透明代理修改时间:2026-09-22 01:30:04