端口映射需求分析
1. 让外网访问Web服务
# 先确认Web服务是否在运行,监听什么端口
ss -tulpn | grep ':80'
ss -tulpn | grep ':443'
# 如果没有Web服务,你需要安装一个(如Nginx/Apache)
# 然后将路由器的外网端口映射到服务器的80端口
sudo apt install nginx
# 启动并设置开机自启
sudo systemctl start nginx
sudo systemctl enable nginx
# 验证80端口在监听
curl http://localhost
2. 通过外网SSH连接
# SSH已经在监听某个端口(默认22或自定义)
ss -tulpn | grep ssh
# 将路由器的外网SSH端口映射到服务器的SSH端口
# 例如:路由器2222 → 服务器22
但是哦,服务器上的22端口一般是内网用的,SSH端口映射一般选用高位端口。
# 1. 修改服务器SSH端口(比如改成 2222)
sudo nano /etc/ssh/sshd_config
# 找到 #Port 22,改为:
Port 22 # 保留22给内网用(可选)
Port 2222 # 添加新端口
# 2. 重启SSH服务
sudo systemctl restart sshd
# 3. 防火墙开放新端口
# Ubuntu/Debian:
sudo ufw allow 2222/tcp
# CentOS/RHEL:
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
# 4. 路由器映射
# 外网端口:2222 → 内网IP:2222
检查当前SSH端口
# 查看SSH实际监听的端口
ss -tlnp | grep sshd
netstat -tlnp | grep ssh
# 查看SSH配置
sudo grep -i port /etc/ssh/sshd_config
# ssh登陆
ssh -p 端口号 用户名@服务器地址
# 测特定端口是否开放
telnet 192.168.1.100 22
于是发现:能ping通机器但是ssh加上端口2222后链接被拒绝;但是端口22依然能登陆上。并且实际监听没有新添加的2222端口。
问题排查
1. 配置文件语法错误
# 检查配置文件语法
sudo sshd -t
# 如果有错误,会显示具体位置
# 常见错误:缺少空格,格式错误等
2. SSH服务没有正确重启
其实22端口能登陆已经证明重启成功了。
# 查看SSH服务状态
sudo systemctl status sshd
# 或
sudo service ssh status
# 查看日志中的错误信息
sudo journalctl -u sshd --since "5 minutes ago"
sudo tail -50 /var/log/auth.log # Ubuntu/Debian
3. 端口被占用
查看SSH实际监听的端口时已经没显示这个端口,所以应该也不是被占用了。
# 检查2222端口是否被其他程序占用
sudo lsof -i :2222
sudo ss -tlnp | grep :2222
4. 检查SSH服务实际使用的配置文件
前面的排查说明:Port 2222 根本没被 sshd 解析进最终配置!sshd_config 可能被 include 覆盖,Ubuntu 22.04+ 开始,真正生效的配置不一定只看 /etc/ssh/sshd_config
# 主配置里有没有 include
grep -i include /etc/ssh/sshd_config
# 可能输出:Include /etc/ssh/sshd_config.d/*.conf,那么需要检查这个目录
ls -l /etc/ssh/sshd_config.d/
# 如果有输出50-cloud-init.conf 00-defaults.conf 可能会覆盖Port
# 找出到底谁在定义 Port
grep -R "^Port" /etc/ssh/
# 如果输出如下,说明最后生效的是 50-cloud-init.conf 的 Port 22
/etc/ssh/sshd_config:Port 22
/etc/ssh/sshd_config:Port 2222
/etc/ssh/sshd_config.d/50-cloud-init.conf:Port 22
但是笔者ls -l /etc/ssh/sshd_config.d/里面是空的,共计0;grep -R "^Port" /etc/ssh/也只出现在/etc/ssh/sshd_config
最终解决
上述四个问题都不是,最后chatGPT发现了原因:不是配置问题。Ubuntu 24.04 默认行为用的是 systemd 的 socket 激活模式,ssh.socket 只监听了 22 端口,sshd_config 里的 Port 2222 被完全忽略了。
sudo systemctl status ssh.socket
# 输出类似:
Loaded: loaded (/lib/systemd/system/ssh.socket; enabled)
Active: active (listening)
Listen: 0.0.0.0:22
sudo systemctl status ssh.service
因为 ssh.service 是被 socket 拉起的,sshd 不会自己 bind 端口。在 socket 激活模式下,监听端口的是 ssh.socket,所以sshd_config 里的 Port 才会不起作用。
# 关闭 socket 激活,回到传统 sshd
sudo systemctl disable --now ssh.socket
sudo systemctl enable --now ssh.service
# 确认 sshd 自己在监听端口
ss -tlnp | grep sshd
在 ssh.socket 模式下,端口属于 systemd,不属于 sshd
进一步提问
ssh.socket和ssh.service,区别是什么,为什么要有这两种启动 sshd 的方式?
- ssh.service = 传统模式(sshd 自己监听端口)
- ssh.socket = systemd 帮你监听端口,再“按需唤醒”sshd
| 项目 | ssh.service | ssh.socket |
|---|---|---|
| 谁监听端口 | sshd | systemd |
| Port 配置生效 | ✅ | ❌ |
| 是否常驻 | 是 | 否(按需) |
| 启动速度 | 稍慢 | 更快(懒加载) |
| 可控性 | 高 | 较低 |
| 适合场景 | 服务器 / 运维 | 轻量 / 节能 |