暴露在公网上的Ubuntu服务器,默认的22端口几乎是恶意扫描器的最爱。每天数万次的暴力破解尝试,不仅拖累服务器性能,更埋下了严重的安全隐患。把SSH端口改掉,再配合禁用密码登录,强制使用密钥认证,能直接挡掉99%的自动化攻击。这不是什么高深操作,但细节处理不到位,很容易把自己锁在服务器外面。

修改前的必要准备

动手之前,务必保留一个已连接的终端窗口。如果修改过程中出现配置错误,只要当前会话不断开,你就有机会回滚配置。另外,先确认你手上有一对能用的SSH密钥,并且公钥已经放到了服务器的authorized_keys文件里。如果没有,现在就用ssh-keygen生成,用ssh-copy-id把公钥推上去。测试密钥登录完全正常后,再开始后续操作。很多人就是跳过了验证密钥这一步,结果端口一改、密码一关,自己再也连不上了。

选择新端口的原则

端口范围从1到65535,但选端口有讲究。1024以下的端口属于特权端口,需要root权限绑定,虽然能用但没必要。1024到49151是注册端口,部分服务会占用。49152到65535是动态或私有端口,相对干净。建议选一个五位数的端口,比如26489、51872这种,避免和其他常见服务冲突。用命令 ss -tlnp 查看当前监听的端口,确保你选的端口没被占用。选好之后记下来,后续配置会用到。

修改SSH默认端口

Ubuntu的SSH服务端配置文件在 /etc/ssh/sshd_config。用编辑器打开它,注意是sshd_config,不是ssh_config,后者是客户端配置,改错了没用。

sudo nano /etc/ssh/sshd_config

找到 #Port 22 这一行。去掉前面的注释符号#,把22改成你选定的端口号。如果这一行被注释掉了,SSH服务就会使用默认的22端口。修改后应该是这样:

Port 26489

保存文件,先别急着重启SSH服务。现在防火墙还挡着新端口,一重启SSH服务绑到新端口上,但防火墙没放行,连接就断了。

配置防火墙放行新端口

Ubuntu默认使用ufw管理防火墙。先查看当前状态:

sudo ufw status

如果防火墙是激活状态,需要添加新端口的放行规则。假设新端口是26489:

sudo ufw allow 26489/tcp

这条命令添加允许TCP协议通过26489端口的规则。如果你还开着22端口,先别急着删,等确认新端口能正常连接后再移除旧规则。现在可以重启SSH服务了:

sudo systemctl restart sshd

重启完成后,新开一个终端窗口,用新端口测试连接:

ssh -p 26489 用户名@服务器IP

能连上,说明端口修改成功。这时可以回到原来的终端,把22端口的防火墙规则删掉:

sudo ufw delete allow 22/tcp

如果用的是云服务器,别忘了在云服务商的安全组或防火墙规则里也放行新端口。这是最容易被忽略的地方,安全组默认只开22,你没在云控制台加新端口,外部流量根本进不来。

禁用密码登录,仅允许密钥认证

端口换了,但密码登录还开着的话,攻击者扫描到新端口后照样可以暴力破解。所以必须关掉密码登录。继续编辑 sshd_config:

sudo nano /etc/ssh/sshd_config

找到以下几行,确保它们的值如下设置。如果行首有#号就去掉:

PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
PubkeyAuthentication yes

PasswordAuthentication no 是核心,直接禁用密码认证。ChallengeResponseAuthentication no 关掉质询响应认证,这也是一种交互式认证方式,同样存在被暴力破解的风险。UsePAM 保持yes,因为密钥认证本身也依赖PAM模块进行账户管理。PubkeyAuthentication yes 确保密钥认证是开启状态。

还有一个参数需要留意,PermitRootLogin。如果之前允许root直接登录,现在强烈建议改成 prohibit-password 或者 no。prohibit-password 的意思是root只能通过密钥登录,密码不行。no 则是完全禁止root远程登录。推荐设置为 prohibit-password:

PermitRootLogin prohibit-password

保存文件后,先别重启服务。用 sshd -t 命令测试配置文件语法是否正确:

sudo sshd -t

如果没有输出任何错误信息,说明配置语法没问题。这个习惯能救命,配置写错了直接重启服务,SSH就起不来了。测试通过后,重启SSH服务:

sudo systemctl restart sshd

现在再开一个新终端测试连接。用密码登录应该会被拒绝,用密钥登录则正常通过。如果密钥登录失败,检查本地密钥路径是否正确,服务器上 ~/.ssh/authorized_keys 文件权限是否为600,~/.ssh 目录权限是否为700。权限不对,SSH服务会拒绝使用该公钥。

加固SSH的额外配置

端口改了,密码关了,安全基础已经打好了。但还可以再做一些加固,让SSH服务更健壮。在 sshd_config 里追加或修改以下参数:

MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 30
MaxSessions 5
AllowUsers 你的用户名

MaxAuthTries 限制单次连接最多尝试认证次数,超过就断开,拖慢暴力破解速度。ClientAliveInterval 和 ClientAliveCountMax 配合使用,服务端每300秒发一个心跳包,两次无响应就断开僵死连接,避免资源浪费。LoginGraceTime 设置认证超时时间,30秒内没完成认证就断开。MaxSessions 限制单个连接能建立的最大会话数。AllowUsers 是白名单,只允许指定的用户通过SSH登录,这是最有效的访问控制手段,多个用户用空格分隔。

修改完这些参数后,同样用 sshd -t 测试,然后重启服务。

配置Fail2ban自动封禁恶意IP

换了端口不代表高枕无忧,专门针对高位数端口的扫描也在增多。Fail2ban能监控日志,发现多次认证失败的IP就自动用防火墙封禁一段时间。安装很简单:

sudo apt update
sudo apt install fail2ban -y

安装后,复制一份配置文件进行自定义,不要直接修改默认配置:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

编辑 jail.local,找到 [sshd] 段落,调整参数:

[sshd]
enabled = true
port = 26489
maxretry = 3
bantime = 3600
findtime = 600

port 要填你修改后的SSH端口。maxretry 是最大重试次数,超过就封禁。bantime 是封禁时长,单位秒,3600就是一小时。findtime 是统计时间窗口,600秒内失败3次就触发。配置完成后启动Fail2ban并设置开机自启:

sudo systemctl enable fail2ban --now

用 sudo fail2ban-client status sshd 可以查看当前封禁状态,被ban的IP列表一目了然。

密钥管理的注意事项

强制密钥登录后,密钥本身的安全就成了关键。私钥绝对不能泄露,本地存储的私钥文件权限必须是600。生成密钥对时建议加密码保护,虽然每次连接要多输一次密码,但即使私钥文件被盗,没有密码也无法使用。多台设备访问同一台服务器时,每台设备生成自己的密钥对,把各自的公钥追加到服务器的authorized_keys里,不要共用同一对密钥。定期检查 authorized_keys 文件,移除不再使用的公钥,离职同事的访问权限第一时间清理掉。

验证整体安全性

所有配置完成后,做一次全面验证。用nmap扫描一下自己的服务器,确认新端口已开放,旧端口已关闭:

nmap -p 22,26489 服务器IP

22端口应该显示closed或filtered,新端口显示open。再尝试用密码连接,应该被拒绝并提示Permission denied。检查SSH日志确认Fail2ban在正常工作:

sudo tail -f /var/log/auth.log

日志里能看到失败的登录尝试,以及Fail2ban的封禁记录。如果一切正常,这台Ubuntu服务器的SSH安全性已经达到了相当高的水准。后续只需定期更新系统,保持软件包在最新版本,基本可以抵御绝大多数针对SSH的攻击。