ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Ubuntu 20.04 SSH远程访问配置指南:从安装到安全加固

Ubuntu 20.04 SSH远程访问配置指南:从安装到安全加固

1. 为什么今天还值得花时间把 SSH 远程访问这件事做扎实

很多人第一次接触远程管理 Linux 主机,都是从一条ssh user@host命令开始的。看起来简单,但真正到了自己动手装系统、配网络、开远程的环节,问题就一个接一个冒出来:明明服务装好了却连不上、密码输对了却被拒绝、重启之后配置又失效了。Ubuntu 20.04 作为一个长期支持版本,至今仍大量运行在各种开发机、测试服务器、家庭实验室和边缘设备上,把它的 SSH 远程访问配置到位,是一件投入产出比非常高的事情。

这篇文章要解决的问题很具体:在一台刚装好的 Ubuntu 20.04 上,从零把 SSH 服务装起来,并且让局域网内的其他机器能够稳定地远程登录进来。它适合三类人:一是刚接触 Linux 服务端、想搞明白远程登录到底怎么回事的新手;二是手头有闲置机器想做成开发或测试节点、需要一套可靠远程方案的开发者;三是已经会敲命令但经常在权限、防火墙、配置持久化这些细节上翻车、想把知识补全的运维初学者。

我见过太多人卡在“装完了但连不上”这一步,最后靠重启、重装甚至放弃来收场。其实 SSH 远程访问涉及的环节并不多,无非是服务端安装、服务状态、监听配置、认证方式、网络放行这几块,但每一块都有容易忽略的细节。下面我会按照真实的操作顺序,把每一步背后的原因讲清楚,把常见的坑提前标出来,让你一次配好、长期稳定。

2. 装 SSH 之前先搞清楚:服务端和客户端到底谁装谁

2.1 一个高频误解:Ubuntu 桌面版默认没有 SSH 服务端

很多人以为 Ubuntu 自带 SSH,其实要分情况。Ubuntu 桌面版默认只装了 SSH 的客户端,也就是你能用ssh命令去连别人,但别人连不进来,因为服务端sshd根本没运行。而 Ubuntu Server 版在安装时如果勾选了相关选项,通常会预装服务端。所以当你在一台桌面版机器上敲ssh localhost发现连接被拒绝时,不要怀疑命令写错了,先确认服务端在不在。

判断方法很直接,查服务状态:

systemctl status ssh

如果返回Unit ssh.service could not be found,说明服务端压根没装。如果显示active (running),那服务端已经在跑了。这个判断步骤建议放在最前面,能省掉后面一堆无用排查。

2.2 服务端与客户端包名不同,别装错

Ubuntu 里 SSH 相关的包主要有两个:

包名作用谁需要
openssh-client提供 ssh 命令,用于连接别人几乎所有机器默认都有
openssh-server提供 sshd 服务,允许别人连进来需要被远程访问的机器

我们要装的是openssh-server。这里有个经验:不要图省事直接装ssh这个元包,虽然它通常会同时拉取客户端和服务端,但在某些精简系统上行为不一致。明确装openssh-server,意图清晰,依赖也干净。

提示:安装前先执行sudo apt update,否则可能因为软件源索引过期而装到旧版本,甚至报找不到包。

2.3 安装命令与安装后的第一反应

安装本身一条命令:

sudo apt update sudo apt install openssh-server -y

装完之后,Ubuntu 的包管理机制通常会自动把ssh.service设为开机自启并立即启动。但“通常”不等于“一定”,尤其是在容器、精简镜像或手动裁剪过的系统里。所以装完第一件事不是急着连,而是确认服务真的起来了:

systemctl status ssh

看到绿色的active (running)才算过关。如果没起来,手动拉一下:

sudo systemctl enable --now ssh

enable负责开机自启,--now表示同时立即启动,这两个动作合在一起写是运维里的常用习惯,能避免“这次起来了但重启后又没了”的尴尬。

3. 服务起来了却连不上:把监听、认证、网络三层逐一拆开

3.1 先确认 sshd 到底在监听哪个地址和端口

服务运行不代表它监听了你期望的地址。默认情况下,OpenSSH 服务端监听0.0.0.0的 22 端口,也就是所有网卡的 22 端口。但配置文件可能被改过,或者系统里有多个网络接口导致行为不符合预期。查看监听状态:

sudo ss -tlnp | grep sshd

这条命令会列出所有 TCP 监听端口以及对应的进程。正常应该看到类似0.0.0.0:22或*:22的输出。如果只看到127.0.0.1:22,那说明服务端只监听本地回环,外部机器永远连不进来,问题就出在配置文件上。

对应的配置项在/etc/ssh/sshd_config里,关键两行是:

ListenAddress 0.0.0.0 Port 22

ListenAddress决定监听哪些网卡地址,Port决定端口。改完配置后必须重载服务才生效:

