Ubuntu 24.04 改 SSH 端口的 socket activation 陷阱

Ubuntu 24.04 的 sshd 由 systemd socket activation 管理,改端口只写 sshd_config 不够;手动建 socket override 会与 generator 冲突导致 socket failed。

#type / debug #status / growing #tech / ops #resource / ssh #platform / linux #platform / server

[!warning] 改端口前先留好后路 重启 ssh.socket 会断开「新建」连接的能力。务必保留一个已建立的 SSH 会话作为救命窗口,或先确认带外通道(控制台连接、Tailscale)可用,再动 socket。

Ubuntu 24.04 改 SSH 端口的 socket activation 陷阱

现象

/etc/ssh/sshd_config.d/ 写了 Port 1688sshd -T 也能看到该端口,但 ss -tlnp 里新端口根本没监听;或者重启 ssh.socket 后直接 failed:

ssh.socket: Failed to create listening socket (0.0.x.x:22): Address already in use
ssh.socket: Failed with result 'resources'.

之后所有新 SSH 连接被立即关闭,只有改动前已建立的会话还活着。

根因

Ubuntu 24.04 的 sshd 走 systemd socket activation,监听端口由 ssh.socket 单元定义,而非 sshd 自己 bind。关键机制:

  1. systemd 有一个 generator,会自动读取 sshd_config 里的 Port 指令,生成 /run/systemd/generator/ssh.socket.d/addresses.conf,里面写好对应的 ListenStream
  2. 如果此时再手动创建 /etc/systemd/system/ssh.socket.d/override.conf 写一遍同样的 ListenStream,两份 drop-in 叠加,每个端口出现两次。
  3. systemd 绑定第二个重复端口时撞到自己 → Address already in use → socket 启动失败 → 新连接全部被拒。

正确做法

只在 sshd_config 里声明端口,让 generator 自动生成 socket 配置,不要手动建 socket override

# /etc/ssh/sshd_config.d/99-port.conf
Port 22
Port 1688
sudo sshd -t                 # 语法检查
sudo systemctl daemon-reload # 触发 generator 重新生成 addresses.conf
sudo systemctl start ssh.socket   # socket 当前是 dead 时用 start,不是 restart
sudo ss -tlnp | grep -E ':22|:1688'

若之前误建过 override,先删除再 daemon-reload:

sudo rm /etc/systemd/system/ssh.socket.d/override.conf
sudo rmdir /etc/systemd/system/ssh.socket.d 2>/dev/null
sudo systemctl daemon-reload
sudo systemctl start ssh.socket

关键认知:已建立会话不受影响

SSH 会话一旦建立,实际的 socket 文件描述符由内核维护,sshd 进程只负责认证和分配 shell。因此 ssh.socket 重启或 failed 时:

  • 改动前已建立的会话继续可用(这是救命窗口);
  • 但任何新建连接都会失败(因为没有监听 socket)。

利用这一点:在活动会话里修复配置 → daemon-reload → start ssh.socket(dead 状态启动不会抢占已建立连接)→ 验证新端口监听 → 再开新窗口测试。

回归验证

sudo systemctl status ssh.socket --no-pager | head -12   # 应为 active (listening)
sudo ss -tlnp | grep -E ':22|:1688'                       # 每个端口只出现一次

确认 Listen: 列表里每个端口只出现一次(无重复),再从新窗口 ssh -p 1688 验证可连。

创建于 2026/7/21 更新于 2026/7/21