如果你手里正好有一台Ubuntu机器,不管它是物理机、云服务器还是VMware里的虚拟机,装SSH服务器大概率是你做完系统之后要干的第一件事。这玩意儿装不装得好,直接决定你接下来是舒舒服服地在Windows上远程敲命令,还是老老实实蹲在机房显示器边上插键盘。这篇文章先从"为什么几乎所有Ubuntu运维场景都绕不开SSH"说起,再把安装、验证、加固、排障、实际使用一条线拉通,尽量把每一步背后"为什么要这么做"也讲清楚。适合刚接触Linux的小白,也适合帮被SSH折腾过的老手查漏补缺。
1. 为什么装SSH服务器几乎是Ubuntu装完系统后的第一件事
1.1 SSH解决了什么问题
SSH全称是Secure Shell,本质就是一个加密的远程命令行通道。没有它,你管理一台Linux服务器就得坐在那台机器面前,接上显示器和键盘操作;有了它,你在工位上、在家里、甚至在手机上都能连过去执行命令、改配置、传文件。生产环境里的Linux服务器绝大多数没有接显示器,日常维护完全依赖SSH,所以装好系统后第一件事就是把这个远程通道打开,这句话一点都不夸张。
1.2 装之前先搞清楚自己的环境和需求
在敲第一条安装命令之前,我建议你先花两分钟确认三件事:Ubuntu版本、网络环境、root和普通用户的权限情况。
查看Ubuntu版本可以用这行命令:
bash复制lsb_release -a
比如我手头这台就是Ubuntu 22.04 LTS,这个版本对应的OpenSSH软件包在官方源里比较稳定,不需要额外添加PPA。确认网络环境尤其重要,特别是虚拟机场景:你是桥接模式还是NAT模式?你的虚拟机能不能访问外网?这直接决定了 apt update 能不能成功。权限方面,Ubuntu默认不给root密码,安装时需要 sudo 提权,如果你的用户不在sudo组里,安装过程会卡在权限不足的提示上,这个问题在纯净安装时偶尔会遇到。
另外想清楚你装SSH服务器的用途:是给VSCode远程开发用,还是给服务器做管理,还是给嵌入式开发板调试用?不同场景选的端口、认证方式和安全策略不太一样。开发机可以宽松一些,生产服务器则建议直接按安全要求一步配到位。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 安装OpenSSH Server的标准流程与每步背后的原因
2.1 先更新软件源,别跳过这一步
很多人装软件习惯直接 apt install openssh-server,结果偶尔会碰到“找不到软件包”或者装上去的版本很旧。原因是默认的软件包索引是装系统时生成的,可能已经过时。先执行:
bash复制sudo apt update
这步会从 /etc/apt/sources.list 里配置的Ubuntu软件源拉取最新的软件包索引。如果这里报了连接超时或者404错误,先别急着往下走,把源修好再说。国内服务器建议把源换成速度更快的镜像源,社区里用的比较多的像阿里云、清华源都可以,修改方法就是编辑上面那个sources.list文件,把官方源地址替换成镜像地址,然后再次 apt update。
2.2 安装和启动openssh-server
软件源正常后,执行安装:
bash复制sudo apt install -y openssh-server
装完后系统会自动启动sshd服务,但你最好手动确认一遍状态:
bash复制sudo systemctl status ssh
看到 active (running) 说明服务已经起来了。为了让SSH服务在每次开机后自动启动,执行:
bash复制sudo systemctl enable ssh
这一步在很多云镜像上默认已经做好,但本机手动装的Ubuntu不一定,养成习惯总没错。装完后顺手看一下sshd监听的端口和地址:
bash复制sudo ss -lntp | grep sshd
正常情况应该能看到 0.0.0.0:22,这意味着所有网卡上的22端口都在监听,别的机器可以连进来了。如果你想限制只监听某个内网IP,后面可以在配置文件里改 ListenAddress。
2.3 防火墙和UFW策略判断
Ubuntu桌面版默认不带UFW防火墙规则,服务器版如果你之前没动过,UFW大概率是关闭的。但千万别想当然,装完之后检查一下:
bash复制sudo ufw status
如果状态是 inactive,那不用管防火墙的事;如果状态是 active,就必须放行SSH端口,否则客户端连过来会直接超时:
bash复制sudo ufw allow 22/tcp
有些云服务器厂商(比如阿里云、腾讯云)除了系统里面的防火墙,还有一层安全组策略,那个在网页控制台上配置。如果你用的是云服务器,安装好SSH之后连不上,第一反应就应该是去安全组里确认22端口有没有放行。这个问题我在帮朋友排查时遇到了好几次,系统内怎么查都是好的,最后发现是安全组没放行。
3. 第一次SSH登录的完整验证与虚拟机场景联调
3.1 先拿回环地址自测
装完服务别急着拿出手机连,先在本机自测一下,确认服务本身没问题。执行:
bash复制ssh localhost
如果提示输入当前用户的密码,然后成功进入到shell,说明SSH服务基本正常。这个自测能过滤掉很多外部因素。自测时如果报 Connection refused,说明sshd没起来或者没监听22端口;如果报 Connection timed out,多半是防火墙挡了22端口,但本机回环测试一般不会走到这步。
3.2 局域网内用SSH客户端远程登录
确认本机服务正常后,就可以在另一台电脑上试着连了。Windows上最常用的客户端是PowerShell自带的ssh命令、Xshell、MobaXterm、Bitvise SSH Client等;Linux/macOS下直接在终端输入:
bash复制ssh 用户名@服务器IP
这里的“用户名”是Ubuntu上的一个真实用户,不能是IP地址的别名。服务器IP地址用 ip addr 查看,找 eth0、ens33、enp0s3 这类网卡对应的IPv4地址,一般在192.168.x.x这个网段。第一次连接时,SSH客户端会提示确认远程主机的指纹:
code复制The authenticity of host '192.168.1.100 (192.168.1.100)' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxx...
Are you sure you want to continue connecting (yes/no)?
输入 yes 回车。这一步是SSH防中间人攻击的重要机制,指纹相当于服务器的身份证,以后如果服务器重装系统导致指纹变化,客户端会提示指纹不匹配,那时候就要小心是不是有人冒充了服务器。
3.3 VMware虚拟机里的网络模式为什么连不上
很多人在VMware里装了Ubuntu,然后在Windows宿主机上想用SSH连虚拟机,结果发现怎么都连不通。这里的问题大概率出在VMware虚拟机的网络模式上。
VMware有三种网络模式:桥接模式、NAT模式、仅主机模式。桥接模式下,虚拟机会和宿主机处于同一个局域网,像一台独立的电脑,最容易互通;NAT模式是虚拟机通过宿主机上网,外部设备默认无法直接访问虚拟机里的服务;仅主机模式更封闭,只能和宿主机通信。
如果你用的是NAT模式,想让Windows宿主机SSH连进虚拟机,需要做一步端口转发,或者直接把网络模式切换成桥接。VMware的虚拟网络编辑器里可以设置NAT端口转发,把宿主机的某个端口映射到虚拟机的22端口。我实测下来,最省事的方式是改桥接模式,前提是你的路由器DHCP能分配IP给虚拟机。不过桥接模式下虚拟机IP是路由器分配的,和宿主机在同一个网段,SSH连接地址也是固定的,后续不需要额外配置。
如果你不想改网络模式,就在虚拟网络编辑器里加一条NAT转发规则,例如宿主机2222端口转发到虚拟机192.168.x.x的22端口,然后用 ssh 用户名@宿主机IP -p 2222 连接。
4. 初装之后不要立刻投入生产:先做这几项必要加固
4.1 修改默认端口和监听地址
SSH默认监听22端口,网上大量扫描工具就是扫22端口的,改一个不常用端口能直接过滤掉一大批自动扫描流量。修改方法:编辑sshd配置文件。
bash复制sudo vim /etc/ssh/sshd_config
找到 #Port 22 这一行,去掉注释改成:
code复制Port 2222
改完记得重启服务:
bash复制sudo systemctl restart ssh
这时再用22端口连接就进不来了,必须换成2222端口。如果你在云服务器上,记得安全组也要同步放行这个新端口。另外,如果服务器有多个网卡,可以加上 ListenAddress 内网IP 来限制只能通过内网IP访问SSH,外网网卡上的SSH直接关闭,这样安全性会提升很多。
4.2 配置SSH密钥登录,替代密码登录
密码登录最大的问题是容易被暴力破解。哪怕你设了强密码,在有公网IP的机器上,每天也能看到成千上万次扫描尝试。配置密钥登录的本质是让客户端持有一把私钥,服务器存公钥,登录时通过非对称加密算法验证身份。
在客户端(比如Windows上的PowerShell)生成密钥对:
bash复制ssh-keygen -t ed25519 -C "your_email@example.com"
一路回车,会在当前用户目录生成 ~/.ssh/id_ed25519(私钥)和 ~/.ssh/id_ed25519.pub(公钥)。然后把公钥拷贝到服务器上:
bash复制ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 用户名@服务器IP
ssh-copy-id 会自动把公钥追加到目标服务器 ~/.ssh/authorized_keys 文件里,并且设置好权限。如果客户端是Windows,PowerShell里也能用这个命令,前提是机器上装了OpenSSH客户端。等密钥登录确认没问题后,再来改配置文件禁用密码登录:
code复制PasswordAuthentication no
重启服务后再连接时,输入密码的提示就没有了,只有持有私钥的客户端才能进来。这一步是我在所有机器上的标配操作,做了之后/var/log/auth.log 里的失败登录日志会肉眼可见地减少。
4.3 限制可登录用户和失败重试次数
如果你想再严一点,可以在sshd_config里追加限制:
code复制AllowUsers ubu dev
MaxAuthTries 3
AllowUsers 后面跟允许登录的用户名,多用户之间用空格隔开;MaxAuthTries 限制单次连接的最大认证尝试次数,超过就断开。这两项配置能有效防止某些针对单个用户的暴力破解。另一个可选项是安装fail2ban,它会监控登录日志,在多次失败后自动封禁来源IP一段时间:
bash复制sudo apt install -y fail2ban
不过fail2ban在纯内网环境里意义不大,公网服务器才需要它。配置完这些之后,记得用 sshd -t 检查配置文件语法,确认无误再重启,避免改错导致整个SSH服务起不来。
5. 连不上的时候怎么办:从现象到根因的完整排查思路
5.1 Connection refused、timeout、permission denied分别指向什么
SSH连接报错大概就这么几类,每一类对应的排查方向完全不同。
Connection refused:说明目标机器上22端口没有程序在监听,或者防火墙主动拒绝了。先看sshd是否启动,再看端口是否在监听,然后看防火墙规则。Connection timed out:说明网络包发出去了,但对端一直没回应,多半是网络不通或者防火墙丢包。优先检查IP是否正确、能不能ping通、云安全组是否放行。Permission denied (publickey,password):说明TCP连接已经建立,但身份验证没过,用户名、密码、密钥的某一步出了问题。Host key verification failed:远程服务器指纹变了。可能是服务器重装过或者存在中间人,先确认是不是重装,再用ssh-keygen -R 服务器IP清除旧指纹重连。
我把这些整理成了一张排查表,遇到问题时直接按表格查:
| 报错信息 | 可能原因 | 排查命令/操作 |
|---|---|---|
| Connection refused | sshd未启动 / 端口未监听 / 防火墙拒绝 | systemctl status ssh;ss -lntp;ufw status |
| Connection timed out | IP不通 / 安全组未放行 / 跨网段路由问题 | ping 服务器IP;检查云控制台安全组 |
| Permission denied | 密码错 / 用户名不存在 / 密钥不匹配 | 确认用户名;检查~/.ssh/authorized_keys权限 |
| Host key verification failed | 服务器指纹变化 | ssh-keygen -R 服务器IP 后重连 |
5.2 我踩过的一个真实坑:authorized_keys权限不对
有一回我在客户服务器上配好了密钥登录,当时连得通,结果服务重启后突然就提示 Permission denied (publickey)。检查半天,最后发现是有人手动修改过 .ssh 目录权限,把 ~/.ssh 的权限改成了755。OpenSSH对目录权限非常敏感,权限太宽松它会认为不安全,直接拒绝用公钥认证。
正确权限要求是:
~/.ssh目录:700~/.ssh/authorized_keys文件:600- 用户家目录本身:不能对group和other开放写权限
修复命令:
bash复制chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
另外,如果是root用户登录,还要注意 /root 目录的权限也不能是775这种宽松模式,否则一样报错。
5.3 开启SSH调试模式,看最详细的日志
如果上面的常规排查都没发现原因,可以启停sshd的时候打开调试日志,把输出打出来看。重启服务时用前台运行模式:
bash复制sudo systemctl stop ssh
sudo /usr/sbin/sshd -d
这个模式会在终端里打印出完整的握手过程,包括密钥加载、认证流程。连完一次之后Ctrl+C退出,再恢复正常服务:
bash复制sudo systemctl start ssh
还有一种只查日志的方式:
bash复制sudo tail -f /var/log/auth.log
这个是排查认证问题的神器,几乎每一条失败登录都会在这里留下原因。我在处理大量SSH故障时,90%的问题都能通过这一条命令定位到方向。
6. 配好SSH服务器之后,把这些高频玩法顺手用起来
6.1 免密登录的另一种姿势:写客户端config文件
前面用 ssh-copy-id 把公钥传上去之后,平时连接还是要 ssh 用户名@IP -p 端口 这一长串。机器多了之后记IP就是个大麻烦。可以在客户端 ~/.ssh/config 文件里给每台服务器起一个别名。
code复制Host ubuntu-dev
HostName 192.168.1.101
Port 2222
User ubuntu
IdentityFile ~/.ssh/id_ed25519
配置完后连接只需要:
bash复制ssh ubuntu-dev
用MobaXterm、Xshell这类图形工具的同学,也可以直接新建会话时填好主机名、端口、用户名,然后把私钥路径填到认证设置里。效果和命令行完全一样,每次打开工具直接双击会话就进去了,不用再敲一次密码。
6.2 VSCode通过SSH做远程开发
热搜词里有一堆“vscode连接ssh远程服务器”“could not create directory /c/users...”相关的问题,看来远程开发是大家很常见的用途。VSCode装一个 Remote - SSH 扩展,然后按F1输入 Remote-SSH: Connect to Host,选择你刚才配好的别名,就能在本地VSCode里直接打开远程目录写代码。
有个经典错误值得单独说:在Windows上用VSCode连接Linux开发机时,有时会报这个错:
code复制could not create directory '/c/users/xxx/.ssh'
原因是Windows的OpenSSH没有正确识别HOME路径。解决方法是给用户环境变量加一个 HOME,值设为 C:\Users\你的用户名,然后重启VSCode和终端。这个坑非常隐蔽,很多人折腾半天,最后发现就是环境变量的问题。
VSCode连上远程主机后,相当于在本地打开了一个远程工作区,终端、调试、Git操作全部基于远程环境,体验非常接近本地开发。公司服务器、云主机都能这么玩。
6.3 SSH端口转发的几个实战用法
SSH端口转发是个容易被忽略但极其强大的能力。最经典的用法是把一个本机不存在的端口映射到远程服务器可访问的某个内网服务上。
假设你只能SSH登录到跳板机(IP为10.0.0.5),但想访问内网里另一台机器上的Web管理界面(IP为192.168.1.5,端口8080),就可以在本机执行:
bash复制ssh -L 8080:192.168.1.5:8080 user@10.0.0.5
然后浏览器打开 http://localhost:8080,流量已经通过SSH隧道到达内网的Web服务了。相当于在本地和跳板机之间打了一个加密隧道,隧道出口帮你转发到目标内网IP。
另一种是动态转发,配合代理使用:
bash复制ssh -D 1080 user@跳板机
这个命令会在本地1080端口开一个SOCKS代理,浏览器、终端走这个代理时,出口IP就是跳板机的IP,相当于一个加密的HTTP隧道。不过这里需要注意,用SSH做代理转发前要确认公司或者校园网的网络使用政策,别拿去做访问控制之外的用途。端口转发的配置同样写在 ~/.ssh/config 里可以固定下来,比如:
code复制Host mongodb-tunnel
HostName 10.0.0.5
User ubuntu
LocalForward 27017 192.168.1.8:27017
以后每次 ssh mongodb-tunnel,隧道就自动建立了。这个玩法对调试内网服务、临时应急访问非常有价值。
安装SSH服务器这件事,说简单是真简单,一条命令就能跑起来;说复杂也复杂,从端口监听、密钥认证、防火墙规则到虚拟机网络模式,任何一个环节出问题都可能卡住你半天。我在实际配过的机器里,遇到过最离谱的一次是装完SSH后一切正常,结果一个月后系统重启无法连接,最后发现是有人把 /etc/ssh/sshd_config.d 下的某个自定义配置改成禁用密码登录,而密钥认证又被证书策略覆盖了。所以我的建议是:刚开始用默认配置跑通一次完整流程,再逐步给sshd_config增加加固项,每次改完都要用 sshd -t 检查语法,才能保证这台机器不只是“装好了”,而是真正“用得稳”。