sudo systemctl reload ssh

用reload而不是restart,是因为 reload 不会断开已有连接,对生产环境更友好。这个细节很多人不注意,直接 restart,结果把自己正在用的会话也踢掉了。

3.2 认证失败:密码明明对,为什么还被拒

连上了但登录被拒,是第二类高频问题。原因通常有三个方向:密码认证被禁用、用户被限制、或者密码本身有问题。

先看密码认证开关。在sshd_config里:

PasswordAuthentication yes

如果这行是no,那密码登录直接被封死,只能用密钥。有些加固过的系统默认就关掉了密码认证,新手不知道就会一直卡在“密码正确却进不去”。

再看用户限制。配置里可能有AllowUsers或DenyUsers指令,只允许特定用户登录。比如写了AllowUsers deploy,那你用其他账号怎么试都不行。检查方法:

sudo grep -E "AllowUsers|DenyUsers|PermitRootLogin" /etc/ssh/sshd_config

PermitRootLogin也值得关注,默认通常是prohibit-password,意思是 root 不能用密码登录,但可以用密钥。如果你正试图用 root 加密码登录,被拒是正常的,这是安全设计而非故障。

3.3 网络层:防火墙和网段这两关必须过

服务正常、认证正常,但就是连不上,八成卡在网络层。Ubuntu 20.04 默认可能启用了ufw防火墙。查看状态:

sudo ufw status

如果显示Status: active,那就要确认 22 端口是否放行:

sudo ufw allow 22/tcp

或者如果你改了端口,把 22 换成实际端口。放行后再次查看状态,应该能看到对应规则。

除了防火墙,还要确认两台机器在不在同一网段、能不能互相 ping 通。这一步经常被跳过,但它是排查的基石。如果 ping 都不通,那问题在路由或网段,跟 SSH 本身没关系。确认被访问机器的 IP:

ip addr show

找到类似192.168.x.x或10.x.x.x的地址,然后在另一台机器上ping这个地址。通了再谈 SSH,不通就先解决网络连通性。

注意:如果你在虚拟机里操作,还要确认虚拟机的网络模式。NAT 模式下外部机器无法直接访问虚拟机,需要改成桥接模式,或者配置端口转发。这是虚拟机环境里最常见的“连不上”原因,没有之一。

4. 让远程访问真正好用:密钥登录、配置持久化与安全收尾

4.1 从密码登录升级到密钥登录的完整流程

密码登录能用,但不够好。密钥登录更安全,也更方便,配好之后连密码都不用输。流程分三步:生成密钥对、把公钥放到服务端、验证登录。

在客户端机器上生成密钥对:

ssh-keygen -t ed25519 -C "my-remote-key"

这里选ed25519而不是默认的rsa,是因为 ed25519 更短、更快、安全性也足够,是现代系统的推荐算法。命令会问你把密钥存哪,直接回车用默认路径~/.ssh/id_ed25519即可。然后会问你要不要设密码短语,设了更安全,但每次登录要输;不设则完全免密。个人开发机建议设一个,服务器之间自动化调用可以不设。

把公钥传到服务端,最省事的方式是用ssh-copy-id:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@192.168.x.x

这条命令会自动把公钥追加到服务端的~/.ssh/authorized_keys文件,并处理好权限。如果系统里没有ssh-copy-id,也可以手动复制公钥内容,然后登录服务端粘贴进authorized_keys,但一定要记得改权限:

chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys

权限不对是密钥登录失败的头号原因。SSH 对权限极其敏感,authorized_keys如果是 644 甚至 777,服务端会直接拒绝使用它,而且日志里往往只给一句模糊的提示,让人摸不着头脑。

4.2 配置持久化:别让重启毁掉你的成果

很多人配好之后能用,一重启就回到解放前。原因通常是配置没写进文件,或者服务没设开机自启。要保证持久化,记住两件事:

第一,所有对sshd_config的修改都要写进文件并保存,改完执行sudo systemctl reload ssh。临时用命令行参数启动的方式不会持久。

第二,确认服务开机自启:

sudo systemctl is-enabled ssh

返回enabled才算稳。如果是disabled,执行sudo systemctl enable ssh补上。

另外,如果你改了端口或监听地址,建议改完后先用sshd -t做一次配置语法检查:

sudo sshd -t

这个命令只检查配置文件的语法,不实际启动服务。如果配置写错了,它会直接告诉你哪一行有问题。这个习惯能帮你在 reload 之前就发现错误,避免把正在运行的服务搞挂。

4.3 安全收尾:几个不折腾但有效的加固动作

远程访问能用之后,花几分钟做点基础加固,能挡掉大量自动化扫描和暴力尝试。以下动作都不复杂,但效果明显。

第一,禁用 root 密码登录。在sshd_config里确保:

