下面方法适用于主流 systemd Linux 发行版。示例里的
nginx.service 请替换成实际服务名;Docker 容器、云镜像初始化脚本、发行版自带服务可能还有自己的管理方式,需要同时确认。
Table of Contents
Toggle
- 一、先区分“没有启用”和“启动失败”
- 二、用 systemctl 找最近一次失败原因
- 三、检查 unit 文件来源,不要直接改软件包文件
- 四、依赖和启动顺序不要混为一谈
- 五、检查 Type、ExecStart 和 Restart 的常见误区
- 六、配置变更后重新加载,再做重启验收
- 七、把处理顺序固定下来
- 参考资料
一、先区分“没有启用”和“启动失败”
登录服务器后先执行两条命令:
systemctl status nginx.service
systemctl is-enabled nginx.servicestatus 看当前状态、PID、退出码和最近日志;is-enabled 只回答 unit 是否配置为开机加载。常见输出有四种:enabled 表示已创建开机启动链接;disabled 表示没有设置开机自启;static 表示 unit 通常由其他 unit 或定时器拉起;masked 表示 unit 被屏蔽,systemd 拒绝启动它。如果
is-enabled 返回 disabled,先确认这个服务确实应该开机启动,再执行 sudo systemctl enable nginx.service。enable 只处理开机链接,通常不会立即启动服务。确认配置可以启动时,才使用 sudo systemctl enable --now nginx.service,因为 --now 会立即启动服务。二、用 systemctl 找最近一次失败原因
服务已经
enabled,重启后却不在运行,重点看失败线索:systemctl status nginx.service
systemctl list-units --state=failed
journalctl -b -u nginx.service --no-pagerstatus 里重点记录 Active、Process、since 和日志末尾,用来区分失败发生在开机阶段还是运行中,并确认退出码、信号、配置路径、权限、端口、证书或依赖错误。排查整机启动阶段时,可以再按错误级别过滤:journalctl -b -p err --no-pager日志里出现配置文件路径、端口占用、证书过期、权限不足、上游目录不存在、依赖地址连不上,都比反复重启服务有价值。
三、检查 unit 文件来源,不要直接改软件包文件
确认服务实际加载了哪份配置:
systemctl cat nginx.service
systemctl show nginx.service -p FragmentPath -p DropInPaths -p After -p Wants -p RequiresFragmentPath 是主 unit 文件,DropInPaths 是覆盖片段。发行版包常把 unit 放在 /usr/lib/systemd/system/,软件包升级可能覆盖这里的修改。自建服务适合放在 /etc/systemd/system/example.service;对软件包服务做少量覆盖,更适合使用 sudo systemctl edit nginx.service 创建 drop-in。例如让服务等待网络目标并调整重启间隔,可以在编辑器中加入类似配置:
[Unit]
Wants=network-online.target
After=network-online.target
[Service]
Restart=on-failure
RestartSec=5保存后必须执行
sudo systemctl daemon-reload,再执行 sudo systemctl restart nginx.service 验证。修改前保留原配置或 drop-in 备份;出问题时删掉新增片段、重载配置,再按原配置启动,就能回到修改前状态。四、依赖和启动顺序不要混为一谈
Wants=、Requires= 和 After= 经常被一起写,但含义不同。Wants= 会尝试拉起依赖,依赖失败时本服务仍会启动;Requires= 是强依赖,依赖失败会带动本服务失败;After= 只定义顺序,不会自动拉起依赖。要让应用等待网络就绪,通常至少同时有
Wants=network-online.target 和 After=network-online.target。应用依赖远端数据库时,只写 After=postgresql.service 也可能不够,因为数据库 unit 变为 active 不代表业务端口已可接受连接,应用自身还需要重试或启动前检查。查看依赖关系:
systemctl list-dependencies nginx.service
systemctl list-dependencies nginx.service --reverse依赖越强,故障传播范围越大。不要为了看起来稳妥给每个服务都加
Requires=;生产机上更可靠的做法是明确网络、存储、数据库的真实启动条件,并让应用在临时失败时按 Restart=on-failure 与合理间隔重试。五、检查 Type、ExecStart 和 Restart 的常见误区
自建服务的启动失败常和这几项有关:
systemctl show example.service -p Type -p ExecStart -p Restart -p RestartSec -p User -p WorkingDirectoryType=simple 只要把进程 fork 出去,systemd 就可能继续后续启动流程;主进程二进制不存在、脚本解释器错误、启动即退出,仍可能在之后才暴露。能用 Type=exec 时,它会更明确地等待执行阶段完成。运行一段命令后退出的初始化任务适合 Type=oneshot。Restart= 决定失败后的行为。no 表示不自动拉起;on-failure 表示非零退出触发重启;always 连正常退出也会重启,适合需要长期驻留的进程。RestartSec= 设置间隔,避免进程每秒反复崩溃刷日志。如果服务由 Docker 管理,还要区分两层:容器重启由 Docker restart policy 控制,宿主机 Docker daemon 由 systemd 控制。两层同时做“开机后自动执行脚本操作容器”时,容易产生重复启动或权限问题,需要确认服务归属。
六、配置变更后重新加载,再做重启验收
修改 unit、drop-in 或服务配置后,流程建议固定为:
sudo systemctl daemon-reload
sudo systemctl restart nginx.service
systemctl status nginx.service
journalctl -u nginx.service -n 100 --no-pager仅执行
enable 不会让修改后的 unit 立即生效;仅改文件不执行 daemon-reload,systemd 也可能继续使用旧定义。Nginx 等能离线检查配置的软件,先执行自身语法检查,再交给 systemd。修复后至少验证一次真实重启。重启前确认控制台、带外管理或备用 SSH 入口可用,避免把管理链路也依赖到本次调整的服务上。重启完成后检查:
systemctl is-enabled nginx.service
systemctl is-active nginx.service
journalctl -b -u nginx.service --no-pager需要隔离启动目标做验证时,先确认目标含义和影响,例如
sudo systemctl isolate multi-user.target。这条命令会停止不属于目标的服务,风险比查看命令高,不应在未评估业务影响的生产机上直接执行。七、把处理顺序固定下来
遇到服务器重启后服务没有自动启动,按顺序收集四类信息:
is-enabled 的启用状态,status 的失败状态和退出码,journalctl -b -u 的本次开机日志,systemctl cat/show 的实际 unit 与依赖。确认原因后再启用服务、修改 drop-in、调整依赖顺序或重启策略,最后通过一次真实重启验收。不要直接修改
/usr/lib/systemd/system/ 下的软件包 unit;不要在生产机上无备份地堆叠 Requires=;也不要把 enable --now 当成万能修复。开机自启的可靠性来自明确的启动条件、可观察的失败日志,以及重启后能复现并验证的处理结果。参考资料
- systemctl(1) – Arch Linux Manual Page
- systemd.service(5) – Arch Linux Manual Page
- journalctl(1) – Linux man-pages