基于策略的路由配置求助:Arch Linux路由器VPN分流需求
嘿,我刚好折腾过一模一样的Arch Linux路由器+OpenVPN客户端的场景,太懂你这种“想让部分动态多变的IP/域名绕开VPN,但硬写静态路由根本赶不上IP变化”的头疼了!给你几个我亲自验证过的实用方案,一步步来就能搞定:
方案1:用ipset + iptables 动态管理绕开VPN的IP集合
ipset是个能动态维护IP/子网集合的工具,完美解决静态路由的局限性:
- 先装依赖:
sudo pacman -S ipset iptables - 创建一个名为
bypass_vpn的IP集合(用hash:net类型支持单个IP和子网):sudo ipset create bypass_vpn hash:net - 配置iptables规则,给这个集合里的目标IP打标记,然后让标记过的流量走原来的非VPN路由表(假设你的VPN接口是
tun0,默认所有流量走tun0):# 给目标IP在bypass_vpn里的流量打标记100 sudo iptables -t mangle -A PREROUTING -m set --match-set bypass_vpn dst -j MARK --set-mark 100 # 让带标记100的流量优先走main路由表(也就是物理网卡的默认路由) sudo ip rule add fwmark 100 table main priority 100 - 动态添加/删除IP非常方便:
- 加单个IP:
sudo ipset add bypass_vpn 8.8.8.8 - 加子网:
sudo ipset add bypass_vpn 192.168.0.0/24 - 删除IP:
sudo ipset del bypass_vpn 8.8.8.8
- 加单个IP:
- 配置开机自动加载:
- 保存ipset规则:
sudo ipset save > /etc/ipset.conf - 新建一个systemd服务文件
/etc/systemd/system/ipset-restore.service:[Unit] Description=Restore ipset rules on boot Before=network.target [Service] Type=oneshot ExecStart=/usr/sbin/ipset restore -f /etc/ipset.conf ExecStop=/usr/sbin/ipset destroy RemainAfterExit=yes [Install] WantedBy=multi-user.target - 启用服务:
sudo systemctl enable --now ipset-restore.service - 保存iptables规则:
sudo iptables-save > /etc/iptables/iptables.rules,然后启用iptables服务:sudo systemctl enable --now iptables.service
- 保存ipset规则:
方案2:结合DNS自动把域名解析的IP加入集合(应对动态IP域名)
如果你的目标是经常换IP的域名(比如某些流媒体、云服务),用dnsmasq自动把解析到的IP加入ipset,完全不用手动管:
- 装dnsmasq:
sudo pacman -S dnsmasq - 编辑
/etc/dnsmasq.conf,添加你要绕开VPN的域名(支持通配符):# 把example.com及其所有子域名解析到的IP自动加入bypass_vpn集合 ipset=/example.com/*.example.com/bypass_vpn - 把系统DNS改成dnsmasq的本地地址:编辑
/etc/resolv.conf,把nameserver改成127.0.0.1(如果用systemd-resolved的话,需要调整配置让它用dnsmasq,不过直接改resolv.conf更简单) - 重启dnsmasq:
sudo systemctl restart dnsmasq
这样每次解析这些域名时,对应的IP会自动被加入bypass_vpn,IP变了也不用手动更新,太省心了!
方案3:用nftables替代iptables(更现代的选择)
如果你已经在使用nftables(Arch现在默认推荐这个),可以用它自带的集合功能,步骤更简洁:
- 创建一个动态IP集合:
sudo nft add set inet filter bypass_vpn { type ipv4_addr; flags dynamic; } - 添加规则给集合里的IP打标记:
# 给局域网进来的流量打标记 sudo nft add rule inet filter prerouting ip daddr @bypass_vpn meta mark set 100 # 给路由器自身的输出流量打标记 sudo nft add rule inet filter output ip daddr @bypass_vpn meta mark set 100 - 同样添加ip rule让标记流量走main表:
sudo ip rule add fwmark 100 table main priority 100 - 保存nftables配置并开机启用:
sudo nft list ruleset > /etc/nftables.conf sudo systemctl enable --now nftables.service - 动态添加IP:
sudo nft add element inet filter bypass_vpn { 8.8.8.8 }
几个关键注意事项
- 确保你的OpenVPN客户端配置里有
redirect-gateway def1(你说所有流量都走VPN,应该已经加了),这个配置会把默认路由指向tun0,而我们的标记规则优先级更高,所以能让指定流量绕开 - 测试的时候用
traceroute 目标IP看看,第一跳如果是你的网关而不是VPN服务器的IP,就说明配置成功了 - 如果需要支持IPv6,要对应创建IPv6类型的集合,规则里换成
ip6 daddr
内容的提问来源于stack exchange,提问作者archie
相关产品推荐
相关产品推荐

