RDP Monster

Ubuntu 启用 SSH:安装 OpenSSH 服务端并加固

Ubuntu 启用 SSH:安装 OpenSSH 服务端并加固

在 Ubuntu 上启用 SSH:安装、启动、放行防火墙

Ubuntu 的 SSH 服务来自 openssh-server 软件包。Ubuntu Server 在安装过程中会询问是否安装,几乎所有云或 VPS 镜像出厂时就已在监听;Ubuntu Desktop 则完全不安装它。

1. 安装 openssh-server

sudo apt update
sudo apt install -y openssh-server

如果软件包已经存在,apt 会提示并不做任何改动。安装同时会注册一个名为 OpenSSH 的 UFW 应用配置,第 3 步会用到。

2. 启用并启动服务

sudo systemctl enable --now ssh
systemctl status ssh

在 Ubuntu 上,该单元名为 ssh,sshd 是它的别名。enable --now 会立即启动守护进程,并设置为开机自启。自 Ubuntu 22.10 起,sshd 由 socket 激活:ssh.socket 持有 22 端口,并在第一个连接到来时启动 ssh.service,所以安装后状态显示 inactive (dead) 且带有 TriggeredBy: ssh.socket 是正常的;端口是开着的。想了解全貌,可参阅用 systemctl 列出服务。

3. 在 UFW 中放行 SSH

Ubuntu 默认关闭 UFW。如果你要开启它,请先放行 SSH;在规则存在之前就启用防火墙,是把自己锁在远程机器外面的经典方式。

sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status

ufw allow OpenSSH 使用应用配置并开放 22/tcp。如果之后更改了 sshd 端口,请用 sudo ufw allow 2222/tcp 放行新端口并删除旧规则。用 hostname -I 查看服务器地址。

从 Windows、macOS 或 Linux 连接

当前所有主流桌面系统都内置 OpenSSH 客户端,语法完全一致:

ssh username@SERVER_IP
ssh -p 2222 username@SERVER_IP      # non-default port
  • Windows 10 和 11:打开 PowerShell 或 Windows Terminal 输入命令即可;自 2018 年(1809 版本)起 Windows 就自带 OpenSSH 客户端。如果提示无法识别 ssh,请在“设置 > 应用 > 可选功能”中添加。
  • macOS:打开终端,命令相同。
  • Linux:任意终端;Ubuntu 默认已安装 openssh-client。

首次连接时输入 yes 接受服务器的主机密钥指纹;它会保存在 ~/.ssh/known_hosts 中,日后若发生变化系统会发出警告。接着输入账户密码;下一节会用密钥取代它。

切换到密钥认证

僵尸网络昼夜不停暴力破解的正是密码登录;使用密钥可以让这些尝试彻底失效。请在你自己的电脑上生成 Ed25519 密钥对,绝不要在服务器上生成:

ssh-keygen -t ed25519 -C "laptop-2026"

接受默认路径(~/.ssh/id_ed25519)并设置一个口令;它会在磁盘上加密私钥,配合 SSH agent,每个会话只需输入一次。只有 .pub 文件会离开你的机器。

把公钥复制到服务器

在 macOS 和 Linux 上,ssh-copy-id 一步完成,最后一次使用密码:

ssh-copy-id -i ~/.ssh/id_ed25519.pub username@SERVER_IP

Windows 版 OpenSSH 不包含 ssh-copy-id;可以在 PowerShell 中用管道把密钥传过去:

type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh username@SERVER_IP "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

两种方式都会把密钥追加到该用户的 ~/.ssh/authorized_keys。权限很关键:当 ~/.ssh 不是 700 模式,或 authorized_keys 对属主之外的人可写时,sshd 会静默忽略该文件。打开一个新终端,此时 ssh username@SERVER_IP 应当无需账户密码即可登录。在做到这一点之前,不要进行下一节的操作。

加固 sshd_config:禁用密码、禁止 root、限定用户白名单

