服务起不来时,systemctl status 只是起点:五步定位法
写了个 unit 文件,systemctl start 之后立刻 inactive,status 里只有一句「Failed with result 'exit-code'」。这时候最容易做的是反复重启,而不是看日志。
systemd 的错误分四类:程序自己退出、权限不足、环境变量缺失、依赖未就绪。四类的日志位置不同。
先说结论
先 journalctl -u 服务名 -n 50,再看 unit 文件的三个高危字段:ExecStart 路径、WorkingDirectory、User。
- journalctl -u xxx -n 50 --no-pager 看真实报错
- systemctl cat xxx 核对 unit 内容
- 前台手动跑一遍 ExecStart 的命令
- 检查 User/Group 与目录权限
- 确认端口没被占、依赖服务已就绪
先把问题说清楚
systemd 不读你的 shell 环境(.bashrc 里的 PATH、代理都不生效),所以「我手动能跑」和「服务起不来」经常同时成立。
Type=simple 时 systemd 认为进程一启动就是就绪,如果程序需要几秒初始化,要配 Type=notify 或加 ExecStartPre 等待。
具体怎么做
按顺序执行,每步都验证完再进下一步:
- journalctl -u 服务名 -n 50 --no-pager 读最近的日志
- systemctl cat 服务名 检查 ExecStart/WorkingDirectory/User/Environment
- 把 ExecStart 的命令复制出来,用相同用户手动执行(sudo -u www -i)
- 检查目录属主与 SELinux/AppArmor 是否拦截
- ss -lntp 确认端口占用;对依赖型服务用 After=/Requires= 明确顺序
参数与成本对照
把关键数值摊开,方便判断该选哪条路:
| 现象 | 常见原因 | 处理 |
|---|---|---|
| status 显示 exit-code | 程序自身报错退出 | journalctl 看 stderr |
| Permission denied | User 与目录属主不一致 | chown 或用正确用户启动 |
| command not found | PATH 里没有该命令 | ExecStart 写绝对路径 |
| 启动超时 | Type 与实际不符 | 改 Type=notify 或加 TimeoutStartSec |

几个容易踩的坑
下面这些是最常见的错误做法:
- 只反复 restart:日志会滚掉,反而丢了证据
- 在 .bashrc 里 export 变量指望 systemd 读到
- 用 root 跑一切:出问题更难定位
- 改完 unit 不 daemon-reload,改动不生效
最后补两句
把「手动能跑但服务不行」当成常态去排查环境差异,是最快的路径:差异只有用户、环境变量、工作目录三项。
工具是手段,理解机制才是能力。命令记不住没关系,知道「该看什么」就够了。
评论 (3)
照着做了一遍,确实少走弯路。第二步最容易漏,建议顺手加个检查清单。
比「一键脚本」有用多了,知道为什么比知道怎么做重要。
补充一句:不同版本行为会变,动手前先确认自己的版本号。
发表评论