你在安装时把 SSH 绑定到隧道地址,一切正常;可下次重启后,除非有人手动重启服务,否则谁也登录不了。问题不在凭据。守护进程向内核请求了一个当时还不存在的地址,绑定失败,报错在启动日志里一闪而过。看起来像认证问题,其实是启动顺序问题。

绑定报错到底说了什么

监听套接字必须建立在当下已经存在的地址上。VPN 接口稍后才出现,而只配置为绑定隧道地址的守护进程就无处可依。配置本身在语法上仍然有效,只是环境还没准备好。自手动启动以来一直在运行的服务从不会走启动流程,所以故障只在下次重启时出现。把绑定失败的时间戳与地址分配的时间戳对照一下,顺序就显而易见了。

配置有效性和运行时就绪是两回事。两者都要测,因为其中一个会一声不响地失败。

哪个进程占着端口

创建监听端的未必总是守护进程本身。套接字激活会把这项职责交给某个 unit,这时重启守护进程毫无作用。

ss -ltnp 'sport = :22'
systemctl cat ssh.socket

套接字列表显示哪个进程、在哪个地址上占着端口,而 unit 转储显示是否存在套接字 unit。启用激活时,地址属于套接字 unit,守护进程配置文件不再是权威。要读启动日志找真正的绑定报错,而不是从现象倒推。缺少套接字 unit 只说明用的是经典做法:守护进程直接绑定。

把就绪写成显式依赖,而不是睡眠

固定延时是一种猜测,它把快机器和慢网络一视同仁。应当把依赖表达出来:等地址出现,再启动。

ip -4 addr show dev tun0
systemctl edit ssh.service

加一条 ExecStartPre 命令,循环到地址出现为止;或者把 unit 排到拥有该接口的特定网络目标之后。两种做法都把依赖记录在下一个管理员读得到的地方。循环必须有超时,否则 VPN 失败时会留下一个卡住的 unit,而不是报告故障。然后确认守护进程绑定了隧道地址,同时普通接口仍受你的过滤规则管辖。

测试干净启动和重新连接

一切在线之后手动重启,证明不了任何启动顺序。把隧道配置为自动拉起,重启整台机器,观察监听端是否无需干预就出现。

systemctl status ssh.service
ss -ltnp 'sport = :22'

然后断开并重新建立隧道,因为重连可能改变地址,而硬编码的绑定不会跟着走。测试期间要保留带外恢复通道,免得一次糟糕的顺序改动把你锁在主机之外。

成功的标准是监听端按文档写明的依赖出现,而不是某个记得去重启的人。

相关文章