为什么停止接口时 wg-quick 会重写 wg0.conf
SaveConfig 是关机时的保存,而不是后台同步。在隧道运行时编辑文件,重启可能把旧状态写回去。
你向 /etc/wireguard/wg0.conf 添加了一个 peer,运行 systemctl restart wg-quick@wg0,再看时这个 peer 已经从文件里消失了。并没有什么东西损坏了它。重启是先停止再启动,而停止这一步可能把当前运行状态写回你刚刚编辑过的文件。负责这件事的设置就在你编辑的那个文件里,这正是第一次遇到时这个循环如此令人困惑的原因。
两种状态、一个文件,以及关机时的一次保存
WireGuard 的运行状态与 wg-quick 配置文件相关但并不相同。文件是输入:wg-quick 读取它,创建接口,设置地址和路由,并配置 peer。内核设备是活的对象,用 wg 做的底层改动永远不会自己写回去。
除了一个方向。当接口部分出现 SaveConfig = true 时,wg-quick 会在关闭接口的过程中把当前配置保存到文件。wg-quick 手册警告的正是这一点:接口运行时对文件所做的修改,可能在接口被移除时被覆盖。这是关机时的保存,而不是后台定时器,所以只有某个东西停止接口时它才会触发。
| Action | What it writes | When it surprises you |
|---|---|---|
wg set on a live interface | Kernel state only | After reboot, when the file was never updated |
wg-quick down with SaveConfig | Live state into the file | Right after you edited the file |
wg syncconf | Kernel state only | Never; it does not touch the file |
wg-quick up | Kernel state from the file | If the file is stale, you get the old tunnel |
把这张表当作关于顺序的警告来读。这个领域里的每一次意外丢失,都来自发生在保存之前而不是之后的编辑。
先停止,再编辑,最后启动
如果文件是你的真相来源,那就用结构而不是靠运气让文件成为权威。关闭接口,确认它已经消失,然后编辑,再把它启动起来。规则很简单:只要保存还可能运行,就不存在任何编辑。
sudo cp -a /etc/wireguard/wg0.conf /root/wg0.conf.$(date +%F-%H%M)
sudo wg-quick down wg0
ls /sys/class/net/wg0 2>/dev/null || echo "interface is gone"
sudoedit /etc/wireguard/wg0.conf
sudo wg-quick up wg0
备份那一行不是形式主义。如果隧道是你到达这台机器的方式,关闭这一步可能结束你的会话,而磁盘上的副本加上控制台或带外通道才是唯一有效的回滚。在信任第二行之前先检查它:脚本里过时的接口名静默失败,正是人们编辑一个仍然活着的文件的方式。
在正常关闭之前设置 SaveConfig = false 是另一种被接受的做法,而且必须在 wg-quick 真正读取的文件里做。它能阻止那一次自动保存。它不会让单独的 NetworkManager 配置、路由器导出或容器入口重新加载你的修改,因为那些管理器根本不读这个文件。
不撕裂接口地应用 peer 变更
并非每次编辑都需要中断。把文件转换成配置并同步,就可以把 peer 级别的变更应用到正在运行的接口上,这完全绕过了关闭步骤,因此也绕过了保存:
sudo wg syncconf wg0 <(sudo wg-quick strip wg0)
sudo wg show wg0 peers
sudo wg show wg0 latest-handshakes
strip 这一步很重要。它会打印出去掉仅属于 wg-quick 的键之后的文件,这样地址、DNS 和路由指令就不会被送进一个不理解它们的工具。随后同步会把 peer 和密钥应用到活设备上而不重建接口,因此现有会话和路由得以保留。
对边界要精确。同步 peer 不会改变接口地址、wg-quick 添加的路由或解析器配置,因为这些都不属于 WireGuard 设备。向 AllowedIPs 添加子网并指望内核为它路由,是典型的误读;路由必须在启动时由 wg-quick 添加,或者由你添加。
编辑任何东西之前先确认接口归谁所有
在由配置系统管理的桌面或服务器上,文件可能是输出而不是输入。一个 NetworkManager 连接、路由器生成的配置或容器启动脚本都可能拥有同一个接口名,在这种情况下,无懈可击的 wg-quick 流程仍然在编辑错误的产物。
systemctl status wg-quick@wg0 --no-pager
nmcli connection show | grep -i wireguard
sudo wg showconf wg0 | head -n 5
第三条命令会以与文件相同的格式打印当前配置,包括私钥,这对比较很有用,放在工单里却很危险。粘贴之前先涂掉;支持线程里的私钥是永久泄露,而不是笔误。
如果服务单元未激活但接口存在,那就是别的东西创建了它,文件并不权威。仅凭这一个观察就能省下一小时去编辑一个没人读的文件。
验证下一次重启,然后保留回滚
真正能证明修复的测试是第二次重启,因为第一次失败的就是这个序列。确认 peer 能挺过去,并且当前配置仍然与磁盘上的一致:
sudo systemctl restart wg-quick@wg0
sudo wg show wg0 latest-handshakes
sudo grep -c '^\[Peer\]' /etc/wireguard/wg0.conf
把重启跑两次。一次干净通过可能是运气:第一次重启可能消耗掉一个尚未保存的运行期改动,所以第二次才会告诉你,文件与运行状态在第一次结束时是一致的。
从流程开始就保留备份,直到你完成双重重启,然后删除它或把它移出配置目录。真正的文件旁边多出一个 wg0.conf.bak 对 wg-quick 无害,却会让下一个人困惑,他最终会编辑错的那个。