systemd服务报203/EXEC或200/CHDIR

程序在终端里能运行,交给 systemd 却立即退出,常见原因是服务使用了不同的账户、工作目录或环境。先分清失败阶段,再改对应一处配置,通常比反复重启更快。

适用范围:使用 systemd 管理的 Linux 系统服务。下文的 demo.service、目录和程序名均为示例,需替换为实际值;日志查看需要相应权限,配置修改与重启应由有权限的管理员安排。

拿到完整的失败阶段

systemctl status demo.service --no-pager -l
journalctl -u demo.service -b -n 60 --no-pager
systemctl show demo.service -p FragmentPath -p DropInPaths -p User -p Group -p ExecStart -p WorkingDirectory

关注最近一次启动时间附近的 Failed at step CHDIR 或 Failed at step EXEC。前者对应 200/CHDIR,表示切换工作目录失败;后者对应 203/EXEC,表示执行程序失败。单独一个数字也可能由应用主动返回,要结合日志阶段判断。进程参数和应用日志可能含敏感信息,只在本机核查,转交时删去令牌、密码及客户数据。

200/CHDIR:从目录逐层向上查

先核对 WorkingDirectory 是否拼错、目录是否被移动、相关挂载是否就绪。再按 User 和 Group 确认服务实际身份;不要拿管理员终端的访问结果代替服务账户的权限。

进入一个目录需要沿途每一级目录允许该账户遍历,即目录的执行权限;仅给最后一级目录加权限可能仍然失败。系统装有 namei 时,可用 namei -l /opt/demo 辅助查看各级目录,涉及 ACL 时还应检查实际 ACL。若配置了根目录或文件系统隔离,要从服务看到的目录结构判断,不能只看宿主机路径存在。

203/EXEC:文件存在还不够

核对 ExecStart 第一个参数指向的文件、符号链接目标和可执行权限。建议使用明确的绝对路径;如果执行的是脚本,还要检查首行解释器是否存在、是否带 CRLF 回车,以及运行账户能否读取脚本。解释器或二进制加载器缺失,也可能让一个看似存在的文件报“找不到”。

若日志指向权限拒绝,再检查目录权限、挂载的 noexec、SELinux 拒绝记录及服务自身隔离设置。修正文件位置或必要的精确权限,不要为了试通关闭安全策略、取消整组沙盒选项,或把服务改成高权限账户。

ExecStart 不是交互式 Shell 命令行,|、&& 和重定向不会自动按 Shell 语法执行。服务也不应依赖用户登录时设置的 PATH。复杂启动逻辑宜写入可审查的脚本,确认解释器后调用;不要把终端里的一整串命令直接粘进去。

只修已确认的一处,再检查业务

假设已确认工作目录和程序路径写错,可先保存当前配置与相关 drop-in 文件,再用 systemctl edit demo.service 编辑覆盖配置。下面仅演示写法:务必保留原服务实际需要的参数,不要照抄示例路径。

[Service]
WorkingDirectory=/opt/demo
ExecStart=
ExecStart=/opt/demo/bin/worker --config /etc/demo/worker.conf

空的 ExecStart= 用于清空原命令列表,再设置替换命令;直接叠加另一条可能使普通服务配置无效。完成后重新加载配置,并在允许中断业务的时间重启:

systemctl daemon-reload
systemctl restart demo.service
systemctl status demo.service --no-pager -l
journalctl -u demo.service -b -n 30 --no-pager

确认新启动没有相同失败,再检查该服务的监听、健康检查或实际任务结果;显示 active 不代表业务已正常。如果修改无效,只恢复本次编辑前保存的文件;新建的覆盖文件只撤销本次内容,保留既有覆盖配置,然后重新加载并按原运行状态处理服务。不要用批量清除覆盖配置代替回退。

延伸阅读