1. 修改 SSH 端口到底解决什么问题——动机评估与适用场景
聊到 Ubuntu 系统改 SSH 端口这件事,我得先给各位泼一盆冷水:如果你以为改了端口就能一劳永逸地解决服务器安全问题,那你多半要失望。但它依然是一件值得做的事,前提是你搞清楚它到底解决什么、不解决什么。
SSH 服务默认监听 22 端口,这几乎是所有运维人员、脚本扫描器和恶意爬虫的“共识”。互联网上每天有大量的自动化扫描程序在全网扫 IPv4 地址段,遇到 22 端口开放就会尝试常见的用户名密码组合进行暴力破解。我托管过一台公网 Ubuntu 服务器,装好系统不到 24 小时,/var/log/auth.log里就能看到源源不断的 Failed password 记录,来源 IP 遍布全球。这不是个例,几乎每台公网服务器都会面临同样的处境。把 SSH 从 22 端口改到高位端口(比如 22222 或 50022),这些无差别扫描的大部分流量就直接扫不到了,因为它们的扫描清单里默认只写了 22 端口。
但要注意,这属于“降低暴露面”而非“绝对安全”。一个专注针对你的攻击者,用nmap -p 1-65535全端口扫描照样能找到你的 SSH 服务。所以改端口通常配合密钥登录、禁用密码登录、Fail2ban 等方案一起使用,形成纵深防御。这篇文章聚焦在“怎么把端口改好、改稳”,其他安全加固手段我们会在涉及的地方顺带提一句,但不展开。
适用场景很清晰:你是 Ubuntu 服务器管理员,想把 SSH 从默认的 22 端口迁到自定义端口;或者你所在的内网环境有端口冲突,本机或者其他服务占用了 22 端口;又或者你的安全审计要求明确指出“不得使用默认 SSH 端口”。这几种情况都适合按照本文的流程操作。
需要特别提醒的是:如果你是通过远程 SSH 连接服务器来执行这次修改,请一定先确保自己理解了每一步的含义,而且最好准备一个备用连接方案,比如云服务商控制台提供的 VNC、管理终端,或者干脆是同一网络里的另一台跳板机。因为一旦配置写错、防火墙没放行、sshd 服务没重启成功,你可能会把自己锁在门外,而这时云控制台的救援通道就是你唯一的救命稻草。我在后面的故障处理章节会专门展开这个场景。
2. 动手前的环境检查——配置备份、端口冲突与防火墙现状排查
很多人改端口失败、把服务搞挂,问题不是出在改端口这一步,而是出在准备工作没做扎实。我见过太多反面教材:直接编辑sshd_config把Port 22改成Port 22333,然后迫不及待地重启 sshd,结果一重启就发现连接直接断开,怎么也连不回去了。原因无非是以下几种:新端口被其他进程占用、防火墙没放行新端口、SELinux 或 AppArmor 策略拦截、sshd 配置语法有误。这些坑,全部可以在动手之前用几分钟排查干净。
2.1 确认当前 SSH 服务状态与现有配置
先登录目标 Ubuntu 服务器,执行:
sudo systemctl status ssh正常情况下你会看到 ssh.service 处于 active (running) 状态。如果输出显示的是ssh.socket,说明你用的可能是 socket 激活模式(新版 systemd 的特性),这种模式下手动改sshd_config的端口不一定生效,还要处理 socket 单元的配置,后面我会专门说明。确认服务正常后,再看看当前实际监听的端口:
sudo ss -tlnp | grep sshd一般会输出类似:
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3)) LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1234,fd=4))注意看 IPv4 和 IPv6 两条监听记录都有,说明 sshd 在双栈环境正常工作。接下来看一眼现在的配置文件全貌:
sudo grep -n "^" /etc/ssh/sshd_config | grep -v "^#" | grep -v "^$"这样能看到所有未被注释的行,快速了解当前生效的配置项。特别留意有没有多个Port指令——sshd_config 的规则是,如果有多个 Port 行,sshd 会同时监听所有列出的端口,这其实是一个可用于平滑迁移的技巧,后面细说。
2.2 备份:这个动作不能跳过
在改任何系统级配置文件之前,养成备份习惯是基本功。改 SSH 配置尤其如此,因为你可能因为一个多余的空格、一个写错的指令名而把整个服务搞挂。备份命令很简单:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d%H%M%S)这样生成带时间戳的备份文件,出问题可以精确回滚到改动前的那一刻。顺便建议把原来的 sshd 二进制和服务状态也做记录:
sudo sshd -T | head -20sshd -T是 sshd 的“测试模式”,只输出根据当前配置计算出的生效参数,不实际启动服务。改动配置后可以用它来快速对比前后差异。
2.3 检查新端口是否被占用
端口冲突是改端口失败的头号原因。你选一个新端口,比如 22222,得先确认没有被其他服务占用:
sudo ss -tlnp | grep -E "22222|:22222"没有任何输出说明端口是空闲的。如果你想更细致一点,直接用ss -tln | awk '{print $4}'列出所有监听端口,目测一下自己想用的端口不在其中。
提示:端口范围要注意,1-1024 是特权端口,1024-49151 是注册端口,49152-65535 是动态/私有端口。sshd 以 root 启动,理论上可以监听任何端口,但为了避免和其他服务冲突,建议选 1024 以上的高位端口,且避开常见服务端口和临时端口范围。另外,不要选别人常用的替代端口,比如 2222 是很多教程里推荐的“标准替代”,实际上也成了扫描器的重点关注对象——我见过不少扫描流量专门扫 2222。挑一个不那么“热门”的高位端口,比如 32122、44555 这类,效果更好。
2.4 检查防火墙现状
Ubuntu 系统最常见的防火墙是 ufw(Uncomplicated Firewall),也有不少人直接操作 iptables/nftables。先看看当前状态:
sudo ufw status verbose如果输出显示Status: inactive,说明 ufw 根本没启用,任何端口都对外可达,那防火墙不用管。如果显示Status: active,注意看当前放行的规则里有没有 22/tcp。通常云服务器镜像默认会放行 22,但你自己改端口后必须手动添加新规则——这是最容易遗漏的一步。
如果你用的不是 ufw 而是云平台安全组(阿里云安全组、腾讯云防火墙、AWS Security Group 等),对应的放行规则要先去云控制台改,服务器内部的防火墙只是第二层。很多人在云服务器上改了端口却连不上,就是漏了安全组的入方向规则。这一步现在记在心里,后面操作完一起处理。
如果你用 iptables 直接管理规则,检查一下当前规则:
sudo iptables -L -n | grep 22或者用 nftables:
sudo nft list ruleset | grep 22搞清楚了现状,我们才进入真正改配置的环节。
3. sshd_config 修改实操——命令行修改、语法校验与服务重启
准备工作做完了,开始动配置。这部分看起来很简单——改一行字的事——但细节决定成败,几个原则必须先在脑子里过一遍。
3.1 直接编辑 vs 追加覆盖
我的习惯是直接用编辑器打开主配置文件修改:
sudo vim /etc/ssh/sshd_config找到这一行:
#Port 22去掉注释并改成你自己的端口:
Port 32122如果你不改Port 22那行,而是想在文件末尾追加一行Port 32122,会出现什么情况?sshd_config 的规则是,配置文件中同一个指令出现多次时,取第一个出现的值(不是最后一个)。前半句是几乎所有教程都告诉你的,但很多人忽略了一个关键细节:如果你保留了Port 22那行带#注释,然后在末尾加一行Port 32122,那没问题,生效的只有32122。但如果Port 22是没有注释的生效指令,末尾再追加Port 32122,结果是 sshd同时监听 22 和 32122两个端口——因为Port指令比较特殊,它不像PermitRootLogin那样“第一个生效,后续忽略”,而是“每个 Port 值都会被加入监听列表”。我之前迁移端口就利用过这个特性:先在末尾追加新端口的Port行,重启 sshd,确认新端口能连接,再把老端口那行注释掉,再重启一次,整个过程平滑无感。
3.2 不仅仅是端口——连接数限制和监听地址
除了Port,我建议你顺手检查另外几个配置项,这些不直接决定端口对不对,但影响改完之后的稳定性和安全性:
ListenAddress 0.0.0.0:默认监听所有网卡的 IPv4 地址。如果你只想让内网某个 IP 连 SSH,可以写成ListenAddress 192.168.1.10。PermitRootLogin:强烈建议no,然后用普通用户登录再sudo su -提权。这个和改端口是黄金搭档。PasswordAuthentication:能改成no就改成no,然后只允许密钥登录。大部分针对 22 端口的暴力破解都依赖密码认证,关了这扇门配合改了端口,攻击面小很多。MaxAuthTries:默认 6,可以调小到 3。这个决定了单条连接里最多允许几次认证失败。ClientAliveInterval和ClientAliveCountMax:设置空闲超时,防止一些僵尸连接长期占用。
这些配置一句话带过,但每一项展开都是安全课题。这篇的重点还是端口,其他配置我建议你按需逐项搜索研究。
3.3 语法校验:重启前的最后一道闸门
改完配置别急着重启,先让 sshd 自己检查一下语法:
sudo sshd -t没有任何输出,说明配置语法正确。如果输出了类似:
/etc/ssh/sshd_config line 5: Bad port number.那就是端口值写错了,检查是不是敲了非数字字符或者超出 1-65535 范围。语法校验没报错,再看一眼计算出的生效配置:
sudo sshd -T | grep -E "^port|^listenaddress"确认port 32122和listenaddress 0.0.0.0符合预期。这一步能直观看到 sshd 实际会用到哪些值,比直接猜靠谱得多。
3.4 重启服务并保持连接不中断
远程操作最关键的一步来了。重启 sshd 时千万不要使用下面的命令:
sudo systemctl restart ssh # 危险!为什么不建议?因为如果配置有误或者 SSH 服务重启后监听失败,systemd 可能会杀掉当前连接对应的 sshd 进程,你的 SSH 会话会直接断掉。更稳妥的姿势是使用reload:
sudo systemctl reload sshreload 会加载新配置,但不中断现有连接——严格来说,你当前这个会话所用的 sshd 进程是旧的,它继续监听旧端口直到会话结束;新连接才会走新配置。不过 reload 也不是完全没有风险:如果配置错误,sshd 会拒绝重载并保持旧配置运行,所以你的现有连接安全。这是远程操作 SSH 时最推荐的优雅方式。
注意:2022 年以后的 Ubuntu 版本(22.04 及更新),
ssh.service和ssh.socket的体系发生了变化。如果你执行systemctl status ssh发现输出里出现Triggered by: ssh.socket,那么你还需要处理 socket 单元。此时检查一下sudo systemctl status ssh.socket,确认它监听的端口是否还是 22。如果确实以 socket 方式激活,重启 ssh 的正确方式是:
sudo systemctl restart ssh.socket
这个细节是很多 Ubuntu 用户改完端口发现“没生效”的隐藏原因,后面故障排查还会再提。
reload 或者 restart 执行后,立刻在新终端窗口测试:
ssh -p 32122 user@your-server-ip如果新连接能建立,恭喜,核心操作完成了。如果新端口连不上,别慌,下一步按流程排查。
3.5 平滑迁移到新端口
如果你追求零中断,可以按这个顺序操作:
- 在
sshd_config追加一行Port 32122,保留原来的Port 22。 sudo systemctl reload ssh,此时 22 和 32122 同时可连。- 新窗口测试
ssh -p 32122能正常连上。 - 确认连接稳定后,注释掉
Port 22,再次 reload。 - 测试旧端口应该无法连接,新端口正常。
这个流程特别适合生产环境。每一步都有验证,每一步都可以回退,不存在“一刀切”把自己关在门外的尴尬。
4. 防火墙规则更新——ufw 和 iptables 两套方案,别漏了云安全组
配置改完了,服务也重载了,如果新端口还是连不上,十有八九是防火墙在拦。这一节把防火墙的几种情况全部过一遍。
4.1 ufw:最常见的 Ubuntu 防火墙
如果你的 ufw 是 active 状态,执行:
sudo ufw allow 32122/tcp如果之前只允许了 22,这个新规则加上后应该能直接放行新端口。可以用以下命令确认:
sudo ufw status numbered输出里应该能看到:
[ 1] 22/tcp ALLOW IN Anywhere [ 2] 32122/tcp ALLOW IN Anywhere看到新的规则在列,说明放行成功。
很多人问“要不要把 22 的规则也删掉”。我的建议是:在确认新端口稳定运行一段时间之前,先别急着删。你可以改端口后保留 22 的放行规则,但 SSH 服务本身已经不再监听 22,规则留着也不会有流量进来。等你在新端口上跑了几天,确定没有异常,再删掉旧规则不迟:
sudo ufw delete allow 22/tcp4.2 iptables/nftables
iptables 场景,在默认 INPUT 链里加一条:
sudo iptables -I INPUT -p tcp --dport 32122 -j ACCEPT这条规则插到第一条,让后面的规则在评估时直接匹配放行。如果想让它重启后依然生效,别忘了保存规则:
sudo netfilter-persistent save # 或 sudo iptables-save > /etc/iptables/rules.v4nftables 场景,先看当前表结构:
sudo nft list ruleset然后按你的表结构添加规则,以inet filter表为例:
sudo nft add rule inet filter input tcp dport 32122 accept4.3 云安全组:最容易被忽略的一层
如果你用的是云服务器,服务器内部的 ufw 只是第二层防线。云平台的安全组(Security Group)才是第一层。以达梦云、某云、某翼云为例,安全组的入方向规则通常要手动添加端口段,常见默认规则是22/22 源 0.0.0.0/0。你要去云控制台的网络与安全组配置页面,加一条32122/32122的入方向 TCP 规则,源地址按需填0.0.0.0/0(公网开放)或特定 IP 段(只允许内网)。
这一步不做,即使服务器内部防火墙全放行,外网照样连不上新端口。很多“教程说改了端口就连不上”的案例,最后查出来都是这里漏了。
4.4 内网还有没有其他防火墙
如果服务器在公司内网,或者前面还有硬件防火墙、路由器 ACL,那也得确认这些中间设备是否允许高位端口的入站流量。有些公司网络策略只开放特定端口(比如 80、443、22),这种情况改端口之前最好先跟网络管理员确认,否则改完连不上还得回头沟通。
5. 连接测试的完整链路——从本机检测到公网穿透测试
配置改完、防火墙放完,最后一步是完整的连接测试。这一步的目的不是“哦能连了”,而是“确认新端口真的工作、旧端口真的关闭、修改没有引入其他问题”。我习惯分三层测试。
5.1 本机验证监听状态
回到服务器上,检查 sshd 监听状态:
sudo ss -tlnp | grep sshd预期输出:
LISTEN 0 128 0.0.0.0:32122 0.0.0.0:* users:(("sshd",pid=1234,fd=3)) LISTEN 0 128 [::]:32122 [::]:* users:(("sshd",pid=1234,fd=4))我只能看到 32122,看不到 22,说明老端口确实关闭了。如果 22 和 32122 同时出现在列表里,说明你还有一行生效的Port 22没注释干净,回配置里查一遍。
5.2 本机回环测试
在服务器本机执行:
ssh -p 32122 localhost这一步能确认 sshd 本身工作正常、端口可以接受连接。如果本机都连不上,那不是防火墙的问题,是 sshd 配置或服务状态的问题,先排查服务。
5.3 局域网测试
换一台同一局域网的机器,执行:
ssh -p 32122 user@server-lan-ip这步验证局域网内的连通性,如果不行,重点查服务器内部的防火墙(ufw/iptables)和监听地址是否绑定了内网 IP。
5.4 公网测试与端口连通性检测
如果你操作的是公网服务器,最后一步用外部环境测。最简单的方法是用手机流量热点开一台笔记本,或者找另一台公网机器:
nc -vz your-server-ip 32122或
nmap -p 32122 your-server-ip端口状态显示 open,说明公网可达。显示 filtered 或 closed,说明大概率被云安全组或外部防火墙拦了。
这里提一句:测试完新端口后,建议顺手把 SSH 配置里的旧端口行注释掉,并删除防火墙旧的 22 端口入站规则。很多管理员改完新端口后,旧的 22 端口规则还留着,服务虽然不监听 22,但安全组和防火墙规则一直挂着,等于是给攻击者留了一个“看起来没用但随时可能被重新启用”的口子。干净利落地清掉旧规则,才算真正完成迁移。
6. 常见故障与回滚方案——连接超时、权限拒绝、配置没生效的完整排查链路
这一节是重点中的重点。我相信每个改过 SSH 端口的人都至少踩过其中一个坑,而最常见的结果就是把自己锁在门外。下面我把故障排查链路完整拆开,手把手教你一步步定位和修复。
6.1 改完端口后完全连不上——先分清“拒绝连接”和“超时”
连接失败时,错误信息很重要,不要忽略它直接瞎猜。
Connection refused:目标端口没有服务在监听,或者防火墙直接回了 RST。说明 sshd 没监听新端口,或者防火墙 DROP 之前先 REJECT。优先检查 sshd 状态和监听地址。Connection timed out:数据包被静默丢弃,一般是防火墙 DROP 规则或者云安全组没放行。优先检查安全组和内部防火墙。No route to host:三层不通,检查网络配置和路由,跟这次改动关系通常不大。
用这条规律先缩小范围,就能省掉大量无效排查。
6.2 服务重启失败——查看日志是第一步
如果sudo systemctl reload ssh或restart ssh报错,立刻看日志:
sudo journalctl -u ssh -n 50最常见的错误是配置语法问题,比如端口范围写错、指令拼错、引号不匹配。日志里会明确提示第几行配置有问题:
/etc/ssh/sshd_config line 8: Bad port 'abc'需要系统恢复的话,直接把配置恢复到备份版本:
sudo cp /etc/ssh/sshd_config.bak.20240101120000 /etc/ssh/sshd_config sudo systemctl start ssh6.3 配置改对了但连接仍然走 22 端口——检查 ssh.socket
这是 Ubuntu 22.04 用户最常撞见的怪问题:配置里写了Port 32122,sshd -T也显示 port 32122,但实际连接 22 端口照样能建立 SSH 会话。原因在于新版 systemd 的 socket 激活机制。用下面的命令确认:
sudo systemctl status ssh.socket如果 socket 是 active 且监听端口是 22,那么 ssh 连接是由 socket 单元接管,压根不会完全走你 sshd_config 里的端口配置。处理方式:
sudo systemctl stop ssh.socket sudo systemctl disable ssh.socket sudo systemctl restart ssh把 socket 停掉禁用,让 sshd 服务以 standalone 模式直接监听配置里的端口。这样Port 32122才能真正生效。
提示:改 socket 配置的另一种方法是直接修改
/lib/systemd/system/ssh.socket里的ListenStream=行,但我觉得更干净的方式是禁用 socket 激活,让 SSH 回到传统 daemon 模式,行为更容易预测,也方便排查。
6.4 密钥登录失效——端口改了和它没关系,但坑还是踩得到
有些场景是端口改完了,密码登录可以,密钥登录却报Permission denied (publickey)。这跟端口本身没关系,但很容易在改动过程中不小心踩到。检查思路:
- 服务端
sshd_config里有没有显式设置PubkeyAuthentication no。有些教程在加固时会把密码登录和密钥登录一起调,改完后把行为搞乱了。 - 客户端用了
-i ~/.ssh/id_rsa吗?没有指定私钥文件的话会默认尝试~/.ssh/id_rsa,文件名不匹配就登录不了。 - 服务端的
~/.ssh/authorized_keys权限对吗?必须是600,.ssh目录必须是700。权限不对会导致服务端拒绝读取密钥。
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys6.5 把旧连接挤掉、新连接也断——MaxStartups 和连接数限制
改端口后如果遇到“能连上但马上就断”或者“连接一多就踢人”的症状,查一下MaxStartups配置。默认值是10:30:100,含义是未认证连接数达到 10 后,以 30% 的概率拒绝新连接,直到达到 100 全部拒绝。如果你同时有很多连接在排队,就可能触发这个机制。可以适当调大:
MaxStartups 50:30:100这个和端口改动没有直接关系,但迁移端口后很多人会顺便做压力测试或批量推密钥,就容易撞上这个参数。
6.6 最终手段:通过云控制台救援通道恢复
如果上述所有排查都做完了,你依然被锁在门外,别慌,还有最后的自救通道。几乎所有主流云平台都提供 VNC 或者 Web Shell 登录入口。登录到系统后,你可以直接修改配置文件:
sudo vi /etc/ssh/sshd_config # 把端口改回 22,或者改回正确的端口 sudo systemctl restart ssh哪怕是 socket 激活的状态,在救援通道里都能直接操作。这也是我为什么在前面强调“操作之前先确认自己有没有备用通道”——这句话关键时刻真的能救命。
7. 改完端口后的习惯建议——密钥登录、Fail2ban 与定期检查
最后再多聊几句“改完端口之后的事”。端口改对了只是第一步,整个 SSH 安全策略的升级才是长远之计。
7.1 配合密钥登录,关闭密码认证
如果你现在还用密码登录,我强烈建议这次改端口的同时把密钥登录一并配上。操作流程:
- 本地生成密钥对(如果有就不用了):
ssh-keygen -t ed25519 -C "your-comment"- 上传公钥到服务器:
ssh-copy-id -p 32122 user@server-ip- 确认密钥登录正常后,禁用密码认证:
sudo sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config sudo systemctl reload ssh改完后,密码登录这条路就断了,暴力破解也就失去意义。
7.2 Fail2ban 做第二层拦截
即使改了高位端口,针对性扫描依然可能发生。Fail2ban 能监控 SSH 的认证日志,自动封禁短时间内连续失败多次的 IP。安装很简单:
sudo apt install fail2ban sudo systemctl enable fail2ban默认配置就能工作,但建议把ignoreip填上自己的固定 IP,免得哪天误伤自己。
7.3 每月检查一次 auth.log
一条很土但有效的习惯:定期看一眼认证日志。
sudo grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head -20这个命令能列出过去所有认证失败次数最多的 20 个 IP。如果你的新端口真的是“安静”的,这条命令跑出来应该是空的结果。如果还有大量失败记录,说明你的端口已经被人盯上了,考虑再加上 Fail2ban 或者改用密钥登录。
在多次和 SSH 安全问题打交道之后,我更确信一件事:改端口不是银弹,但它是一个成本极低、效果明显的安全习惯。配合密钥认证、Fail2ban、定期审计日志,这套组合拳能让你的 Ubuntu 服务器在公网环境里安静很多。最后再分享一个小技巧:改完端口后,把~/.ssh/config里对应主机的Port字段更新一下,再也不会出现“换台电脑就忘了端口”的尴尬。这些经验都是踩坑踩出来的,希望各位一次就能顺利改完,不用经历被锁在门外的惊魂时刻。