本文以 Ubuntu Server 24.04 为例,完成普通管理员、公钥认证、SSH 端口迁移和基础软件维护。操作涉及 Windows 管理端、云网络控制台和服务器终端。修改 SSH 时保留控制台或现有会话,确认新连接可用后再关闭旧入口。
适用范围、风险与变量
适用于 Ubuntu Server 24.04。开始前准备云控制台或可用的初始 SSH 会话,并预留一个新的 PowerShell 窗口测试连接。示例变量按实际环境填写。
| 变量 | 含义 | 操作位置 |
|---|---|---|
ADMIN_USER |
普通管理用户 | 服务器 |
SERVER_ADDR |
服务器公网地址或域名 | PowerShell |
OLD_SSH_PORT / NEW_SSH_PORT |
迁移前后 SSH 端口 | 控制台、服务器、PowerShell |
KEY_FILE |
Windows 私钥文件名 | PowerShell |
PowerShell 先定义变量:
$AdminUser = '<管理员用户>' |
建立独立密钥和普通管理用户
在 Windows PowerShell 创建一套服务器专用密钥。公钥文件默认在私钥路径后追加 .pub;私钥只保留在管理端。
ssh-keygen -t ed25519 -a 100 -f $KeyFile -C '<用途说明>' |
在保留的初始服务器会话中创建用户。adduser 会交互设置服务器本地密码;不要记录或公开该密码。将 PowerShell 中读取的单行公钥粘贴到 heredoc 内。
ADMIN_USER='<管理员用户>' |
确认账号、sudo 组和文件权限无误后,保持旧会话打开,转到新的 PowerShell 窗口测试登录。
在第二个 PowerShell 窗口验证公钥和 sudo:
ssh -p $OldSshPort -i $KeyFile -o IdentitiesOnly=yes "$AdminUser@$ServerAddr" |
登录后执行:
id |
预期id显示新用户,sudo whoami输出root。还可以用另一把未授权密钥确认访问会被拒绝:
ssh -p $OldSshPort -i "$HOME\.ssh\<其他私钥文件>" -o IdentitiesOnly=yes -o BatchMode=yes -o PreferredAuthentications=publickey "$AdminUser@$ServerAddr" |
负向测试仅尝试公钥认证,不应输入账号密码补救。先确认目标可达、主机指纹已核验,以及指定测试密钥能够被加载;带口令的测试密钥需要提前在受控的密钥代理中解锁。预期是服务器拒绝这把未授权公钥,而不是网络超时、主机验证失败或密钥无法解锁。
若登录失败,在旧会话或控制台检查用户名、公钥是否完整,以及.ssh和authorized_keys的属主与权限。修复配置后重新测试,不要先删除唯一可用的授权。
平滑迁移 SSH 端口
端口迁移遵循:新增网络规则 → 双端口监听 → 第二会话登录 → 单端口监听 → 第三会话登录 → 移除旧网络规则。非默认端口只减少常见扫描噪声,核心控制仍是密钥、私钥口令、禁止密码/root 登录和最小 sudo。
先在服务器识别实际监听单元。Ubuntu 24.04 可能使用 ssh.socket,不能假定只改 sshd_config 就会改变监听:
systemctl is-enabled ssh.socket ssh.service |
然后在云网络控制台新增 TCP NEW_SSH_PORT入站规则,暂时保留OLD_SSH_PORT。保存规则后还要检查服务器监听,并从新的 PowerShell 窗口实际登录。
在服务器写双端口 socket drop-in:
OLD_SSH_PORT='<旧SSH端口>' |
空的 ListenStream= 重置列表;随后两行明确保留旧端口并新增新端口。daemon-reload、cat/show/restart/status 的退出状态用于发现加载问题,ss 才证明监听层。
在第二个新 PowerShell 窗口验证新端口和 sudo:
ssh -p $NewSshPort -i $KeyFile -o IdentitiesOnly=yes "$AdminUser@$ServerAddr" |
成功后先让服务器只监听新端口:
sudo tee /etc/systemd/system/ssh.socket.d/10-ports.conf >/dev/null <<EOF_SOCKET |
在第三个新 PowerShell 窗口再次登录新端口:
ssh -p $NewSshPort -i $KeyFile -o IdentitiesOnly=yes "$AdminUser@$ServerAddr" |
第三个会话成功,才在云网络控制台删除旧端口放行。最后的新连接到旧端口应失败:
ssh -p $OldSshPort -i $KeyFile -o IdentitiesOnly=yes "$AdminUser@$ServerAddr" |
若旧端口测试表现为超时,应结合网络规则和服务器ss输出确认是否已经关闭。
端口迁移回退
迁移失败时,先在网络控制台确认或恢复旧端口放行,再在保留会话恢复双端口:
sudo tee /etc/systemd/system/ssh.socket.d/10-ports.conf >/dev/null <<EOF_SOCKET |
随后用独立新终端测试旧端口。没有有效旧会话或控制台时,不应删除唯一入口。
仅允许公钥认证
确认新端口公钥登录正常后再收紧认证策略,并继续保留一个已登录会话。先查看现有配置;Ubuntu 的 OpenSSH 配置可能受多个文件影响,最终以sshd -T输出为准。
( |
上述括号创建子 Shell;备份、写入或语法检查失败会终止本块,不会继续 reload,也不会退出保留的交互会话。sshd -T 输出还需人工核对;如有 Match,使用 sudo sshd -T -C 'user=root,addr=<客户端地址>,host=<客户端主机名>' 等对应连接条件检查有效策略(先替换占位符),不要只看全局值。
用新的 PowerShell 窗口做正向验证:
ssh -p $NewSshPort -i $KeyFile -o IdentitiesOnly=yes "$AdminUser@$ServerAddr" |
在新的 PowerShell 窗口分别做密码认证和 root 远程登录的负向测试:
ssh -p $NewSshPort -o PubkeyAuthentication=no -o PreferredAuthentications=password -o NumberOfPasswordPrompts=1 "$AdminUser@$ServerAddr" |
root 测试失败也可能因为没有提供可用密钥,不能单凭失败证明禁止 root。应结合对应连接条件下的 permitrootlogin no、认证策略输出及服务端日志判断,且普通管理员的新会话必须仍能成功。
回退前核对本次备份目录及原 snippet 状态:原来存在则恢复原文件,原来不存在才删除本次新增文件。主配置未被本步骤修改,不应无条件覆盖回去:
( |
再以新终端复验,最后才关闭回退会话。
软件索引、工具、升级与重启
升级前确认 SSH 仍可从新窗口登录,并检查磁盘、内存和失败服务:
df -h / |
apt update 会刷新本地包索引,是状态变更但不会升级已安装包;apt install 安装指定包;apt upgrade 升级已安装包。模拟依赖动作仍需要可用索引:
sudo apt update |
确认模拟结果和维护窗口后执行:
sudo apt install git curl ca-certificates docker.io rsync |
Compose 是否需要取决于业务和当前软件源,不应假定所有主机都有相同 Compose 包。检查重启标记:
test -e /var/run/reboot-required && cat /var/run/reboot-required || true |
如果核心库或内核更新要求重启,选择维护时段重启,随后重新建立 SSH 连接并检查:
uname -r |
degraded 是诊断信号,要结合失败单元判断;即使没有重启标记,也应复验关键服务和管理入口。
常见问题与最终验收
| 现象 | 先检查什么 | 不能据此断定什么 |
|---|---|---|
| 新端口超时 | 网络规则、ss、管理端地址 |
不能只凭超时认定是安全组问题 |
| 新用户被拒绝 | 公钥、权限、用户名、日志 | 本地文件存在不等于登录成功 |
sshd -t 成功 |
再看 sshd -T |
语法成功不等于策略生效 |
systemctl 非零 |
systemctl --failed |
不自动等于系统不能维护 |
完成后确认:普通管理员可以通过新端口和公钥登录并使用 sudo;旧端口已经关闭;密码与 root 远程登录被拒绝;软件更新和服务状态无异常。
Ubuntu 镜像和云平台的默认配置可能不同。修改前先查看当前 SSH unit 和生效配置,并始终保留控制台或已有会话。