反向VPN(WireGuard)环境下邮件服务器的iptables规则正确性验证及配置问题咨询
反向VPN(WireGuard)环境下邮件服务器的iptables规则正确性验证及配置问题咨询
问题描述
我搭建了一台VPS作为反向VPN,用来连接内网自建的邮件服务器(mailcow Docker容器),目前遇到了两个核心问题,希望能得到大佬的指导:
- 我自己拼凑了一套iptables规则脚本,想确认这套规则是否合理、正确,符合当前的架构需求;
- 邮件服务器的WireGuard配置中,按照教程设置
AllowedIPs = 0.0.0.0/0时完全无法传输流量,但改用明确指定的IP地址就能正常工作,我对iptables完全是新手,不知道哪里出了问题。
环境架构说明
- VPS:Oracle Linux 8系统,运行Docker和内核级WireGuard;上面部署了反向代理容器,负责VPS本地应用及内网邮件服务器的公网反向代理。
- 内网邮件服务器:Rocky Linux 8系统,同样运行Docker和内核级WireGuard,位于NAT后方,除了mailcow容器外还托管了其他私有Web应用,本地也有反向代理容器。
当前配置文件
VPS端iptables规则脚本(/etc/wireguard/scripts/vps-load-wg-iptables.sh)
#!/bin/bash set -x # set up install and uninstall directives A=-A I=-I if [[ "$1" == "down" ]]; then A=-D I=-D fi ip4_localip=10.0.0.11 ip4_wg_subnet=10.20.100 ip4_source=$ip4_wg_subnet.10 ip4_dest=$ip4_wg_subnet.11 # SET PUBLIC IP INTERFACE NAME ni=enp0s3 # SET WIREGUARD INTERFACE NAME wg=wg0 # SET FORWARDED PORTS TCP_PORTS="25 110 143 465 587 993 995 4190" # Accept it all. # Per docker manual: iptables -I DOCKER-USER -i src_if -o dst_if -j ACCEPT # to preserve linux routing capabilities. # Docker requires forwards to be on its own chain, use DOCKER-USER instead of FORWARD sudo iptables $I DOCKER-USER -i $wg -o $ni -j ACCEPT sudo iptables $I DOCKER-USER -s $ip4_wg_subnet.0/24 -j ACCEPT sudo iptables $I DOCKER-USER -m state --state RELATED,ESTABLISHED -j ACCEPT for p in $TCP_PORTS do # Allow traffic on specified ports. sudo iptables $A DOCKER-USER -i $ni -o $wg -p tcp --syn --dport $p -m conntrack --ctstate NEW -j ACCEPT # Forward traffic from public network to wireguard on specified ports sudo iptables -t nat $A PREROUTING -i $ni -p tcp --dport $p -j DNAT --to-destination $ip4_dest # Forward traffic from wireguard back to public network on specified ports sudo iptables -t nat $A POSTROUTING -o $wg -p tcp --dport $p -d $ip4_dest -j SNAT --to-source $ip4_source done # Source nat. sudo iptables -t nat $A POSTROUTING -s $ip4_wg_subnet.0/24 ! -d $ip4_wg_subnet.0/24 -j SNAT --to $ip4_localip # Masquerade. sudo iptables -t nat $A POSTROUTING -o $wg -j MASQUERADE
VPS端wg0.conf
[Interface] Address = 10.20.100.10/24 MTU = 1280 PrivateKey = KEY ListenPort = 51820 PreUp = sysctl -w net.ipv4.ip_forward=1 PostUp = /etc/wireguard/scripts/vps-load-wg-iptables.sh PostDown = /etc/wireguard/scripts/vps-load-wg-iptables.sh down PostDown = sysctl -w net.ipv4.ip_forward=0 [Peer] PublicKey = KEY PresharedKey = KEY AllowedIPs = 10.20.100.11/32, 10.20.1.11/32 PersistentKeepalive = 20
邮件服务器端wg0.conf
[Interface] Address = 10.20.100.11/32 MTU = 1280 PrivateKey = KEY PreUp = sysctl -w net.ipv4.ip_forward=1 PostDown = sysctl -w net.ipv4.ip_forward=0 [Peer] PublicKey = KEY PresharedKey = KEY AllowedIPs = 10.20.100.10/32, 10.0.0.11/32 Endpoint = VPS_PUBLIC_IP:51820 PersistentKeepalive = 20
专家解答
一、WireGuard AllowedIPs 无法使用 0.0.0.0/0 的原因及修复
你遇到的这个问题是典型的路由冲突+Peer配置不匹配导致的:
- 路由优先级冲突:当邮件服务器设置
AllowedIPs = 0.0.0.0/0时,WireGuard会添加一条默认路由(优先级高于内网默认网关),接管所有出站流量。但内网邮件服务器原本的默认网关指向NAT路由器,这时候两条默认路由会让系统无法判断流量走向,导致丢包。 - VPS端Peer配置限制:VPS的Peer配置中
AllowedIPs仅包含10.20.100.11/32, 10.20.1.11/32,这意味着VPS只会转发发往这两个IP的流量,而不会处理邮件服务器发往公网的反向流量(当邮件服务器用0.0.0.0/0时,所有流量都会发往VPS,但VPS会因为AllowedIPs不匹配而丢弃这些流量)。
针对性修复方案
根据你的需求选择一种:
需求1:仅让邮件入站流量通过VPS转发
不需要把所有流量走WireGuard,邮件服务器的AllowedIPs只需设置为VPS的WireGuard IP和公网IP:AllowedIPs = 10.20.100.10/32, VPS_PUBLIC_IP/32这样邮件服务器只会和VPS通信,其他流量走内网默认网关,避免路由冲突。
需求2:邮件服务器的所有流量(入站+出站)都通过VPS转发
- 邮件服务器端:设置
AllowedIPs = 0.0.0.0/0,并添加Table = auto让WireGuard自动管理路由表:[Interface] Address = 10.20.100.11/24 MTU = 1280 PrivateKey = KEY Table = auto PreUp = sysctl -w net.ipv4.ip_forward=1 PostDown = sysctl -w net.ipv4.ip_forward=0 - VPS端:修改Peer的
AllowedIPs为0.0.0.0/0,允许接收邮件服务器的所有流量:[Peer] PublicKey = KEY PresharedKey = KEY AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 20
- 邮件服务器端:设置
二、iptables规则的优化与正确性验证
你的脚本整体方向是对的,但有几个冗余和可优化的点:
- 规则顺序问题:iptables按匹配顺序执行,建议先处理已建立的连接,再处理新连接,避免规则被跳过:
# 先放行已建立/相关的连接 sudo iptables $I DOCKER-USER -m state --state RELATED,ESTABLISHED -j ACCEPT # 再放行WireGuard到公网的流量 sudo iptables $I DOCKER-USER -i $wg -o $ni -j ACCEPT - SNAT与MASQUERADE冲突:如果你VPS用的是固定公网IP,MASQUERADE(动态SNAT)完全多余,保留固定IP的SNAT即可,去掉这条规则:
# 移除这条规则:sudo iptables -t nat $A POSTROUTING -o $wg -j MASQUERADE - TCP规则冗余:
--syn和--ctstate NEW重复,后者已经涵盖新的TCP连接,简化规则:sudo iptables $A DOCKER-USER -i $ni -o $wg -p tcp --dport $p -m conntrack --ctstate NEW -j ACCEPT - WireGuard UDP端口放行:你完全漏掉了WireGuard本身的UDP端口(51820),需要在VPS的防火墙(比如firewalld)里放行,否则邮件服务器连不上VPS的WireGuard:
sudo firewall-cmd --add-port=51820/udp --permanent sudo firewall-cmd --reload - 冗余的SNAT规则:邮件服务器回复流量会自动通过WireGuard回到VPS,你添加的
POSTROUTING针对邮件端口的SNAT规则完全多余,可以移除:# 移除这条规则:sudo iptables -t nat $A POSTROUTING -o $wg -p tcp --dport $p -d $ip4_dest -j SNAT --to-source $ip4_source
三、额外测试建议
- 用
iptables -L -v -n查看当前规则的匹配计数,确认流量是否命中规则; - 在VPS和邮件服务器的WireGuard接口用
tcpdump抓包:
通过抓包可以直观看到流量是否正常传输。# VPS端抓包 sudo tcpdump -i wg0 port 25 or 465 or 587 # 邮件服务器端抓包 sudo tcpdump -i wg0 port 25 or 465 or 587
备注:内容来源于stack exchange,提问作者likeyeah
相关产品推荐
相关产品推荐

