缺点1:对于管理客户端流量不直观,Connections 里虽然能看到一个内网 IP 连了一个外网 IP,但还得去 DHCP 分配里查这个内网 IP 的主机名或MAC地址,可能还得上网查一下这个 MAC 地址的 vendor,才能确定这个客户端是谁;对于外网 IP 也没法跟 DNS 查询记录里的域名做关联,很不直观。
Unifi 上设置 WAN1(OpenWrt)为 Primary,WAN2(PPPoE)为 Backup,模式为Failover Only
Unifi 上设置策略路由:
1. 目标 Region 为 China 的都走 WAN2(不用勾 Kill Switch,没啥用且会跟下面的DNS hijack有奇妙的冲突);
2. 来自 OpenWrt 的流量都走 WAN2(避免循环,勾上Kill Switch)
OpenWrt 上和标准的路由+代理设置基本相同,WAN 为 DHCP,连接 Unifi 内网。然后要将 WAN 和 WAN6 接口高级设置中的“自动获取 DNS 服务器”禁用,并填入运营商的 DNS 地址,避免循环
效果:正常情况下,客户端的 DNS 请求先到 Unifi 的 DNS 服务器上(对于 DPI 功能有帮助),然后走 WAN1 -> OpenWrt 的无污染 DNS,解析得到国外地址继续走 OpenWrt 做代理(OpenWrt 再通过 Unifi LAN -> PPPoE 连接代理服务器),国内地址直接走 PPPoE 发出。一旦 OpenWrt 挂掉,Unifi 检测到 WAN1 不通,会自动把全部路由和 DNS 都切换到 PPPoE,实现自动降级直连
(可选)此时 Unifi 上可以再设置一个 DNS hijack,让不遵守 DHCP 下发的 DNS 服务器的设备的所有 UDP 53 端口流量都强制发到 Unifi DNS 服务器:增加 DNAT 规则,匹配来源 IP 非 OpenWrt,目标 IP 非 Unifi,目标 UDP 53,将目标 IP 改写为 Unifi 的 IP
IPv6 与 WireGuard Server 问题
按上述方案配置后,你会发现两个问题:
IPv6 不通:哪怕客户端已经具有了来自 PPPoE 的 v6 地址,但 v6 网络就是不通。这里来到了 Unifi 最逆天的地方了:除非主 WAN 断开,不然在任何情况下都试图让 IPv6 走主 WAN,哪怕主 WAN 都没配 IPv6,导致网络不通。
Unifi 上运行的 WireGuard Server 不通:哪怕 WireGuard Server 上设置了监听的是 WAN2 (PPPoE),只要主 WAN 还在,所有回包都会走主 WAN,导致外界的客户端连不上。
这两个问题都是 Unifi 的双 WAN 功能不完善导致的,必须 SSH 进去并设置自启脚本来修正:
#!/bin/sh
# ================= Configuration =================
# backup WAN Interface (real Internet, e.g. PPPoE to ISP)
IFACE="ppp1"
# Routing Table ID for backup WAN (Usually 202 for WAN2)
TABLE="202"
# WireGuard Server Listen Port
WG_PORT="16384"
# Log Tag for syslog
LOG_TAG="UniFi_Network_Fixer"
# =================================================
# Function to clean up rules on exit or restart
cleanup() {
# Remove IPv6 default route
ip -6 route del default dev "$IFACE" metric 1 2>/dev/null
# Remove Policy Routing rule based on Source Port
ip rule del sport "$WG_PORT" lookup "$TABLE" 2>/dev/null
# Remove Force-SNAT rule from NAT table
iptables -t nat -D POSTROUTING -o "$IFACE" -p udp --sport "$WG_PORT" -j MASQUERADE 2>/dev/null
}
# Run cleanup on start to ensure a clean slate
cleanup
logger -t "$LOG_TAG" "Starting network fix script..."
while true; do
# Check if the interface exists
if ip link show "$IFACE" > /dev/null 2>&1; then
# -----------------------------------------------------
# Task 1: Fix IPv6 Direct Access
# Problem: Unifi doesn't add a default IPv6 route for Secondary WAN.
# Fix: Manually add a default route to Main Table via ppp1.
# -----------------------------------------------------
HAS_V6_ROUTE=$(ip -6 route show default dev "$IFACE" metric 1)
if [ -z "$HAS_V6_ROUTE" ]; then
ip -6 route add default dev "$IFACE" metric 1
logger -t "$LOG_TAG" "IPv6: Added default route via $IFACE"
fi
# -----------------------------------------------------
# Task 2: Fix WireGuard VPN Server on Secondary WAN
# Problem: Local UDP traffic uses Primary WAN gateway & source IP.
# Fix A: Policy Routing based on Source Port (Directs traffic to WAN2 Table)
# -----------------------------------------------------
if ! ip rule show | grep -q "sport $WG_PORT lookup $TABLE"; then
# Priority 98 ensures it runs before Unifi's default rules
ip rule add sport "$WG_PORT" lookup "$TABLE" priority 98
ip route flush cache
logger -t "$LOG_TAG" "VPN: Added Policy Routing for Source Port $WG_PORT"
fi
# -----------------------------------------------------
# Fix B: Force SNAT (Masquerade)
# Problem: Source IP might be internal (e.g., 192.168.x.x) even if routed correctly.
# Fix: Force NAT on egress to ensure Source IP matches the Public IP.
# -----------------------------------------------------
if ! iptables -t nat -C POSTROUTING -o "$IFACE" -p udp --sport "$WG_PORT" -j MASQUERADE 2>/dev/null; then
# Insert at top (1) to override any conflicting rules
iptables -t nat -I POSTROUTING 1 -o "$IFACE" -p udp --sport "$WG_PORT" -j MASQUERADE
logger -t "$LOG_TAG" "VPN: Added Force-SNAT rule for port $WG_PORT"
fi
fi
# Check every 30 seconds to handle re-dials or IP changes
sleep 30
done
进一步的,我们发现其配置文件/etc/sysconfig/libvirt-guests从某个版本起被移除了(你还能搜到关于这件事的相关讨论,暴躁用户 vs 倔强maintainer),更不方便我们配置了,因此首先恢复其内容:
# URIs to check for running guests
# example: URIS='default xen:/// vbox+tcp://host/system lxc:///'
#URIS=default
# action taken on host boot
# - start all guests which were running on shutdown are started on boot
# regardless on their autostart settings
# - ignore libvirt-guests init script won't start any guest on boot, however,
# guests marked as autostart will still be automatically started by
# libvirtd
#ON_BOOT=start
# Number of seconds to wait between each guest start. Set to 0 to allow
# parallel startup.
#START_DELAY=0
# action taken on host shutdown
# - suspend all running guests are suspended using virsh managedsave
# - shutdown all running guests are asked to shutdown. Please be careful with
# this settings since there is no way to distinguish between a
# guest which is stuck or ignores shutdown requests and a guest
# which just needs a long time to shutdown. When setting
# ON_SHUTDOWN=shutdown, you must also set SHUTDOWN_TIMEOUT to a
# value suitable for your guests.
ON_SHUTDOWN=shutdown
# If set to non-zero, shutdown will suspend guests concurrently. Number of
# guests on shutdown at any time will not exceed number set in this variable.
#PARALLEL_SHUTDOWN=0
# Number of seconds we're willing to wait for a guest to shut down. If parallel
# shutdown is enabled, this timeout applies as a timeout for shutting down all
# guests on a single URI defined in the variable URIS. If this is 0, then there
# is no time out (use with caution, as guests might not respond to a shutdown
# request). The default value is 300 seconds (5 minutes).
#SHUTDOWN_TIMEOUT=300
# If non-zero, try to bypass the file system cache when saving and
# restoring guests, even though this may give slower operation for
# some file systems.
#BYPASS_CACHE=0