OpenWrt + IPv6 DDNS + wiregurad 全 VPN 组网落地手册
WireGuard 为核心 · 公网零服务暴露 · 多 OS 客户端 · 双向访问 · 多站点互联
环境前提:OpenWrt 上 DNSPod(腾讯云)IPv6 DDNS 已配好,即存在一条 AAAA 记录(如router.example.com)能稳定解析到路由器当前的公网 IPv6。 本手册的核心思路:既然 DDNS 已经让”路由器”在公网可被稳定寻址,我们就只把 WireGuard 的 UDP 51820 端口暴露在公网(经 IPv6),其余一切服务(NAS、HA、Jellyfin、SSH、RDP…)都不暴露公网,全部通过 VPN 隧道按内网域名/地址访问。这样:
- 外部访问内网 Web 服务 → 拨入 VPN 后用
nas.lan访问- 外部管理内网设备(SSH/RDP)→ 拨入 VPN 后直连内网 IP
- 多站点互联(家↔父母家↔办公室)→ 两个 OpenWrt 之间站点对站点 WG
- 内网设备主动连外(反向)→ 隧道天然双向,家里也能主动连到已拨入的手机/笔记本上的服务
0. 约定与地址规划(全文统一,照抄前先改成你自己的)
为避免歧义,全文使用以下地址段。实施前请替换为你自己的,且多站点时各站点 LAN 段不能重叠。
| 用途 | IPv4 | IPv6 (ULA) | 说明 |
|---|---|---|---|
| 家里 LAN | 192.168.1.0/24 |
fd00:cafe:1::/64 |
路由器 = .1 / ::1 |
| 站点 B(父母家)LAN | 192.168.2.0/24 |
fd00:cafe:2::/64 |
路由器 = .1 / ::1 |
| WireGuard 隧道 | 10.200.0.0/24 |
fd00:cafe:9::/64 |
服务端 = .1 / ::1 |
| DDNS 域名 | — | — | router.example.com(站点 B 用 router-b.example.com) |
| 内部域名后缀 | — | — | .lan(由路由器 dnsmasq 解析) |
为什么 VPN 隧道同时配 v4 和 v6 地址? 很多客户端所在网络只有 v4,隧道走 v4 更兼容;而家里内网又有 v6 服务。双栈隧道让两种资源都能到达。
1. 前置确认:DNSPod DDNS 端点可用性
WireGuard 客户端的 Endpoint 会写成 router.example.com:51820,所以这条 AAAA 必须始终指向路由器当前的公网 GUA。先验证:
# 在任意公网主机(或手机蜂窝网络)上
dig AAAA router.example.com +short
# 应输出类似 2408:xxxx:xxxx:xxxx::1
# 验证它正是路由器 WAN 当前的 GUA(在 OpenWrt 上)
ip -6 addr show pppoe-wan 2>/dev/null || ip -6 addr show wan 2>/dev/null
# 或
ifstatus wan | jsonfilter -e '@["ipv6-address"][0].address'
若两者一致 → DDNS 正常。若不一致 → 先修 DDNS(见附录 C 的 DNSPod 更新脚本与排查)。
重要提醒:客户端所在网络必须有 IPv6才能连到这个 v6 端点。若你的客户端常出现在纯 v4 环境(很多公司 WiFi、部分蜂窝),建议二选一:
- 向运营商要公网 IPv4,DDNS 同时维护 A 记录,WG 端点用域名(自动选 v4/v6);
- 用一台便宜 VPS 做 WG 中继(VPS 有双栈),客户端连 VPS,VPS 再连家里。本手册主流程按”IPv6 端点”写,VPS 中继见 §8。
2. OpenWrt WireGuard 服务端配置(家里路由器)
2.1 安装
⚠️ 先确认你的包管理器。OpenWrt 24.10+ / 25.x 已从opkg切换到apk;旧版(23.05 及更早)仍是opkg。下面给出两套命令,只跑你那套。判断方法:能跑apk就是新固件。
OpenWrt 25.x / 24.10(apk):
apk update
apk add wireguard-tools luci-proto-wireguard qrencode
OpenWrt 23.05 及更早(opkg):
opkg update
opkg install wireguard-tools luci-proto-wireguard qrencode
luci-proto-wireguard让你能在 LuCI 里管理(否则 LuCI 显示”不支持的协议类型”);qrencode用于给手机生成二维码。 装完 LuCI 扩展后,若 LuCI 仍显示”不支持的协议”,或新装的协议接口ifup静默失败,执行/etc/init.d/network restart(不是 reload)重启 netifd,让它重新扫描协议脚本(/lib/netifd/proto/wireguard.sh)。详见 §2.7。 存储空间提示:WireGuard 相关包总计约 350–500 KB,但 64MB flash 设备(如新路由3)装完包后务必清缓存:apk cache clean或rm -f /var/opkg-lists/*(opkg)。OK: 31.1 MiB in 216 packages这类输出是全系统已装总量,不是本次安装大小,别被吓到。空间紧张就挂 extroot。
2.2 生成服务端密钥对
mkdir -p /etc/wireguard # 目录默认不存在,必须先建
wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub
chmod 600 /etc/wireguard/server.key
cat /etc/wireguard/server.pub # 记下公钥,客户端 [Peer] PublicKey 用
用绝对路径生成,别cd /etc/wireguard后再生成——该目录可能不存在导致cd失败,后续命令就在错误目录(/root)执行,文件位置对不上。 私钥随后会写入/etc/config/network的wg0.private_key字段(由 uci 完成),server.key文件只是中转与备份,删掉不影响运行(建议离线备份,别上传云端)。
2.3 配置接口 /etc/config/network
用 uci 或直接编辑。下面用 uci 批量写入(可整体粘贴):
uci -q delete network.wg0
uci set network.wg0='interface'
uci set network.wg0.proto='wireguard'
uci set network.wg0.private_key="$(cat /etc/wireguard/server.key)"
uci set network.wg0.listen_port='51820'
uci add_list network.wg0.addresses='10.200.0.1/24'
uci add_list network.wg0.addresses='fd00:cafe:9::1/64'
uci commit network
⚠️ 必须uci commit。uci show看到的是 uci 内存状态,netifd 读的是/etc/config/network文件。漏 commit 会导致 netifd 根本不知道有 wg0,ifup wg0静默失败。验证:grep -A10 "config interface 'wg0'" /etc/config/network能看到才算真写进去了。 隧道地址为什么用 ULA(fd00:cafe:9::/64)而不是公网 GUA? 运营商下发的 IPv6 前缀是动态变化的(如2409:8a62:...每次拨号都变)。若隧道地址用 GUA,前缀一变整条隧道地址失效、所有客户端配置作废。ULA 永远不变,适合做隧道寻址。代价是 ULA 公网不可路由 → WG 客户端 IPv6 不走家里出公网(v4 靠 NAT 出,v6 访问内网走 ULA 互通即可,这是有意取舍)。详见 §6 与 §9 排错。
等会儿在 §2.6 加 peer(客户端)。先做防火墙。
2.4 防火墙:放行 51820 + 建立 wg 区域
端口可自定义:若 51820 被运营商/光猫封禁,改用其他端口(如 10520)。改端口时三处必须同步:uci set network.wg0.listen_port='10520'+ 防火墙放行 10520 + 客户端 Endpoint 用 10520。改完network restart(非 reload)让监听端口生效。下方示例用 51820,按需替换。
编辑 /etc/config/firewall,增加:
# 1) 放行 WAN 侧 UDP 51820(双栈,一条规则 family=any 即可)
uci add firewall rule
uci set firewall.@rule[-1].name='Allow-WG-51820'
uci set firewall.@rule[-1].src='wan'
uci set firewall.@rule[-1].dest_port='51820'
uci set firewall.@rule[-1].proto='udp'
uci set firewall.@rule[-1].target='ACCEPT'
# 2) 新建 wg 区域
uci add firewall zone
uci set firewall.@zone[-1].name='wg'
uci set firewall.@zone[-1].input='ACCEPT'
uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].forward='ACCEPT'
uci add_list firewall.@zone[-1].network='wg0'
# 3) wg <-> lan 互通(双向访问的关键)
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='wg'
uci set firewall.@forwarding[-1].dest='lan'
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='lan'
uci set firewall.@forwarding[-1].dest='wg'
# 4) (可选)让 VPN 客户端走家里出口上网(v4)——靠 wan 区域的 masq,不要单独写 MASQUERADE 规则
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='wg'
uci set firewall.@forwarding[-1].dest='wan'
# 给 wan 区域开 masq:这样所有转发到 wan 的 v4 流量自动 SNAT,WG 客户端即可 v4 出公网
# 先查 wan 是第几个 zone:uci show firewall | grep "name='wan'" (假设 @zone[1])
uci set firewall.@zone[1].masq='1' # 索引按你实际查到的改!别照抄 [1]
uci commit firewall
/etc/init.d/firewall restart
⚠️ 千万不要单独写target='MASQUERADE'的 rule。MASQUERADE 目标会跳到masquerade_to_wan链,而该链只有当 wan zone 启用masq='1'时才生成。若 wan 没开 masq 却写了 MASQUERADE rule,firewall restart会报错:此时防火墙不会重启、保持旧规则。修复:删掉那条 MASQUERADE rule(Error: No such file or directory; did you mean chain 'forward_wan' ...? meta nfproto ipv4 counter jump masquerade_to_wan comment "!fw4: ..." The rendered ruleset contains errors, not doing firewall restart.uci delete firewall.@rule[N],N 用uci show firewall | grep MASQ查真实索引,别照抄文档里的索引),改为给 wan zone 开masq='1'。 删 rule 时索引必须现查:uci show firewall | grep WG-MASQ会显示如firewall.@rule[13].name='WG-MASQ-v4',就用 13。文档里的[1]/[3]只是示例,每台机器不同。 masq 只管 IPv4。IPv6 是真实公网地址,不要开 masq6、不要做 NAT66(反模式,且 fw4 支持有限)。WG 客户端 v6 出公网用客户端本地网络的 v6,不绕回家;v6 访问内网走 ULA 互通。详见 §6。
2.4.1 确保 wan6 纳入 wan 区域
OpenWrt 里 IPv6 通常走单独的 wan6 接口。防火墙 wan 区域的 network 列表必须同时包含 wan 和 wan6,否则 v6 流量的 zone 归属会错。
uci show firewall.@zone[1] # 看 network 字段
# 应类似:firewall.@zone[1].network='wan wan6'
# 若没有 wan6,补上:
uci add_list firewall.@zone[1].network='wan6' # 索引按实际
uci commit firewall
/etc/init.d/firewall restart
解释:wg↔lan双向 forwarding 是”双向访问”的防火墙基础。lan→wg让家里设备能主动连到已拨入的手机(反向访问)。若你不想要”v4 全流量走家”,省略第 4 步的wg→wanforwarding 即可(纯 split tunnel,只访问内网)。
2.5 让 dnsmasq 在 wg 接口上提供 DNS(让客户端解析 .lan)
VPN 客户端会把 DNS 指向路由器隧道地址,需要 dnsmasq 监听 wg0。
⚠️ 血泪坑:千万别设 dnsmasq 的interface字段! 早期版本曾写uci add_list dhcp.@dnsmasq[0].interface='wg0',这是错的。dnsmasq 的interface/interfaces是排他监听列表——一旦设置,dnsmasq 只监听列表里的接口,lan/loopback 等全被排除 → LAN 设备无法解析 DNS → 全屋断网。add_list在这里不是”追加监听”,而是”限定只听这几个”。 正确做法:不设interface字段。 dnsmasq 默认监听所有接口(含 wg0、lan、loopback),只需用notinterface排除 WAN(防止 DNS 暴露公网)即可。OpenWrt 默认已排除 wan,通常什么都不用配,wg0 自动被监听。
# 1) 如果之前误设过 interface,必须清掉(恢复监听全部接口)
uci -q del_list dhcp.@dnsmasq[0].interface='wg0'
uci -q delete dhcp.@dnsmasq[0].interface # 清空整个 interface 列表
# 确认 notinterface 含 wan(默认有,防 DNS 暴露公网):
# uci show dhcp.@dnsmasq[0] | grep notinterface
# 没有则:uci add_list dhcp.@dnsmasq[0].notinterface='wan'
# 2) 给 wg0 建一个 dhcp 段但禁用 DHCP(只保留 DNS 解析能力,不发地址租约)
uci set dhcp.wg='dhcp'
uci set dhcp.wg.interface='wg0'
uci set dhcp.wg.ignore='1'
uci commit dhcp
/etc/init.d/dnsmasq restart
验证 dnsmasq 监听了 wg0 且没排除 lan:
# 看 dnsmasq 启动参数,应能看到监听 wg0 和 br-lan,且 --bind-dynamic 或监听 0.0.0.0
pgrep -a dnsmasq
# 测试:从路由器自身解析(应正常)
nslookup nas.lan 127.0.0.1
# 从 LAN 设备也能解析 = 没误伤 lan
误设 interface 后的症状与修复:全屋设备无法上网、nslookup超时、LuCI 能开但网页打不开。修复就是上面第 1 步:清空dhcp.@dnsmasq[0].interface列表,restart dnsmasq。清空后 dnsmasq 回到”监听所有接口(除 notinterface 里的 wan)”,lan/wg0 都正常。
并定义内网域名(示例,按你设备改):
uci -q delete dhcp.nas_domain
uci add dhcp domain
uci set dhcp.@domain[-1].name='nas.lan'
uci set dhcp.@domain[-1].ip='192.168.1.10' # 或 'fd00:cafe:1::10'
uci add dhcp domain
uci set dhcp.@domain[-1].name='ha.lan'
uci set dhcp.@domain[-1].ip='192.168.1.12'
uci add dhcp domain
uci set dhcp.@domain[-1].name='win.lan'
uci set dhcp.@domain[-1].ip='192.168.1.20' # RDP 目标机
uci commit dhcp
/etc/init.d/dnsmasq restart
2.6 启动接口并添加第一个客户端 peer
# 装包后第一次启动,用 restart 而非 reload,确保 netifd 重新加载协议脚本
/etc/init.d/network restart
sleep 3
wg show
⚠️ 常见坑:ifup wg0/network reload后wg0不存在。
- 症状:
ip -6 addr show wg0报Device "wg0" does not exist.,wg show空输出,ifup wg0无任何回显,且 netifd 日志里完全没有 wg0 记录。- 根因:
reload只重载已注册接口,不重新扫描协议脚本。刚装完wireguard-tools后协议才注册,netifd 仍持有旧的协议列表,不认识wireguard协议。- 修复:
/etc/init.d/network restart(重启整个 netifd,重新扫描/lib/netifd/proto/wireguard.sh)。验证该文件存在:ls -l /lib/netifd/proto/wireguard.sh。- 其他可能:
uci commit network漏了(配置没写进/etc/config/network,netifd 读不到)→grep -A10 "config interface 'wg0'" /etc/config/network确认。- 兜底排查:
logread -e netifd | tail -30看 netifd 报什么;which wg确认命令在 PATH。
peer 的添加在 §3 为每个客户端做(因为要先有客户端公钥)。
2.7 验证服务端
wg show # 应看到 wg0 listening on 51820 + public key(此时无 peer,正常)
ip -6 addr show wg0 # 应有 10.200.0.1/24 和 fd00:cafe:9::1/64
以命令行wg show为准,别迷信 LuCI。LuCI 显示可能滞后或受协议包加载时机影响;只要wg show有listening port: 51820就是真正起来了。装了luci-proto-wireguard后强刷 LuCI(/etc/init.d/rpcd restart后浏览器 Ctrl+F5)即正常。
wg0 没有 MAC 地址是正常的,不是配置错。 WireGuard 是 L3(网络层)隧道接口,直接封装 IP 包、没有以太网帧头,而 MAC 是 L2(数据链路层)概念,只有承载以太网帧的接口(eth0/br-lan/wlan0)才有。所以ip link show wg0输出里没有link/ether那一行是预期行为(与lo、tun同类)。判断 wg0 是否正常只看 IP 地址和wg show,不要用有无 MAC 来判断。
2.7.1 怎么算”连接成功”(接口层 vs 握手层)
接口起来 ≠ 隧道打通。分两层判定:
层 1:接口起没起(服务端/客户端通用)
ip -6 addr show wg0 # 有隧道地址 = 接口层 OK
wg show # 能列出接口 + peer = 接口层 OK
层 2:握手成没成功(隧道是否真通)—— 这才是硬指标
wg show
看 peer 下这两行:
- 有
latest handshake: 几秒/几十秒前= 握手成功,密钥协商完成,隧道建立 ✅ - 同时
transfer: ... received, ... sent计数在涨 = 真的在收发包 ✅ - 若没有
latest handshake这行、transfer: 0 B received= 握手失败,没真正连上(查公钥是否贴反、endpoint 解析、防火墙是否挡 51820、客户端是否残留ListenPort,见 §10)。
握手成功后用实际流量验证端到端:
ping 10.200.0.1 # 通 = 隧道对端可达
ping nas.lan # 通 = DNS 解析 + 内网都通
ping 192.168.1.10 # 通 = 路由/forwarding 都对
| 状态 | wg show 表现 |
结论 |
|---|---|---|
| 接口没起 | 空输出 / Device does not exist |
配置或 netifd 问题(§2.6 坑) |
| 接口起了、没握手 | 有 peer,但无 latest handshake,rx=0 |
握手失败,查 endpoint/公钥/防火墙 |
| 握手成功 | 有 latest handshake: 几秒前 + rx/tx 在涨 |
连接成功 ✅ |
| 端到端通 | 上面 + ping 10.200.0.1 / ping nas.lan 通 |
全链路 OK ✅✅ |
从公网(手机蜂窝)测试 UDP 可达:
nc -6 -u -v router.example.com 51820 # 不通也没响应是正常的(WG 不握手不回包),主要看防火墙没被 drop
更可靠的验证:配好客户端后看 wg show 出现最新握手时间。
3. 客户端配置(四类 OS)
每个客户端都需要:自己的密钥对 + 一份 .conf。下面先给通用 .conf 模板,再讲各 OS 怎么导入。
3.1 通用客户端配置模板
把下面存为 client.conf,按注释替换:
[Interface]
PrivateKey = <客户端私钥>
Address = 10.200.0.2/24, fd00:cafe:9::2/64
DNS = 10.200.0.1, fd00:cafe:9::1
MTU = 1420
[Peer]
PublicKey = <服务端公钥,即 /etc/wireguard/server.pub>
PresharedKey = <可选,见 3.2;不用就删掉这行>
Endpoint = router.example.com:51820
# 想访问哪些内网段,就写哪些。下面是家里全部内网 + 隧道段:
AllowedIPs = 192.168.1.0/24, fd00:cafe:1::/64, 10.200.0.0/24, fd00:cafe:9::/64
# 想让全部流量都走家里(全隧道),改为:
# AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
AllowedIPs 的含义:既决定”哪些目标流量进隧道”,也决定”服务端把哪些源地址路由给这个 peer”。所以它必须精确包含该客户端的隧道地址之外,还要包含它要访问的内网段。
⚠️ 客户端配置三大坑(实测踩过,务必避免):MTU 选择:默认 1280(IPv6 最小值,保守但低效,包多速度慢)。链路 MTU 1500 时用
- 绝不要在客户端
[Interface]里写ListenPort。这是服务端用的。客户端设了 ListenPort 会强制绑定本地端口监听,导致 Android/iOS 的 VpnService 路由混乱、握手包发不出去(表现:tcpdump抓不到 WG 包,wg show无握手,但 ping/nmap 能通)。客户端用随机端口主动连服务端即可。AllowedIPs格式必须用半角逗号+空格,分隔,绝不能用全角逗号,。从中文输入法粘贴、或带不可见字符,Android App 会报bad address。最稳的做法是用二维码导入(见 §3.5),由qrencode保证格式。手动输入时每段可单独成行。验证配置文件无隐藏字符:cat -A client.conf(正常行尾$,无^M/M-乱码)。- 路由环:Endpoint 所在网段不能出现在 AllowedIPs 里(内网测试时)。若
Endpoint = 192.168.1.1:51820且AllowedIPs含192.168.1.0/24,手机会把去往 192.168.1.1 的握手包也导向尚未建立的隧道 → 死锁 → 不发包。内网测试时 AllowedIPs 去掉 Endpoint 网段,只留隧道段:10.200.0.0/24, fd00:cafe:9::/64, fd00:cafe:1::/64。公网测试(Endpoint=域名)无此问题,因为域名解析出的公网地址不在内网段。0.0.0.0/0全流量模式下,WG 会自动排除 Endpoint 路由,公网场景可用;但内网 Endpoint + 0.0.0.0/0 仍可能死锁,故内网测试优先用具体段。1420,PPPoE(1492)用1412。调大可提速,但过大会丢包。测隧道 MTU:ping -M do -s 1392 10.200.0.1,不通就减,最大不丢包值 +28 = WG MTU。
3.2 (推荐)生成预共享密钥 PSK,多一层对称加密
在任一机器上:
wg genpsk > psk.txt
把内容同时填到服务端该 peer 的 preshared_key 和客户端 [Peer] 的 PresharedKey。即使量子计算时代也能多抗一层。
3.3 生成客户端密钥对
Linux / macOS:
wg genkey | tee client.key | wg pubkey > client.pub
Windows(PowerShell,装了官方 WireGuard 后):
& "C:\Program Files\WireGuard\wg.exe" genkey | Out-File -Encoding ascii client.key
& "C:\Program Files\WireGuard\wg.exe" pubkey < client.key | Out-File -Encoding ascii client.pub
或在官方 GUI 里点 “Generate keypair”。
iOS / Android: 在官方 WireGuard App 里新建隧道时选”Create from scratch”,App 会自动生成密钥;你只需把它的 Public key 抄出来填到路由器。
3.4 把客户端公钥注册到 OpenWrt 服务端
假设手机客户端公钥是 PHONE_PUB,隧道地址 10.200.0.2 / fd00:cafe:9::2:
uci add network wireguard_wg0
uci set network.@wireguard_wg0[-1].description='phone'
uci set network.@wireguard_wg0[-1].public_key='PHONE_PUB'
uci set network.@wireguard_wg0[-1].preshared_key="$(cat /etc/wireguard/psk.txt)" # 可选
uci add_list network.@wireguard_wg0[-1].allowed_ips='10.200.0.2/32'
uci add_list network.@wireguard_wg0[-1].allowed_ips='fd00:cafe:9::2/128'
uci commit network
ifdown wg0 && ifup wg0
服务端 peer 的allowed_ips只填该客户端的隧道地址(它要访问的内网段不写在这里)。要”反向”让家里访问手机上的服务,靠的就是这个隧道地址——家里设备连10.200.0.2:端口即可(见 §4.3)。
3.5 各 OS 导入与启用
Windows
- 装 WireGuard for Windows。
- 打开 → “Import tunnel(s) from file” → 选
client.conf。 - 双击隧道 → 连接。
- 测试:
ping 10.200.0.1、ping nas.lan、ping 192.168.1.10。
macOS
- App Store 装 “WireGuard” 或
brew install wireguard-tools。 - App:”Import from file” →
client.conf;或命令行:sudo wg-quick up client # 配置放 /usr/local/etc/wireguard/client.conf - 测试同上。
Linux(以 wg-quick + systemd 为例)
sudo apt install wireguard # Debian/Ubuntu
# 或 sudo dnf install wireguard-tools # Fedora
sudo install -d -m 700 /etc/wireguard
sudo cp client.conf /etc/wireguard/wg-home.conf
sudo wg-quick up wg-home # 临时启用
sudo systemctl enable --now wg-quick@wg-home # 开机自启
NetworkManager 方式(GUI 发行版):
nmcli connection import type wireguard file wg-home.conf
nmcli connection up wg-home
iOS / Android
- 装官方 WireGuard App。
- 两种导入:
- 二维码:在路由器上对配置生成码,手机扫码——
# 把上面 client.conf 内容生成二维码(路由器装了 qrencode) qrencode -t ansiutf8 < client.conf # 手机 App → "+" → "Scan from QR code" - 文件:把
client.conf传到手机 → App → “+” → “Import from file”。
- 二维码:在路由器上对配置生成码,手机扫码——
- 连接后用 Safari/Chrome 访问
http://nas.lan验证。
给手机配 IP 时,建议用固定隧道地址(如手机固定 10.200.0.2),方便家里反向连它。每多一台设备,递增一个地址并在服务端加 peer。
4. 双向访问实现(四种场景全部打通)
4.1 场景一:外部访问内网 Web 服务
拨入 VPN 后,客户端的 AllowedIPs 含 192.168.1.0/24,DNS 指向路由器 → 直接:
http://nas.lan:5000 # NAS 管理台
http://ha.lan:8123 # HomeAssistant
http://jellyfin.lan:8096
无需任何公网暴露。若想用 HTTPS,在 NAS/服务本机用自签证书或内网 CA 即可(因为只走隧道,证书可信度由你自己的客户端决定,见 §6.4)。
4.2 场景二:外部管理内网设备(SSH / RDP)
拨入 VPN 后直连内网 IP:
# SSH 到 Linux 机器
ssh user@192.168.1.10
ssh user@nas.lan
# RDP 到 Windows 机器(先在目标机开启远程桌面)
# Windows: 设置 → 远程桌面 → 启用;并确保防火墙放行 3389(内网即可)
# 从客户端:
xfreerdp /v:192.168.1.20 /u:username # Linux/macOS
# 或 Windows 自带"远程桌面连接" → 192.168.1.20
目标机只需在内网放行对应端口(SSH 22 / RDP 3389 给 192.168.1.0/24 或给路由器),无需对公网开放。
4.3 场景三:内网设备主动连外(反向,家里访问手机上的服务)
WireGuard 是点对点隧道,一旦手机拨入,隧道双向可达。家里设备要访问手机上跑的服务(如手机上的 Termux SSH、AirDroid、调试服务):
- 手机客户端隧道地址固定为
10.200.0.2(§3.4 已注册)。 - 防火墙 §2.4 已开
lan→wgforwarding。 - 手机上的服务监听
0.0.0.0或隧道地址10.200.0.2。 - 家里任意设备:
ssh termux@10.200.0.2 -p 8022 # 连手机 Termux SSH curl http://10.200.0.2:8080 # 连手机上的服务
关键:服务端 peer 的allowed_ips必须包含10.200.0.2/32(§3.4 已做),否则家里发往10.200.0.2的包不知道路由给哪个 peer。
4.4 场景四:多站点互联(家 ↔ 父母家)→ 见 §5
5. 多站点互联(站点对站点 WireGuard)
两台 OpenWrt:站点 A(家,router.example.com)、站点 B(父母家,router-b.example.com)。让 A 站的设备能直接访问 B 站的设备,反之亦然。
5.1 前提
- 两站 LAN 段不重叠(本例 A=
192.168.1.0/24,B=192.168.2.0/24)。 - 两站 DDNS 都配好(AAA 记录指向各自路由器 GUA)。
- 两站都按 §2 装好 WireGuard 并有 wg0 接口。建议两站 wg0 用同一隧道网段不同地址:A=
10.200.0.1,B=10.200.0.2。
若 A 的 wg0 已是 10.200.0.1 并服务着手机客户端,只需把 B 也接进这个 wg0(作为另一个 peer)即可。下面假设这种”一台路由器 wg0 既是接入服务端又是站点 peer”的常见结构。
5.2 站点 A(家)配置 B 为 peer
uci add network wireguard_wg0
uci set network.@wireguard_wg0[-1].description='site-B'
uci set network.@wireguard_wg0[-1].public_key='<B的公钥>'
uci set network.@wireguard_wg0[-1].preshared_key="$(cat /etc/wireguard/pskAB.txt)"
# 关键:把 B 站的 LAN 段和 B 的隧道地址都放进 allowed_ips
uci add_list network.@wireguard_wg0[-1].allowed_ips='10.200.0.2/32'
uci add_list network.@wireguard_wg0[-1].allowed_ips='192.168.2.0/24'
uci add_list network.@wireguard_wg0[-1].allowed_ips='fd00:cafe:2::/64'
# 站点 B 没有公网 v4 时,给 endpoint 用它的 DDNS 域名 + keepalive 维持
uci set network.@wireguard_wg0[-1].endpoint_host='router-b.example.com'
uci set network.@wireguard_wg0[-1].endpoint_port='51820'
uci set network.@wireguard_wg0[-1].persistent_keepalive='25'
uci commit network
ifdown wg0 && ifup wg0
5.3 站点 B 配置 A 为 peer(对称)
在站点 B 的 OpenWrt 上(假设它的 wg0 地址是 10.200.0.2):
uci add network wireguard_wg0
uci set network.@wireguard_wg0[-1].description='site-A'
uci set network.@wireguard_wg0[-1].public_key='<A的公钥>'
uci set network.@wireguard_wg0[-1].preshared_key="$(cat /etc/wireguard/pskAB.txt)"
uci add_list network.@wireguard_wg0[-1].allowed_ips='10.200.0.1/32'
uci add_list network.@wireguard_wg0[-1].allowed_ips='192.168.1.0/24'
uci add_list network.@wireguard_wg0[-1].allowed_ips='fd00:cafe:1::/64'
uci set network.@wireguard_wg0[-1].endpoint_host='router.example.com'
uci set network.@wireguard_wg0[-1].endpoint_port='51820'
uci set network.@wireguard_wg0[-1].persistent_keepalive='25'
uci commit network
ifdown wg0 && ifup wg0
5.4 两站防火墙:允许 wg↔lan
两站都执行(与 §2.4 的 wg↔lan forwarding 相同,若已建 wg 区域则已有):
# 若还没建 wg 区域,参考 §2.4。已有则只需确保 forwarding 存在:
uci add firewall forwarding; uci set firewall.@forwarding[-1].src='wg'; uci set firewall.@forwarding[-1].dest='lan'
uci add firewall forwarding; uci set firewall.@forwarding[-1].src='lan'; uci set firewall.@forwarding[-1].dest='wg'
uci commit firewall; /etc/init.d/firewall restart
5.5 (关键)关闭两站之间的 ICMP/路由限制 + 允许转发
确保内核转发开启(OpenWrt 默认开):
cat /proc/sys/net/ipv4/ip_forward # 应为 1
cat /proc/sys/net/ipv6/conf/all/forwarding # 应为 1
5.6 验证
# 在 A 站路由器上
wg show # 看到 site-B peer 有最新握手 + rx/tx 计数
ping 192.168.2.1 # ping 通 B 站路由器
# 在 A 站某台 LAN 设备上
ping 192.168.2.x # ping 通 B 站内网设备
ssh user@192.168.2.x # 直接 SSH 到父母家设备
三站及以上同理:每两站互指 peer,allowed_ips 写对方所有内网段。注意别成环,必要时用更精确的路由 / 调整 allowed_ips。
6. 安全加固(全 VPN 架构下的纵深防御)
即使”只暴露一个 WG 端口”,也要按”这个端口迟早会被发现”来设防。
6.1 WireGuard 自身
- PSK 必加(§3.2),抗未来量子泄露。
- 私钥权限
chmod 600,不上传公网仓库/云笔记。建议离线保管(如加密 U 盘)。 - 端口可改非 51820(降低扫描噪声):改
listen_port与防火墙放行端口即可。 - peer 列表最小化:离职/卖掉的设备立刻删 peer(
uci delete network.@wireguard_wg0[N])。 - 客户端
AllowedIPs用最小集:只放需要访问的内网段,别图省事全0.0.0.0/0(除非你真要全流量走家)。
6.2 边界防火墙
wan区域INPUT/FORWARD默认 DROP,仅放行51820/udp(§2.4)。- 关闭 UPnP / NAT-PMP:
/etc/config/upnpd删除或禁用服务,防止内网程序自行开洞。/etc/init.d/miniupnpd disable && /etc/init.d/miniupnpd stop - ICMPv6 必需类型放行(ND/PMtuD:类型 1/2/3/4/128/129/133-137),否则 IPv6 异常;echo-reply 可选关闭防扫描。
- LuCI / SSH 绝不监听 WAN:
/etc/config/uhttpd监听地址只绑内网;dropbear同理。
6.3 路由器加固
# 改强 root 密码
passwd
# 用 SSH key 登录,禁密码(/etc/config/dropbear)
uci set dropbear.@dropbear[0].PasswordAuth='off'
uci set dropbear.@dropbear[0].RootPasswordAuth='off'
uci commit dropbear; /etc/init.d/dropbear restart
# 先放好 authorized_keys 再禁密码!否则会锁死
mkdir -p /etc/dropbear
cp your_pubkey /etc/dropbear/authorized_keys
- 关闭不用的服务:telnet、tftp、旧 uhttpd 端口。
- 及时更新:
apk update && apk upgrade(apk,25.x)或opkg update && opkg upgrade(opkg,旧版),关注 OpenWrt 安全版本。 - 备份含密钥:
sysupgrade -b导出的 tar 里有私钥,离线保管。
6.4 服务侧(即使只在内网)
- NAS/HA/Jellyfin 仍要强密码 + 2FA,因为 VPN 内的设备也可能被 compromise(如手机丢了)。
- 敏感服务走 HTTPS(自签证书或自建 CA),防 VPN 内嗅探。
- IoT 隔离:摄像头/扫地机放独立 VLAN(见 §7),禁止其访问
lan/wg,仅允许iot→wan。
6.5 DNSPod DDNS 凭证最小权限
- 腾讯云 → 访问管理 CAM → 新建子用户 → 只授予
QcloudDNSPodFullAccess或更精细的”仅指定域的记录编辑”自定义策略。 - 不要用主账号 API 密钥。
- SecretId/SecretKey 存路由器脚本里
chmod 600,且不要打印到日志/备份。 - 定期轮换;监控更新失败(前缀变了但更新失败 → 域名指向旧地址 → VPN 断)。
6.6 客户端安全
- 手机/电脑系统全盘加密、锁屏密码。
- WireGuard 配置文件含私钥,传输用加密渠道,用完即删。
- 公司设备别长期挂着家 VPN,避免家内网被公司 MDM 风险波及。
7. 性能瓶颈与硬件选型(重要:先看再排查速度)
实测案例:小米路由器 4C(MT7628N 单核 580MHz、64MB 内存、16MB flash)跑 WireGuard,速度仅 15-25 Mbps,CPU 100% 满载。 这是硬件极限,任何配置调整都无法突破。本节帮你判断自己是否撞到硬件墙。
7.1 怎么判断是不是硬件瓶颈
跑 WG 传大文件时,在路由器上看 CPU:
top -d 2 -n 3
若看到(典型硬件瓶颈特征):
CPU: 0% usr 60% sys 0% idle 40% sirq ← idle 0%,满载
[kworker/0:2+wg-] 36% ← WG 加密内核线程占大头
[kworker/0:1+wg-] 29%
[ksoftirqd/0] 11%
Load average: 4.36 ← 单核负载 4 倍,严重过载
netifd D 状态 ← D=不可中断,CPU 太忙连 netifd 都卡
wg- 内核 worker 占满 CPU + idle 0% = CPU 加密到顶,纯硬件瓶颈。配置层面无解。
7.2 各级硬件的 WireGuard 速度天花板
| 硬件 | 典型机型 | WG 速度 | 备注 |
|---|---|---|---|
| MT7628N 单核 | 小米4C、NW702 等 | 15-25 Mbps | 入门级,跑 WG 勉强,只够轻量管理 |
| MT7621AT 双核 | 红米 AC2100、Newifi3、K2P | 150-250 Mbps | 性价比之选,日常够用 |
| MT7621 + 硬件加密 | 部分型号 | 略提升 | WG 用 ChaCha20,多数硬件加密引擎只支持 AES,帮不上 |
| MT7981/7986 | 红米 AX6000、GL.iNet Flint2 | 300-500 Mbps | 现代 WiFi6,主流推荐 |
| IPQ8074 | 小米 AX9000 | 500-700 Mbps | 高端 |
| x86 N100/J4125 | 软路由 | ~1 Gbps | 跑满千兆 |
注意:WireGuard 用 ChaCha20-Poly1305,多数路由器的硬件加密引擎只加速 AES(给 IPSec/OpenVPN 用),对 WG 帮不上。所以 WG 速度主要看 CPU 核数和主频,不能只看”有硬件加密”。
7.3 软优化(撞墙前的调优,有限提升)
- 改 split tunnel(最有效):客户端
AllowedIPs用具体内网段,而非0.0.0.0/0。这样上网流量不走 VPN、不经路由器加密,CPU 只处理内网访问流量。0.0.0.0/0全流量模式让 CPU 同时干加密+NAT,雪上加霜。 - 调大 MTU:
MTU = 1420(链路 1500)或1412(PPPoE 1492)。1280包多中断多、CPU 忙。测 MTU:ping -M do -s 1392 10.200.0.1。 - 关掉不用的服务腾 CPU/内存:如同时跑 ZeroTier(和 WG 功能重叠)、UPnP 等。
top看谁占资源,不用就disable。 - IPv6 不走 VPN 出口:隧道地址用 ULA(公网不可路由),WG 客户端 v6 出公网用客户端本地 v6,不做 NAT66。这避免了 NAT66 的 CPU 开销和反模式坑。
7.4 硬突破:把 WG 服务端挪到强设备
路由器 CPU 弱但家里有强设备(NAS、小主机、树莓派4、常开电脑)时,WG 服务端跑在强设备上,路由器只做端口转发,加密负担转移:
- 强设备(如 NAS)装 WireGuard,监听 10520
- 路由器把公网 10520/udp 转发到强设备内网 IP
- 手机拨路由器公网地址:10520 → 路由器转发 → 强设备加密
- 速度由强设备决定,通常能跑满百兆甚至千兆
# OpenWrt 端口转发(v4;v6 场景让强设备直接拿 GUA 监听更优)
config redirect
option name 'WG-to-NAS'
option src 'wan'
option src_dport '10520'
option dest 'lan'
option dest_ip '192.168.1.50' # 强设备内网 IP
option dest_port '10520'
option proto 'udp'
7.5 迁移案例:小米4C → 红米 AC2100
若手头有更强路由器(如红米 AC2100,MT7621 双核),直接让它当主路由跑 WG,4C 退二线。速度从 20M 提到 150-250M(7-10 倍),CPU 不再满载,内存 128M 宽裕。
迁移要点:
- AC2100 刷 OpenWrt/ImmortalWrt(原厂不支持 WG)。
- AC2100 接光猫/上级网络,重做 §2 全部配置。
- 密钥可复用:在 4C 导出
uci show network.wg0、server.key、psk.txt,在 AC2100 用相同值配置 → 手机客户端配置零改动(只要 DDNS 域名仍指向新路由器的 GUA)。 - DDNS 在 AC2100 上跑,域名更新指向 AC2100 的 GUA。
- IPv6 场景下 AC2100 直接当主路由最顺(避免 4C 做 v6 转发的复杂拓扑)。
结论:在弱路由器(4C/MT7628N 级)上反复调 WG 速度是浪费时间——配置调不出硬件没有的速度。 先确认 CPU 是否满载(§7.1),是则按 §7.4 挪走 WG 或 §7.5 换路由器。split tunnel(§7.3)只让”上网不受 VPN 限速”,内网访问速度仍受硬件天花板限制。
7.6 弱路由器的内存与闪存纪律
以小米4C(64MB 内存 / 16MB flash)为例,资源极紧张,务必:
- 服务最小集,不堆插件(反代、监控等别往上加)。
apk cache clean/rm -f /var/opkg-lists/*清缓存;df -h /保持几 MB 余量。- 16MB flash 无 USB 口无法 extroot,只能省着用。
- 内存紧会 OOM/服务崩溃,
top定期看Mem。
8. 进阶:IPv6 子网划分与 VLAN 隔离(可选)
运营商下发 /60 或 /56 时,可给不同 VLAN 分配不同 /64 公网前缀,同时每 VLAN 配 ULA(断网也能内联)。
WAN 下发 2408:aaaa:bbbb:cc00::/60
├─ lan 2408:aaaa:bbbb:cc10::/64 fd00:cafe:1::/64 信任设备
├─ iot 2408:aaaa:bbbb:cc20::/64 fd00:cafe:3::/64 IoT 隔离
└─ guest 2408:aaaa:bbbb:cc30::/64 fd00:cafe:4::/64 访客
OpenWrt 示例(IoT 接口):
# 网络
uci set network.iot=interface
uci set network.iot.proto='static'
uci set network.iot.ipaddr='192.168.3.1/24'
uci add_list network.iot.ip6addr='fd00:cafe:3::1/64'
uci set network.iot.device='br-iot'
# DHCPv6/RA 分发公网前缀
uci set dhcp.iot=dhcp
uci set dhcp.iot.interface='iot'
uci set dhcp.iot.ra='server'
uci set dhcp.iot.dhcpv6='server'
uci set dhcp.iot.ra_management='1'
# 防火墙:iot 独立区域,仅 iot→wan,禁止 iot↔lan / iot↔wg
uci add firewall zone; uci set firewall.@zone[-1].name='iot'
uci set firewall.@zone[-1].input='REJECT'; uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].forward='REJECT'; uci add_list firewall.@zone[-1].network='iot'
uci add firewall forwarding; uci set firewall.@forwarding[-1].src='iot'; uci set firewall.@forwarding[-1].dest='wan'
uci commit; /etc/init.d/network restart; /etc/init.d/firewall restart; /etc/init.d/dnsmasq restart
IoT 区域forward=REJECT天然阻止其访问lan/wg,即便某摄像头被攻破也无法横向到 NAS。若 HomeAssistant 在 lan 需控制 iot,再加一条lan→iot的精确端口放行。
9. 纯 v4 环境兜底:VPS 中继(可选)
若客户端常在无 IPv6 的网络,可在双栈 VPS 上做中继:客户端 → VPS(wg0)→ 家(wg1)。VPS 的 wg1 peer 指向 router.example.com:51820(家里),家里 peer 的 endpoint 指向 VPS。VPS 内开启 ip_forward 并在两个 wg 接口间放行转发。这样客户端只需能连到 VPS 的 v4/v6,家里无需公网 v4。
要点(VPS 上):
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1
# wg0(面向客户端)与 wg1(面向家)各自配置 peer,
# AllowedIPs 互指对端内网段,防火墙放行 wg0↔wg1 转发。
10. 排错速查
| 现象 | 排查 |
|---|---|
| wg0 没有 MAC 地址 | 正常现象,不是故障。WireGuard 是 L3 隧道接口,没有以太网帧头,MAC 是 L2 概念只有 eth0/br-lan/wlan0 才有。判断 wg0 状态看 IP 地址和 wg show,不看 MAC(见 §2.7)。 |
| 不确定是否连接成功 | 接口层:ip addr show wg0 有地址 + wg show 能列出 peer。握手层(硬指标):wg show 里 peer 有 latest handshake: 几秒前 且 transfer 计数在涨 = 连接成功;无 latest handshake、rx=0 = 握手失败(查公钥/endpoint/防火墙,见 §2.7.1)。 |
手机报 bad address |
客户端 AllowedIPs 格式错:用了全角逗号 , 或带不可见字符。用半角 , 分隔,或用二维码导入(§3.5)。检查 cat -A client.conf。 |
手机能 ping6 路由器、但 wg show 无握手、tcpdump 抓不到 WG 包 |
客户端配置里残留 ListenPort(必须删),或路由环(Endpoint 网段在 AllowedIPs 内,见 §3.1 坑2/3)。删 ListenPort + 内网测试去掉 Endpoint 网段。 |
| 握手成功但 ping 不通内网 | 客户端 AllowedIPs 是否含目标段;服务端 peer allowed_ips 是否含客户端隧道地址;wg↔lan forwarding 是否存在。 |
| 能 ping IP 但域名不通 | 客户端 DNS 是否指向 10.200.0.1;路由器 dnsmasq 是否监听 wg0(§2.5);.lan 记录是否定义。 |
| 全屋设备突然无法上网/DNS 解析全超时 | dnsmasq 的 interface 字段被设成 wg0,导致只监听 wg0、排除了 lan。 修复:uci delete dhcp.@dnsmasq[0].interface; uci commit dhcp; /etc/init.d/dnsmasq restart(见 §2.5 警告)。dnsmasq 默认监听所有接口,不要设 interface,用 notinterface 排除 wan 即可。 |
| 反向(家→手机)不通 | 服务端 peer allowed_ips 是否含 10.200.0.2/32;lan→wg forwarding 是否存在;手机服务是否监听 0.0.0.0/隧道地址。 |
| 多站点某方向不通 | 对端 allowed_ips 是否含本站 LAN 段;两站 LAN 段是否重叠;persistent_keepalive 是否设了。 |
| DDNS 更新后仍连不上 | dig AAAA 看是否真更新;WG endpoint 会缓存解析,重启隧道 ifdown wg0 && ifup wg0 让它重解析。 |
公网拨入 packets 0(换端口也不涨)、内网却正常 |
光猫拨号模式下光猫挡了入站 IPv6 UDP。进光猫管理界面关 IPv6 防火墙/放行,或光猫改桥接让 OpenWrt 直接拨号拿公网 v6。见 §9 VPS 中继为兜底。 |
| IPv6 拿不到(wan6 up:false) | logread -e odhcp6c 看握手;/lib/netifd/dhcpv6.script 是否报 Command failed: Not found(缺依赖工具,重装 odhcp6c);uci commit network 是否漏了;装协议包后用 network restart 而非 reload(见 §2.6)。 |
| IPv6 异常/时断时续 | ICMPv6 必需类型是否被防火墙误杀;前缀变更后 wg0 的 GUA endpoint 是否过时。 |
| WG 速度慢、跑不满宽带 | 先 top 看 CPU:若 wg- 内核 worker 占满、idle 0% = 硬件加密瓶颈(见 §7)。弱路由器(MT7628N 等)无解,改 split tunnel + 调 MTU 缓解,或挪走 WG/换路由器。 |
常用命令:
wg show # 握手/流量
wg show wg0 latest-handshakes
nft list ruleset | grep 51820 # 端口计数器(packets 涨=包到了)
tcpdump -i any -n 'udp port 51820' # 抓 WG 握手包(区分包到没到)
top -d 2 # 看 CPU 是否被 wg 加密占满(§7)
ip -6 route # v6 路由
logread -e netifd # 接口起不来必看
logread -e odhcp6c # DHCPv6/前缀委派
dig AAAA router.example.com
11. 上线自检 checklist
- [ ]
dig AAAA router.example.com与路由器 WAN GUA 一致 - [ ]
wanINPUT/FORWARD 默认 DROP,仅放行51820/udp - [ ] wg0 接口已起,
wg show有 listen 端口 - [ ]
wg↔lan双向 forwarding 存在 - [ ] dnsmasq 监听 wg0,
.lan域名已定义 - [ ] 每个客户端 peer 都加了 PSK
- [ ] 各 OS 客户端能拨入且
ping nas.lan通 - [ ] 反向:家里能 ping 通手机隧道地址
- [ ] 多站点:两站互 ping 对方 LAN 设备通
- [ ] UPnP 已关;LuCI/SSH 不监听 WAN
- [ ] root 强密码 + SSH key 登录
- [ ] DNSPod 用子账号最小权限,凭证
chmod 600 - [ ] IoT 在独立 VLAN 且
forward=REJECT - [ ] 配置已
sysupgrade -b备份并离线保管
附录 A:客户端配置文件完整示例(手机)
[Interface]
PrivateKey = <手机私钥>
Address = 10.200.0.2/24, fd00:cafe:9::2/64
DNS = 10.200.0.1, fd00:cafe:9::1
MTU = 1420
[Peer]
PublicKey = <服务端 /etc/wireguard/server.pub>
PresharedKey = <psk.txt 内容>
Endpoint = router.example.com:51820
AllowedIPs = 192.168.1.0/24, fd00:cafe:1::/64, 10.200.0.0/24, fd00:cafe:9::/64
PersistentKeepalive = 25
注意:不要写ListenPort(客户端禁忌,见 §3.1 坑1)。AllowedIPs用半角逗号+空格分隔(见 §3.1 坑2)。内网测试(Endpoint=内网IP)时去掉 Endpoint 所在网段避免路由环(见 §3.1 坑3)。
附录 B:Windows RDP 目标机开启步骤
- 设置 → 系统 → 远程桌面 → 启用。
- Windows 防火墙:允许”远程桌面”入站,范围限制为
192.168.1.0/24(内网/VPN)。 - 设强密码账户,或禁用密码改用更安全方式。
- 客户端拨 VPN 后
mstsc /v:192.168.1.20。
附录 C:DNSPod IPv6 DDNS 更新脚本(路由器,参考/核对用)
你的 DDNS 已配好则无需重做,此脚本用于核对逻辑或迁移。用 CAM 子账号的 SecretId/SecretKey。
#!/bin/sh
# /etc/wireguard/ddns_dnspod.sh
set -e
SECRET_ID='your_id'
SECRET_KEY='your_key'
DOMAIN='router.example.com' # 完整主机名
RECORD_TYPE='AAAA'
# 取路由器 WAN 侧第一个非临时 GUA
IP=$(ip -6 addr show pppoe-wan 2>/dev/null | grep -v temporary \
| awk '{print $2}' | cut -d/ -f1 | head -n1)
[ -z "$IP" ] && { echo "no GUA"; exit 1; }
# 调用 DNSPod v3 API(签名较繁琐,推荐用现成的 ddns-scripts)
# OpenWrt 推荐做法(apk,25.x;旧版用 opkg):
apk add ddns-scripts_dnspod
# 在 /etc/config/ddns 配置 dnspod 服务,service_name 选 dnspod
OpenWrt 推荐用官方 ddns-scripts_dnspod 包,在 /etc/config/ddns 里:
config service 'myddns'
option service_name 'dnspod'
option domain 'router.example.com'
option username '<SecretId>'
option password '<SecretKey>'
option ip_source 'network'
option ip_network 'wan6'
option check_interval '5'
option check_unit 'minutes'
option force_interval '60'
option force_unit 'minutes'
option use_ipv6 '1'
/etc/init.d/ddns enable && /etc/init.d/ddns start
logread -e ddns # 查看更新结果
DDNS 更新失败时要能告警(前缀变了但没更新 → VPN endpoint 失效)。可在脚本里加 webhook 通知。
本文链接: OpenWrt + IPv6 DDNS + wiregurad 全 VPN 组网落地手册