ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Unit ssh.service not found 排查:从 systemd 到 SSH 连接的全链路修复

Unit ssh.service not found 排查:从 systemd 到 SSH 连接的全链路修复 1. 先搞清楚报错在说什么unit 文件与找不到服务的真实原因“unit ssh.service not found” 这句话刚出现的时候确实很容易把人带偏总觉得是 ssh 服务出了问题。但实际上 systemd 告诉你的是一个更底层的事实整个系统里根本没有注册过叫ssh.service的服务单元文件。这就好比你想打开一个软件系统却提示“快捷方式不存在”问题是出在入口不一定是软件本身坏了。1.1 systemd 查找服务的路径与 unit 文件检索逻辑systemd 查找服务靠的是一个叫 unit 文件的东西。每个受 systemd 管理的服务在磁盘上都对应一个.service文件比如/lib/systemd/system/ssh.service里面写着服务怎么启动、ExecStart 是什么、要不要开机自启。当你在终端敲systemctl status ssh或systemctl restart ssh的时候systemd 做的事就是按顺序去几个固定目录里翻有没有叫ssh.service的文件。这些目录有优先级之分/etc/systemd/system/管理员手动放进去的优先级最高/run/systemd/system/运行时生成的优先级其次/lib/systemd/system/软件包安装时自带的标准单元目录优先级最低如果apt install openssh-server真的成功装好了那么在/lib/systemd/system/下一定会有ssh.service。所以当你看到 “Unit ssh.service not found” 时第一反应不应该是“服务挂了”而应该是“服务可能压根没装或者装的过程中出了问题”。另外还有一个容易忽略的点Ubuntu 沿用了 Debian 的 upstart 时代习惯早期用service ssh start这种命令也能启动服务。现在的 Ubuntu 里service命令实际上是一个兼容层最终会调用systemctl所以如果你敲service ssh start得到了ssh: unrecognized service和unit ssh.service not found是同一个问题只是表达方式不同。1.2 Ubuntu 里“ssh”和“sshd”服务名为何不统一这里还要说一个坑了无数新手的细节网上搜到的教程有的写systemctl start sshd有的写systemctl start ssh还有人搜到了 CentOS 的教程里面用的是ssh.service。其实这俩在很多发行版上的确不一样。CentOS/RHEL 系列的服务名是sshd.service因为对应二进制是/usr/sbin/sshd。而 Debian/Ubuntu 的 openssh-server 包安装后注册的 systemd 服务名是ssh.service虽然它调用的二进制同样是/usr/sbin/sshd。这意味着同一条命令在 Ubuntu 里可能是废的sudo systemctl status sshd大概率会得到这样的输出Unit sshd.service could not be found.如果你把标题里的报错原封不动地理解为 sshd 不存在那就更有意思了其实sshd二进制就在/usr/sbin/sshd里可 systemd 不买账因为它找的是sshd.service这个单元文件名而不是可执行文件。所以排查的第一课就是先分清你是在说服务名还是在说二进制程序。2. 从零排查服务端80% 的“not found”是因为根本没装好回到这个报错本身我强烈建议用最朴素的办法开始直接问 aptopenssh-server 到底装没装。很多云服务器镜像、精简版 Ubuntu、WSL 默认环境其实都没有安装 OpenSSH 服务端只有客户端。ssh命令能连别人的机器和你的机器能被别人连上那是两码事。2.1 用 dpkg/apt 三步确认安装状态最直接的方式dpkg -l | grep openssh-server如果输出为空说明这个包根本没进入你的系统。也可以用 apt 的查询方式apt-cache policy openssh-server注意看输出里的 “Installed” 字段。如果是(none)那就实锤了没装。还有一种“装了但坏了一半”的情况比如依赖破损、安装中断dpkg 输出里会出现rc状态意思是被删除但配置文件残留。这时候需要重新安装sudo apt --reinstall install openssh-server如果是因为 apt 源问题装不上我建议先换到官方源或者你所在网络环境能稳定访问的镜像源再执行sudo apt update sudo apt install openssh-server -y有很多人在这一步遇到 “unable to locate package”这个往往是apt update之后索引里没有对应包特别是刚装完的 Ubuntu 22.04/24.04 从来没跑过 update。千万别跳过 update 直接 install。2.2 安装之后确认正确的服务名和 socket 状态装完之后不要急着连先看一眼服务注册情况systemctl list-unit-files | grep ssh你会看到一类输出ssh.service enabled ssh.socket enabled这里就引出 Ubuntu 21.10 之后一个很关键的机制默认情况下 SSH 走的是 socket 激活。意思是 systemd 先开一个ssh.socket等到有客户端来连 22 端口的时候才真正把ssh.service拉起来。所以在刚装完的环境里你敲systemctl status ssh很可能是 inactivedead但这不代表服务有问题。真正在监听端口的是 socket 单元。我这里插一句话如果你习惯的是传统的一直挂后台的常驻服务可能会对 socket 激活不太适应。但它确实有一个好处——没连接时不白白占内存和进程资源。接下来如果你的需求是“改端口后仍能正常连”socket 激活反而是个坑后面我会单独说。确认完 unit 文件之后顺手把这些做了sudo systemctl enable --now ssh.socket sudo systemctl enable --now ssh在比较新的 Ubuntu 上enable --now ssh其实会自动 disable 掉 socket 激活转为传统模式这样ssh.service会一直在运行状态。两种方式都能连但理解它们的差别后面排错才不会懵。2.3 没有 systemd 的环境WSL 与容器场景的特殊处理说个更容易踩的实际场景Windows 里的 WSL Ubuntu或者在 Docker 容器里。标题里的systemctl在这两个环境中经常很尴尬。特别是 WSL 旧版本内核里根本没有跑 systemd你敲systemctl status ssh会看到类似System has not been booted with systemd as init system (PID 1). Cant operate.的提示。在 WSL 里要跑 SSH 服务常见做法是sudo service ssh start前提也得是openssh-server已经安装。如果你用的是新版 WSL并且已经在/etc/wsl.conf里开启了 systemd[boot] systemdtrue那么在 WSL 里systemctl status ssh就能正常工作了。这个配置需要wsl --shutdown重启 WSL 才生效直接关终端窗口往往没用。容器场景下很多基础镜像比如ubuntu:24.04默认连 systemd 都不跑因为容器理念就是单进程。这时候强行启用 systemd 属于和设计思路对着干。更好的做法是判断自己到底需要“常驻 sshd 进程”还是“走容器编排去管理端口暴露”如果是前者可以写个 entrypoint 手动启动/usr/sbin/sshd -D但这句话和 systemd 服务已经没关系了。3. 找到服务不代表能连上端口、配置、防火墙逐层排雷服务名对了、systemctl 也显示 active 了不代表就能连上。很多人修复到这一步兴冲冲地在远程电脑上敲ssh userip结果要么卡住不动要么被拒绝。接下来要把“服务端在跑”和“客户端能连上”中间的几道门全部打开。3.1 服务进程与端口监听状态检查先确认 sshd 有没有真的在监听 22 端口sudo ss -tlnp | grep ssh看到的输出大概是这样LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:((sshd,pid1234,fd3))如果ss命令不存在可能是 net-tools 没装全。也可以用sudo apt install net-tools sudo netstat -tlnp | grep 22这一步的目标是确认“进程在 端口在 地址没绑错”。如果看到 sshd 只监听了127.0.0.1:22说明/etc/ssh/sshd_config里的ListenAddress被改过或者默认配置有问题。只监听回环地址的话外部网络永远连不进来但服务又确实活着这种情况相当迷惑。修改监听地址的方式是在/etc/ssh/sshd_config中这样写ListenAddress 0.0.0.0然后重启服务。3.2 sshd_config 里的三个关键配置项SSH 服务端配置集中在/etc/ssh/sshd_config里。这里不建议为了省事直接sed乱替换我建议用nano或vim打开细心看一遍因为改错一个地方服务起不来还算好的更严重的是把自己锁在门外。第一个要确认的是Port。默认是 22 没问题如果你想改成别的端口比如 2222改完服务端之后要注意Ubuntu 22.04 及以上如果 ssh.socket 还处于启用状态端口只改 sshd_config 是无效的。因为 socket 激活时真正开端口的是ssh.socket单元它自己的文件里有ListenStream22。你让sshd_config改成 2222socket 层不听。最终结果往往是你发现 22 和 2222 都被监听一片混乱。我的建议是如果你打算用自定义端口干脆把 socket 单元停用掉彻底回到传统模式sudo systemctl disable --now ssh.socket sudo systemctl enable --now ssh.service然后改/etc/ssh/sshd_config里的Port 2222。如果你又想保留 socket 激活那就得改/etc/systemd/system/ssh.socket.d/下的 override 文件设置新的ListenStream这比前者复杂不值得为默认场景去折腾。第二个要确认的是PermitRootLogin。默认值是prohibit-password意思是 root 可以用密钥登录但禁止密码登录。很多新手在云服务器上习惯用 root 账号结果密码输对了还被拒。如果你确定要用密码登录可以改成PermitRootLogin yes但强烈建议生产环境用密钥登录而不是放开密码。把 root 密码登录打开意味着暴力破解的靶子变成公开的了。第三个是PasswordAuthentication。如果这个值是no哪怕你用户密码正确SSH 也不会给你密码登录的机会。它只认密钥。有的云镜像为了安全默认就是no。你在本机想用密码登录时会一直被拒这种“配置看起来没问题但就是连不上”的情况十有八九是这个值在起作用。改完配置一定要先做语法检查再重启sudo sshd -t如果有输出错误会直接告诉你哪一行写错了。没有任何输出说明语法通过。然后sudo systemctl restart ssh稳妥一点的话我还建议你在当前会话里开两个终端一个用来测试连接一个留着兜底。重启 ssh 并不会断掉已建立的连接但如果前面 nftables、防火墙步骤没做对新连接会连不上。3.3 ufw 与外部网络对连接的影响Ubuntu 桌面版默认会带有 ufw服务器版不一定默认启用。可以用下面命令查看sudo ufw status verbose如果状态是inactive恭喜你没有本机防火墙挡路。但这里还有一种情况就是云服务器的控制台里另有一层安全组或者防火墙规则这和 Ubuntu 内部的 ufw 完全是两码事。本地 ufw 放行了云控制台那层没放行照样连不上。如果你打开了 ufw那就显式放行 SSH 端口sudo ufw allow ssh sudo ufw enable注意如果之前没开过 ufwsudo ufw enable这一步会应用所有已有规则有可能把当前正在用的连接也断掉。所以在云服务器上操作时最好先在控制台确认自己能通过 VNC 或 web 终端访问再执行开启命令。有人说用 iptables 更底层但实际上 ufw 只是封装了 iptables/nftables。对一个日常运维场景来说ufw 的规则已经足够。还有一点容易被忽略如果你改了端口到 2222记得要执行sudo ufw allow 2222/tcp而不是只 allow ssh。外部网络连通性的判断可以用本机和远端两步来确定本机也就是 SSH 服务器自己执行ssh userlocalhost -p 22用来排除服务端自身的问题在另一台机器上执行ssh -vvv user服务器IP -p 22用 verbose 输出看卡在哪一步-vvv是个极好用的调试手段。它会把密钥协商、认证尝试的过程全部打出来。如果输出卡在Connection timed out问题在网络层如果出现Connection refused说明端口没人监听如果出现Permission denied说明服务正常但认证有问题。4. 动手复现一次完整修复从报错到连上的全过程记录前面把原理和要点都铺垫得差不多了下面我用一个真实场景把整个流程串一遍。这个场景就是标题本身一台刚装好的 Ubuntu Server 22.04其他机器 SSH 连不上登录到本机一看systemctl status ssh直接报 “Unit ssh.service not found”。4.1 复现环境与初始状态我先说环境一台安装 Ubuntu Server 22.04 的虚拟机安装时选择的是最小化安装没有勾选 OpenSSH server。虚拟机网络是 NAT 模式主机上有另一台 Linux 机器准备去连接它。起初在服务器本机执行sudo systemctl status ssh输出Unit ssh.service not found.执行service ssh status也是类似ssh: unrecognized service这就是博文标题里那个报错最完整的现场。4.2 逐条执行的排查命令与现象第一步是确认包状态dpkg -l | grep openssh-server没有任何输出。再用 apt 查apt-cache policy openssh-server | head -5输出显示Installed: (none)。确认原因后安装sudo apt update sudo apt install openssh-server -y安装完成后再确认systemctl list-unit-files | grep ssh此时能看到ssh.service和ssh.socket了。接着把两者都启用sudo systemctl enable --now ssh.socket sudo systemctl enable --now ssh.service然后看监听状态sudo ss -tlnp | grep ssh输出为LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:((sshd,pid1342,fd5))到这里服务端已经在 22 端口监听了。第二步检查配置。我打开/etc/ssh/sshd_config检查关键项Port 22 PermitRootLogin prohibit-password PasswordAuthentication yes因为这台测试机用的是普通用户PasswordAuthentication yes是能连上的关键。如果它是no必须准备密钥否则密码再对也没戏。第三步检查 ufwsudo ufw status verbose这台虚拟机里 ufw 是 inactive所以没有影响。第四步回到客户端机器上执行ssh -vvv ubuntu192.168.x.x日志最终出现Authenticated to 192.168.x.x ([192.168.x.x]:22)连接成功。4.3 修改配置并验证连接在此基础上我又模拟了把端口改成 2222 的过程用来验证 socket 激活的坑。先修改/etc/ssh/sshd_configPort 2222然后重启服务sudo systemctl restart ssh此时再看端口监听墙裂推荐你亲手试试这个操作因为它会上演一出“你以为改了配置实际没完全生效”的好戏ssh.service 由于 socket 激活的特性真正监听的端口仍然被ssh.socket控制。如果你没有停用 socket那么 22、2222 很可能同时被监听。处理方式一劳永逸前面已经提过先停用 socketsudo systemctl disable --now ssh.socket sudo systemctl enable --now ssh.service sudo systemctl restart ssh再执行sudo ss -tlnp | grep ssh输出变为LISTEN 0 128 0.0.0.0:2222 0.0.0.0:* users:((sshd,pid1701,fd3))最后在客户端连接测试ssh -p 2222 ubuntu192.168.x.x能正常登录。5. 踩过的坑整理高频连接失败问题速查表这一节我在不同环境里反反复复遇到过写成表方便以后直接对照。这里的每一条都是我实际被坑过的不是从文档上抄来的。报错或现象根本原因推荐处理Unit ssh.service not foundopenssh-server 未安装apt install openssh-serverUnit sshd.service not found服务名不对Ubuntu 用的是 ssh 不是 sshd用ssh而非sshdssh: unrecognized service和上面同根只是走 service 命令查询安装 openssh-server 即可Connection refusedsshd 没在监听或端口不对ss -tlnp确认端口Connection timed out安全组未放行或 IP 不通检查云安全组和网络连通性Permission denied (publickey)PasswordAuthentication no或密钥不对检查 PasswordAuthentication、密钥路径root 密码正确但无法登录PermitRootLogin 值为 prohibit-password 或 no按需改为 yes最好改用密钥改完 sshd_config 的 Port 后 22 仍监听ssh.socket 未关闭socket 单元独立控制端口disable ssh.socket用 ssh.serviceSystem has not been booted with systemd在 WSL/容器里没有 systemd PID 1启用 WSL systemd或直接用 service 命令5.1 客户端日志定位问题阶段排查连接问题最有用的命令就是客户端日志。记住这几个关键字能快速定位。ssh -vvv userip -p 端口日志里出现Connecting to ...之后就卡住通常是 TCP 层超时。这时候别在 SSH 配置上浪费精力先把 IP 通了。ping 不通就先看路由和防火墙。日志里出现Connection established说明 TCP 没问题接下来看密钥交换。出现kex_exchange_identification: Connection closed by remote host时往往是 ssh 服务端握手的时候挂了排查点一般在 sshd_config 有没有明显语法问题或者服务正在重启窗口期。日志走到Authentication methods that may continue时认证阶段才开始。这里最常见的是publickey失败或者password不在允许列表。要不要启用密码登录一切以/etc/ssh/sshd_config里的PasswordAuthentication为准。5.2 修改配置后的存活保障技巧改 SSH 配置是有可能把自己锁在门外的尤其你人在远程。我有几个固定的保命习惯第一改完配置后不要立刻关闭现有终端。在新终端里测试连接等确认能连上再关掉旧的。第二如果sshd -t检查语法通过但还是不放心可以这样启动一个临时额外实例sudo /usr/sbin/sshd -D -p 2222 -f /etc/ssh/sshd_config这会启动一个前台运行的 sshd监听在 2222 端口。如果这台机器本身 22 端口配置已经坏了用这个临时实例连进来也能有退路。测试完按 CtrlC 停掉它即可。这个技巧救过我很多次。第三root 环境下的/root/.ssh/authorized_keys权限和属主必须正确。很多人复制公钥过去却忘了权限问题SSH 会直接拒绝这个文件。错误的表现是日志里出现Authentication refused: bad ownership or modes。修复方式chmod 700 /root/.ssh chmod 600 /root/.ssh/authorized_keys chown root:root /root/.ssh -R普通用户同理用户主目录权限如果太宽松也可能被拒。5.3 端口被占用时的应急处理有时候你启动 sshd发现 22 端口被别的进程占用了。常见的元凶是另一个 sshd 实例或者像是 node、frp 这类工具占了端口。先看谁占着sudo lsof -i :22 sudo ss -tlnp | grep :22确认是 sshd 在跑可能是 socket 激活和 service 同时造成的重复监听。这时候把 ssh.socket 停掉就好。如果占用的确实不是 sshd那就得权衡要么杀掉占用进程要么给 SSH 换端口。如果你想把 ssh 绑到非标准端口最稳的流程是修改/etc/ssh/sshd_config里的Port执行sudo sshd -t执行systemctl stop ssh执行systemctl disable --now ssh.socket执行systemctl start ssh检查ss -tlnp | grep ssh我建议把 disable ssh.socket 放前面不然你很容易看到端口没按预期变化。再说一下我把这些内容放在一起的原因这台服务器最后还要处理 sshd 的 Daily 任务和日志切割但那些都是锦上添花。最核心的东西无非就是三件事——服务没装就装、装好后端口要通、认证配置要允许你要用的方式。你把这三件事按顺序过一遍百分之九十的 “unit ssh.service not found” 或连接失败问题都能解决。我自己排查的时候从来不急着搜报错原文去找“一条命令搞定”的偏方而是用这个顺序一层层往下挖踩过的坑越多越觉得系统化排查比零散技巧靠谱得多。
返回列表