端口映射需求分析

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 配置生效
是否常驻 否(按需)
启动速度 稍慢 更快(懒加载)
可控性 较低
适合场景 服务器 / 运维 轻量 / 节能

文章作者: 易百分
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 易百分 !
  目录