编辑时请保持当前会话不要关闭;如果新配置出问题,它就是你回来的通道。/etc/ssh/sshd_config 开头是 Include /etc/ssh/sshd_config.d/*.conf,而 sshd 对每个关键字只保留第一个读到的值,因此 drop-in 文件会压过主文件中靠后的配置。云镜像还常常自带带有 PasswordAuthentication yes 的 /etc/ssh/sshd_config.d/50-cloud-init.conf,这正是直接改主文件往往毫无效果的原因。解决办法是创建一个排序靠前的 drop-in 文件:

sudo nano /etc/ssh/sshd_config.d/00-hardening.conf

粘贴以下内容,把 username 替换成你自己的登录名:

PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
AllowUsers username
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
ClientAliveInterval 300
ClientAliveCountMax 2

PermitRootLogin no 的前提是你已有一个具备 sudo 权限的普通账户。如果你此前一直以 root 操作,请先在 Linux 上创建 sudo 用户并把密钥复制过去,再应用该文件。随后校验语法、重载配置,并查看在所有 include 合并之后 sshd 实际使用的值,这正是 sshd -T 输出的内容:

sudo sshd -t
sudo systemctl reload ssh
sudo sshd -T | grep -Ei 'passwordauthentication|permitrootlogin|allowusers|port'

先打开第二个终端并用密钥登录成功,再关闭第一个。各指令的作用如下:

指令值作用
PasswordAuthenticationno仅允许密钥;密码暴力破解不再是慢,而是根本不可能。
KbdInteractiveAuthenticationno关闭 PAM 可能用于密码认证的挑战-응答路径(旧称 ChallengeResponseAuthentication)。
PermitRootLoginnoroot 无法通过 SSH 登录,无论是否有密钥;请使用 sudo。
AllowUsers你的登录名未列出的用户在认证之前就被拒绝;[email protected]/24 可把某用户限定在指定网段。
MaxAuthTries3每个连接允许三次失败尝试,随后断开。
LoginGraceTime30未完成认证的连接在 30 秒后被切断。
ClientAliveInterval / ClientAliveCountMax300 / 2每五分钟探测一次空闲客户端,两次无响应后断开;在线客户端会自动应答。
X11Forwardingno除非需要转发图形界面程序,否则保持关闭。

保活也有客户端一侧的设置:在你自己机器的 ~/.ssh/config 中加入 ServerAliveInterval 60,可避免 NAT 路由器切断空闲会话。

改 SSH 端口并不是安全措施

把 sshd 从 22 端口挪走是流行建议,但它带来的只是更少的日志行。批量扫描器会遍历全部 65,535 个端口,几小时内就能发现 2222 上的 sshd;有针对性的攻击者用 nmap 几秒就能找到。密钥、禁止 root 登录、白名单和 fail2ban 才是安全,端口只是表面功夫。在繁忙的服务器上它确实有助于让认证日志保持可读,但绝不要把它当成一层防御。

如果你确实要改,请按这个顺序:先在 UFW 中开放新端口,再修改端口,重启,在第二个终端测试,最后删除旧规则。在 /etc/ssh/sshd_config 中取消注释 #Port 22,设置新端口,然后:

sudo ufw allow 2222/tcp
sudo sshd -t
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket    # Ubuntu 22.10 and later
sudo systemctl restart ssh           # Ubuntu 22.04 and earlier

在采用 socket 激活的版本中,决定绑定哪个端口的是 socket 单元而不是 sshd;Ubuntu 提供了一个 systemd 生成器,在 daemon-reload 期间从 sshd 配置中读取 Port 并更新 ssh.socket。用 sudo ss -tlnp | grep sshd 确认;检查 Linux 开放端口的指南解释了输出内容。如果 sshd 仍固执地停留在 22,可关闭 socket 激活,让服务自己绑定端口:sudo systemctl disable --now ssh.socket && sudo systemctl enable --now ssh.service。当新终端中 ssh -p 2222 可用后,执行 sudo ufw delete allow OpenSSH。

加上 fail2ban,并考虑双因素认证

禁用密码后暴力破解不可能成功,但每次尝试仍会消耗一次 fork 和一行日志。fail2ban 会监视认证日志并封禁反复失败的地址:

sudo apt install -y fail2ban
sudo nano /etc/fail2ban/jail.local

把下面的内容写进文件:

[sshd]
enabled = true
port = ssh
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

永远不要编辑 jail.conf;它在升级时会被覆盖,而 jail.local 会覆盖它的设置。port = ssh 通过 /etc/services 解析,所以如果你换了端口,请写 port = 2222。backend = systemd 直接读取 journal,无论镜像是否写入 /var/log/auth.log 都能工作。fail2ban-client status sshd 可列出被封禁的地址;sudo fail2ban-client set sshd unbanip 203.0.113.7 可解封其中一个。默认情况下 fail2ban 的规则先于 UFW 生效,两者可以共存。

双因素认证

如果密钥加口令仍不够,libpam-google-authenticator 可以在密钥之上再加一个基于时间的验证码:安装它,以登录用户身份运行 google-authenticator,在 /etc/pam.d/sshd 中加入 auth required pam_google_authenticator.so(并注释掉其中的 @include common-auth 行),然后在 sshd 中设置 KbdInteractiveAuthentication yes 和 AuthenticationMethods publickey,keyboard-interactive。这在笔记本被盗时是实打实的收益,但也多了一样可能丢失的东西:把备用验证码保存在服务器之外。

故障排查:连接被拒绝、超时、权限拒绝

Connection refused

服务器有响应,但该端口上没有任何程序监听:sshd 已停止、绑定到了别处,或者你输错了端口。从服务商的控制台运行 systemctl status ssh 和 sudo ss -tlnp | grep ssh。语法错误会让 sshd 根本无法启动;sudo sshd -t 会指出出错的行,journalctl -u ssh -n 50 显示最近一次启动记录。

Connection timed out

数据包被丢弃而非拒绝,这几乎总是防火墙问题:UFW 缺少放行规则(sudo ufw status verbose)、服务商面板中的安全组,或你所在网络封锁了出站 22 端口;用手机热点测试即可排除。ssh -v username@SERVER_IP 能显示握手卡在哪一步。

Permission denied (publickey)

服务器可达但拒绝了你。请依次检查:用户名;该用户的 authorized_keys 中是否包含你所提供的密钥(ssh -i ~/.ssh/id_ed25519 -v 可强制指定某个密钥);~/.ssh 的权限;以及该登录名是否遗漏在 AllowUsers 之外。在服务器上,journalctl -u ssh -n 30 会说明原因;Authentication refused: bad ownership or modes 就是前面提到的权限问题。

主机密钥警告

重装系统后出现 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED 是正常的:运行 ssh-keygen -R SERVER_IP 后重新连接。如果你并没有重装过任何东西,请先查明原因,不要随便输入密码。彻底被锁在外面?服务商的控制台就是回去的路。

以上内容都假设你在一台自己拥有 root 权限、并且可以承受把 sshd 弄坏再从控制台修好的机器上操作。rdp.monster 的 Linux VPS 正是这样一台机器:完整 root 权限、独享 CPU 与内存、不限量(合理使用)带宽、无需 KYC、支持加密货币或法币付款,每月 $8.99 起,付款确认后约 10 秒服务器即上线,有充足的时间在第一个扫描器发现 22 端口之前布置好密钥。

常见问题

Ubuntu 默认启用 SSH 吗?

Ubuntu Desktop 不启用;Ubuntu Server 和大多数云镜像会启用。
Ubuntu Desktop 只安装 SSH 客户端,因此在你运行 sudo apt install openssh-server 之前,没有任何程序监听 22 端口。Ubuntu Server 在安装过程中会询问是否安装 OpenSSH 服务端,并可同时导入你的 GitHub 或 Launchpad 密钥。云和 VPS 镜像几乎总是预装并启用了 openssh-server 且已接受连接,因为这是服务商把机器交付给你的唯一方式。用 systemctl status ssh 检查。

如何检查 Ubuntu 上的 SSH 是否正在运行?

运行 systemctl status ssh,再用 ss 确认 22 端口正在监听。
systemctl status ssh 会告诉你服务是否处于 active 或 enabled 状态。由于 Ubuntu 22.10 及更高版本使用 socket 激活,在无人连接时服务显示 inactive (dead) 并带有 TriggeredBy: ssh.socket 是合理的,因此更可靠的检测是 sudo ss -tlnp | grep ssh:出现 0.0.0.0:22 或 [::]:22 的行就说明 SSH 正在监听。从另一台机器执行 ssh -v username@SERVER_IP 可端到端确认。

把 SSH 留在 22 端口安全吗?

安全,前提是禁用密码并使用密钥;端口号本身不提供任何保护。
22 端口会持续吸引自动化登录尝试,但面对设置了 PasswordAuthentication no 并使用密钥对的服务器,这些尝试无法成功,而 fail2ban 能消除大部分噪音。把 sshd 挪到 2222 或 22222 只能躲开最懒的扫描器;nmap、masscan 之类的端口扫描器几分钟就能找到它,全网索引服务本来也会收录。请把非默认端口视为日志清洁措施,而不是安全控制,更不要因为改了端口就跳过密钥。

Ubuntu 上的 ssh 和 sshd 有什么区别?

ssh 是客户端程序,sshd 是服务端守护进程,在 Ubuntu 上其单元名为 ssh,sshd 为别名。
ssh 是你在笔记本上运行、用来发起连接的客户端,来自 openssh-client 软件包。sshd 是在服务器上应答的守护进程,来自 openssh-server,配置文件为 /etc/ssh/sshd_config(客户端读取的是 ssh_config)。Ubuntu 和 Debian 把 systemd 单元命名为 ssh.service 并声明 sshd.service 为别名,所以 systemctl restart ssh 和 systemctl restart sshd 效果相同;在 Fedora、RHEL 和 Arch 上,该单元就叫 sshd。

Adrien Roche, 基础设施与主机托管编辑

系统工程师,拥有 10 年以上运维 Windows Server 和 Linux 集群的经验。Adrien 负责 rdp.monster 的基础设施文档,并撰写关于 RDP、VPS 托管、服务器管理、网络和隐私工具的指南。

注册加入我们的分销商计划

您的信息

如有任何疑问, 点击这里联系我们 !
姓名(必填)
请填写您的邮箱地址,您必须拥有以下网站的账号: manager.rdp.monster !

您的公司

如果您有网站,请填写网址
请简要说明您打算如何向客户销售服务,例如在论坛上与人交流推广。

连怪兽都爱吃 cookie!

我们使用 cookie 来改善您的浏览体验、提供个性化的广告或内容,并分析网站流量。点击「接受」即表示您同意我们使用 cookie。