Windows 上 OpenVPN:自动启动隧道并保留路由
Windows 服务可以在任何人登录之前把隧道建起来,而推送的路由只在连接期间保留站点前缀。
这里有两个需求纠缠在一起:隧道应当在任何人登录之前就建立起来,而发往第二个站点的流量应当跟随它。这是两个独立的问题,各有各的机制。服务启动决定前者,路由生命周期决定后者。解决其中一个,另一个仍原封不动。
第一步:把配置文件放到服务查找的位置
Windows 服务从固定目录读取配置文件,GUI 也从同一处读取,因此导入时能用的配置文件在开机时仍可能不可见。把 .ovpn 文件放进安装目录下的 config 目录,它通常位于 Program Files 下。留在用户 Downloads 文件夹里的配置文件根本不在服务的查找范围内。
较旧的指南指向 config-auto 文件夹,2.5 时代的部分构建遵循这一做法,后来的版本则不再如此。这就是为什么升级会把原本可用的自动启动变成悄无声息,而日志里关于凭据毫无记载。在移动任何文件之前,先确认已安装的构建究竟读取哪个目录。
一台机器上有多个配置文件时,通过 dev-node 给每个配置一个有名字的适配器。否则它们会争用同一个接口,第二个会以看起来像凭据问题的方式失败。
第二步:启动服务,而不是托盘图标
OpenVPN服务设为 Automatic 后,无需登录即可在开机时启动。这才是机制所在,托盘图标并不属于它。当连接归服务所有时,GUI 可能不显示图标,也不显示状态,这是预期现象,而不是故障。
其后果是,断开连接意味着停止服务,而不是点击 Disconnect。把这一点告诉负责这台机器的人,否则第一次支持电话会是关于图标不见了。
确认服务账户能读取配置文件和密钥材料。开机时的权限问题在日志里看起来正是身份验证失败。
第三步:把路由绑定到隧道上
持久条目在这里是错误工具。用 -P 添加路由会让它在重启后依然存在,更糟的是,在隧道关闭后也依然存在。VPN 断开时,前缀仍指向一个已不存在的网关,因此在有人删除该条目之前,主机无法到达那个目的地。
三种替代方案行为正确。由服务器推送路由,连接时添加,断开时移除。把它加进读取 route_vpn_gateway 的 route-up 脚本,下一跳就来自协商好的隧道。或者把 Add-VpnConnectionRoute 与 Windows 原生 VPN 配置文件一起使用,它把前缀绑定到该连接。
当服务器提供的内容超出本站需要时,route-nopull 会拒绝推送的路由,让路由表完全保持本地。这适合共享配置文件,其用户不应收到企业默认路由。
第四步:熬过冷启动
在网络栈存在之前启动服务,只会得到一次失败尝试,而且不会重试。把它设为 Automatic (Delayed Start),或添加对网络服务的依赖,就能消除这场竞争。然后重做开机测试,确认不再需要第二次尝试。
路由和适配器的更改需要管理员权限。按用户设置的开机快捷方式没有这些权限,所以从提权 shell 里能用的脚本,在登录时可能悄无声息地什么也没做。把它计划为具有最高权限的任务,或者让服务来承担这次更改。然后以真正会登录的用户身份进行测试。
测试你实际部署的顺序,而不是你手工能触发的那个。冷启动是唯一能检验顺序的测试。
第五步:不打开 GUI 验证
重启并登录之后,不打开 GUI 检查三件事。适配器应当持有地址,路由表应当把站点前缀显示出来,下一跳是隧道的网关,并且对远端地址的 ping 应当有回应。每项检查都对应上面步骤中的一个不同机制。
当适配器始终不出现时,可疑的是驱动程序而不是配置文件。这两种故障在日志里毫不相像,而且只有其中一种会对重装软件作出反应。