大多数指南把这一选择说得无关紧要:要么让 NetworkManager 把隧道拉起来,要么启用一个 systemd 实例,就这样。两条路径的差别在于一件决定无头机器结果的事,而它与哪个工具更新毫无关系。NetworkManager 通过会话解锁机密;systemd 实例没有会话可解锁。请选择其机密处理方式与你眼前这台机器相符的那条路径。

其余一切,从路由安装到重连行为,都源自这个最初的决定。

没人提到的差别在于钥匙环

当 NetworkManager 拥有某个 VPN 配置文件时,密码可以存放在登录钥匙环里,用户登录时钥匙环会被解锁。这在笔记本上运行良好:人在场,钥匙环打开,隧道升起。在无人值守启动的服务器上,没有人去解锁任何东西,于是配置就等着一个永远不会到来的机密。连接看起来已经配置好,却永远不会激活。

systemd 实例通过从磁盘读取凭据文件来避开这个问题,于是文件本身成了你要保护的东西。chmod 400 加上由 root 拥有是最低要求,并且该文件应放在你无法控制的备份和镜像模板之外。

把 VPN 挂到连接上并不等于开机保证

在 nm-connection-editor 中,选择有线或无线连接而不是 VPN,打开 General 标签页,勾选自动连接到 VPN 的选项并为配置文件命名。随后,当主连接进入已连接状态时,NetworkManager 会把该 VPN 作为辅助连接激活。这是一种依赖关系,而不是防火墙规则。在隧道升起前的几秒里,数据包仍可能外泄;而保存的机密若无法解锁,机器就会在没有隧道的情况下保持联网。

如果要求是隧道不通就什么都不许出去,那就把这一点说清楚并构建一个断路开关,因为这项设置本身并不提供。还要测试挂起与恢复,因为辅助连接在返回时会被重新评估。

systemd 实例需要匹配的文件名

把配置文件放到软件包预期的客户端目录中,例如 /etc/openvpn/client/office.conf,并在其中用 auth-user-pass office.cred 引用凭据文件。实例名就是去掉后缀的文件名,因此 openvpn-client@office 读取的是 office.conf。用 sudo systemctl enable --now openvpn-client@office 启用它,并用 systemctl cat openvpn-client@office 确认映射关系,而不是相信博客里的示例。

配置文件内部的路径是相对于单元的工作目录解析的,而不是相对于配置文件本身,因此相对的 ca 或 auth-user-pass 行可能在你手动测试时正常、开机时却失败。凡单元必须找到的东西,都请使用绝对路径。然后在真正开机之后读取 journalctl -u openvpn-client@office -b;一个报告已激活却没有隧道的单元,通常会在该日志里指出某个缺失的文件。

较旧的软件包提供的是另一个模板名,因此用 systemctl list-unit-files 'openvpn*' 就能确定这台主机上存在的是哪一个。

重连行为是另一项决定

带有 ping-restart 的配置会在断开后重建隧道,而带有重启指令的单元则在服务层面做类似的事。这些是你选择的策略,而不是你继承的默认值。如果连接只应按需建立,就主动移除重启行为并写下原因。如果单元在网络可用之前就启动,它就需要重试策略,因为开机时一次失败不会自行重复。

停止也同样字面化:sudo systemctl disable --now openvpn-client@office 会停止正在运行的实例并移除开机链接。仅仅禁用它会让隧道一直运行到下次重启,这会让那些禁用之后看着接口仍然在线的人感到意外。

重启之后,按顺序检查四件事

重启服务检验的是服务;重启机器检验的是启动路径。重启之后,先确认单元已经启动,再确认存在通往远端子网的路由,然后确认机器对互联网呈现哪个地址,最后确认域名能通过隧道解析。出问题时这四项检查正是按这个顺序失败的,因此第一个失败项才是有用的。

单元处于激活状态却没有路由,通常意味着配置已连接但服务器没有推送任何路由,或者路由被装在后来消失的接口上。路由存在却无法正常解析域名,指向的是 DNS 配置而不是隧道本身。

提前决定隧道无法建立时该怎么办。回退到普通联网是一种策略,应当写下来,而不是留给某个最先启动的管理器。

相关文章