Linux服务启动失败,systemctl status 显示 code=exited, status=200/CHDIR,意味着systemd还没有真正运行 ExecStart 中的程序,就在切换工作目录时失败。systemd手册将退出码200定义为 EXIT_CHDIR,对应 WorkingDirectory= 处理失败。
200/CHDIR与203/EXEC不是同一个阶段。 前者先检查工作目录,后者才重点检查可执行文件;盲目替换程序或调整应用参数不会解决目录切换失败。

读取真正生效的WorkingDirectory
先查看状态、日志和合并后的单元文件:
sudo systemctl status example.service --no-pager -l
sudo journalctl -u example.service -b -n 100 --no-pager
sudo systemctl cat example.service
再读取systemd解析后的属性:
sudo systemctl show example.service \
-p FragmentPath -p DropInPaths -p WorkingDirectory \
-p User -p Group -p RootDirectory -p RootImage
供应商单元、管理员drop-in和运行时覆盖可能同时存在。应以 @@HTMLTOKEN0@@ 与 @@HTMLTOKEN1@@ 的输出为准,不能只检查你最后编辑的那一个文件。 修改单元后还需运行 sudo systemctl daemon-reload 才会重新加载。
核对目录存在与逐级访问权限
假设生效值为 /srv/example/current,先检查路径与每一级目录权限:
sudo namei -l /srv/example/current
sudo stat /srv/example/current
sudo -u example test -d /srv/example/current
printf 'directory-exists=%s\n' "$?"
sudo -u example test -x /srv/example/current
printf 'directory-searchable=%s\n' "$?"
切换目录不仅要求最后一级存在,服务用户还需要须拥有每一级父目录的搜索权限。部署工具更新软链接时,也要检查链接目标是否已经切换到不存在的版本目录。
不要对 @@HTMLTOKEN0@@ 或应用目录执行 @@HTMLTOKEN1@@。 应针对缺失的目录遍历权限、错误属组或断开的软链接精确修正,同时保留配置和密钥文件的最小权限。
检查挂载时序和启动依赖
工作目录位于独立数据盘、NFS、云盘或加密卷时,目录可能在服务启动时尚未挂载。检查当前挂载以及对应单元:
findmnt -T /srv/example/current
systemctl list-dependencies example.service
systemctl status srv-example.mount --no-pager
systemd会为设置了WorkingDirectory的路径添加访问相关的挂载依赖,但自定义挂载脚本、网络文件系统或错误的fstab选项仍可能造成时序问题。网络文件系统还应正确声明网络依赖。
可以在单元drop-in中显式要求路径可挂载:
[Unit]
RequiresMountsFor=/srv/example/current
只有目录确实应由该挂载提供时才增加依赖。 用空目录临时占位可能让服务启动,却把数据写到根分区,待挂载恢复后又被遮蔽。
处理RootDirectory与沙箱视图差异
如果单元配置了 RootDirectory= 或 RootImage=,WorkingDirectory是相对于服务的新根目录解析,而不是管理员在宿主机Shell中看到的普通路径。还要检查以下设置:
sudo systemctl show example.service \
-p RootDirectory -p RootImage -p ProtectHome \
-p InaccessiblePaths -p BindPaths -p BindReadOnlyPaths
ProtectHome=、InaccessiblePaths=、私有挂载命名空间和绑定路径都可能改变服务看到的文件系统。SELinux或AppArmor拒绝目录访问时,应查看审计日志并修正标签或策略,不能通过关闭强制访问控制来长期绕过问题。
需要复现单元的挂载和沙箱行为,可在 萤光云 创建隔离环境;如果服务依赖跨区域网络存储,也可在 LightNode 建立临时节点。测试环境不要挂载生产数据盘或复制生产密钥。
修复后按服务身份验收
修正路径、权限或依赖后重新加载并启动:
sudo systemctl daemon-reload
sudo systemctl restart example.service
sudo systemctl status example.service --no-pager -l
sudo journalctl -u example.service -b -n 50 --no-pager
如果服务用户允许登录Shell,可在同一身份下验证目录;对nologin账号,使用 sudo -u example 执行最小的 test 命令即可。还应在重启或重新挂载后再次测试,确认不是偶然依赖已有目录状态。
验收通过应同时满足200/CHDIR消失、WorkingDirectory指向预期位置、服务用户可进入、依赖挂载先于服务可用,并且服务没有把数据写入错误的占位目录。
FAQ
在WorkingDirectory前加减号有什么作用?
systemd手册说明,前缀 - 会让目录缺失不再被视为致命错误。只有程序能安全地从默认目录运行时才考虑使用,不能作为掩盖部署目录丢失的通用修复。
目录明明存在,为什么仍报200/CHDIR?
常见原因是父目录无搜索权限、服务用户不同、软链接目标失效,或RootDirectory与沙箱让服务看到另一套文件系统视图。
可以把WorkingDirectory直接删掉吗?
只有应用不依赖相对路径、运行时文件和当前目录时才安全。删除前应检查程序配置,并在测试环境验证。
温馨提示
200/CHDIR是执行程序前的环境错误。先还原systemd实际加载的目录和服务文件系统视图,再修权限、挂载或依赖;不要用777、空目录占位或关闭安全模块换取表面启动。


