WireGuard连接后端口无法访问:如何实现入站流量正常接收且出站流量走WireGuard
这问题我之前折腾过好一阵,核心就是不对称路由在搞鬼!你配置了AllowedIPs = 0.0.0.0/0后,所有出站流量(包括入站连接的回复包)都会被强制走WireGuard的wg0接口,但入站流量是从你的公网物理接口进来的——一来一回路径不一样,中间的防火墙或者对方服务器会把这种“来路不明”的回复包直接丢弃,自然SSH这类服务就连不上了。
下面给你几个实用的解决方案,按易用性和灵活性排序:
方案一:策略路由(最推荐,灵活通用)
核心思路是给“从公网接口进来的流量”单独指定路由表,让它们的回复包仍从公网接口出去,其他主动发起的出站流量走WireGuard。
步骤如下(假设你的公网接口是eth0,网关是1.2.3.1,可以用ip a和ip route show default确认):
- 先创建一个专门的路由表,比如编号100,命名为
isp:echo "100 isp" >> /etc/iproute2/rt_tables - 添加规则:所有从公网接口
eth0进来的流量,都使用isp路由表:ip rule add iif eth0 table isp - 给
isp表添加默认路由,指向公网网关:ip route add default via 1.2.3.1 dev eth0 table isp - 保持WireGuard的
AllowedIPs = 0.0.0.0/0配置不变(这会让主路由表的默认路由指向wg0)。
这样配置后,外部发过来的SSH请求从eth0进来,回复包会自动走isp表的路由从eth0出去;而你服务器主动访问外部的流量,会走主路由表的默认路由走wg0,完全分离,完美解决问题。
方案二:修改WireGuard的AllowedIPs(简单但局限)
如果不想搞策略路由,也可以直接修改WireGuard配置,把你服务器自己的公网IP从AllowedIPs中排除,这样回复到这个IP的流量就不会走wg0:
假设你的服务器公网IP是4.5.6.7,把配置里的AllowedIPs改成:
AllowedIPs = 0.0.0.0/0, !4.5.6.7/32
不过这个方法的局限很明显:如果有多个客户端要连你服务器,或者你需要接收来自不同源IP的入站流量,你得把所有相关IP都排除,扩展性很差,只适合单IP单场景的简单需求。
方案三:iptables标记+策略路由(精细控制)
如果你需要更精细的流量控制,比如只让特定端口的入站流量走公网回复,可以用iptables标记流量,再配合策略路由:
- 给从eth0进来的流量打标记(比如标记为1):
如果你只想针对SSH端口,可以改成:iptables -t mangle -A PREROUTING -i eth0 -j MARK --set-mark 1iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 22 -j MARK --set-mark 1 - 添加规则,让标记为1的流量使用
isp路由表:ip rule add fwmark 1 table isp - 同样给
isp表添加默认路由(和方案一的第三步一致)。
注意事项
- 要把这些配置持久化,不然重启服务器就失效了:可以把命令加到WireGuard配置的
PostUp和PreDown字段里,比如在wg0.conf里加:PostUp = echo "100 isp" >> /etc/iproute2/rt_tables; ip rule add iif eth0 table isp; ip route add default via 1.2.3.1 dev eth0 table isp PreDown = ip rule del iif eth0 table isp; ip route del default via 1.2.3.1 dev eth0 table isp - 确认你的防火墙(比如ufw、firewalld)没有阻止相关流量,入站端口(比如22)要保持开放。
备注:内容来源于stack exchange,提问作者Iuri G.