PermitRootLogin prohibit-password

这样 root 只能用密钥登录,密码爆破对 root 就无效了。

第二,考虑改默认端口。把 22 改成比如 2222,能减少大量无差别扫描。改端口本身不是强安全措施,但能显著降低日志噪音。改完记得同步更新防火墙规则和客户端的连接命令。

第三,限制登录用户。如果这台机器只给特定人用,加一行:

AllowUsers yourname

只允许指定用户登录,其他账号一律拒绝,简单粗暴但有效。

第四,装个fail2ban自动封禁反复失败的 IP:

sudo apt install fail2ban -y

它默认就会监控 SSH 日志,多次失败后自动临时封禁来源 IP。对暴露在较大网络里的机器,这个工具性价比极高。

提示:每次改完sshd_config,都先sudo sshd -t检查语法,再sudo systemctl reload ssh。养成这个顺序,能避免把自己锁在门外。如果真锁了,还能通过本地终端或带外管理进去救回来。

5. 那些文档里不写、但实际一定会遇到的坑

5.1 连接超时和连接被拒绝是两码事

这两个报错经常被混为一谈,但指向的问题完全不同。Connection refused说明包到了目标机器,但目标端口没有服务在监听,问题在服务端。Connection timed out说明包根本没得到回应,问题在中间网络或防火墙,可能是路由不通、防火墙丢包、或者目标机器压根没开机。

排查方向因此完全不同:refused 去查 sshd 状态和监听地址,timed out 去查网络连通性和防火墙。搞混这两个,会在错误的方向上浪费大量时间。

5.2 改了端口之后,客户端和防火墙都要同步

改端口是个连锁操作,涉及三处:服务端sshd_config的Port、防火墙放行规则、客户端的连接命令。任何一处没改,都会连不上。我建议改端口时按这个顺序:先改配置、再放行防火墙、reload 服务、最后用新端口测试。测试通过之前不要关掉旧端口的放行规则,留一条后路。

5.3 虚拟机、容器和云主机的差异要心里有数

同样是 Ubuntu 20.04,跑在物理机、虚拟机、容器和云主机上,SSH 配置的注意点不一样。虚拟机要注意网络模式,容器要注意 sshd 是否真的在容器内运行以及端口映射,云主机要注意平台层面的安全组规则——这个规则在系统防火墙之外,很多人只改了ufw却忘了安全组,结果怎么都连不上。

判断方法:如果本机ssh localhost能通,但外部连不上,且系统防火墙已放行,那大概率是平台层面的网络策略在拦。这时候要去平台控制台检查安全组或网络 ACL。

5.4 日志是你最好的朋友

遇到任何连不上的问题,第一反应应该是看日志,而不是反复试。服务端日志通常在:

sudo journalctl -u ssh -n 50

或者直接看/var/log/auth.log:

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

客户端加-v参数也能看到详细的握手过程:

ssh -v user@192.168.x.x

-v可以叠加成-vv、-vvv,信息越来越详细。握手卡在哪一步、用了哪种认证方式、服务端返回了什么,全都看得见。学会读这些输出,排查效率会提升一个档次。

6. 一套可复用的检查清单与我的实际体会

把上面所有内容浓缩成一套开机即用的检查顺序,下次再遇到远程连不上,按这个顺序走一遍,基本都能定位:

  1. 服务端systemctl status ssh是否 running
  2. ss -tlnp | grep sshd监听地址和端口是否正确
  3. sshd_config里认证方式、用户限制是否符合预期
  4. ufw status防火墙是否放行对应端口
  5. 两台机器能否互相 ping 通
  6. 平台层面(虚拟机网络模式、云安全组)是否有额外限制
  7. 看journalctl或auth.log确认服务端到底报了什么

这套顺序的逻辑是从内到外、从服务到网络,先确认本机服务没问题,再往外一层层排查。反过来从外往里查,容易在没问题的环节上反复折腾。

我自己配过很多台 Ubuntu 20.04 的远程访问,踩过的坑里印象最深的有两个。一个是密钥登录怎么都不行,查了半天发现是authorized_keys权限被同步工具改成了 664,SSH 直接拒绝使用;另一个是云主机上系统防火墙放行了但安全组没放行,白白折腾了一个多小时。这两个坑的共同点是:问题不在你正在看的地方。所以排查时一定要有全局视角,别死磕一个环节。

最后分享一个提高效率的小习惯:把常用的连接配置写进客户端的~/.ssh/config文件,比如:

Host devbox HostName 192.168.x.x User yourname Port 2222 IdentityFile ~/.ssh/id_ed25519

配好之后,直接ssh devbox就能连,不用每次敲一长串参数。机器多了之后,这个文件的价值会越来越明显。远程访问这件事,配一次、稳很久,前期多花二十分钟把细节做对,后面能省下无数次的重复排查。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进