systemd 服务报 200/CHDIR:终端能运行,服务用户却进不了 /root 目录
root 终端可以运行的应用,交给 www-data 服务后报 200/CHDIR。检查工作目录的逐层权限、服务隔离和部署位置,再安全调整启动路径。
应用在 root 的终端中可以运行,改成 User=www-data 的 systemd 服务后却反复失败,状态出现 status=200/CHDIR。这个退出状态表示启动前切换工作目录失败,应先检查 WorkingDirectory 和目录访问条件,不要先把问题归为应用代码或端口故障。
尤其当应用仍放在 /root/... 中时,服务账户可能无法穿过 /root 这一层。目录不存在、隔离设置或挂载条件也会产生同类失败,报错本身不能证明一定是权限问题。本文面向 Linux 上的系统级 systemd 服务。
看生效路径和服务用户
下面是容易出问题的配置片段示例:
[Service]
User=www-data
WorkingDirectory=/root/dev/myapp
ExecStart=/usr/bin/dotnet /root/dev/myapp/myapp.dll
在受控终端读取目标服务配置和近期日志,myapp.service 替换成实际服务名:
systemctl cat myapp.service
systemctl show myapp.service -p User -p WorkingDirectory -p RootDirectory -p ProtectHome
sudo journalctl -u myapp.service -b -n 100 --no-pager
查看日志中最早出现的切换目录错误,注意 No such file or directory 与 Permission denied 的区别。配置和日志可能包含内部路径或敏感信息,不要整段上传公开平台。
如果路径不存在,核对部署目录、大小写以及路径是否位于服务的 RootDirectory 里。程序未启动时,修改应用监听端口不会修复 CHDIR。
逐层检查目录搜索权限
对示例目录检查各层权限,并用服务账户尝试进入目录:
namei -l /root/dev/myapp
sudo -u www-data /bin/sh -c 'cd /root/dev/myapp && pwd'
这两条用于读取路径与权限,不启动应用。namei 是否已安装取决于发行版。进入目录需要沿途各层的搜索权限;项目目录本身可读,也不代表服务用户能够经过 /root。
若第二条失败,按输出检查缺失路径、传统权限或 ACL。不要把 /root 递归改成开放权限,也不要仅为了消除报错把服务改为 root。服务只需要访问自己的部署和数据目录。
若第二条成功但 systemd 仍失败,说明普通用户环境的检查还不足以覆盖服务环境。继续看 ProtectHome、RootDirectory、路径隔离和挂载,以及 SELinux/AppArmor 的拒绝记录。保留隔离措施并调整部署位置或必要的策略,不要一次关闭全部安全设置。
将发布目录放到服务可访问的位置
部署前备份当前程序、服务文件、配置和需要持久保存的数据。可以将经过发布流程生成的程序放到 /srv/myapp 等专用目录,由部署账户管理代码,为服务账户授予必要的目录搜索及文件读取权限;应用需要写入的数据另外安排可写目录。
目录权限落实后,对自定义服务修改为以下片段,示例中的 www-data、dotnet 路径及文件名应按自己的环境替换:
[Service]
User=www-data
WorkingDirectory=/srv/myapp
ExecStart=/usr/bin/dotnet /srv/myapp/myapp.dll
不要用这段片段覆盖整个服务文件,原有重启、环境和依赖设置仍需保留。若通过覆盖文件重写已有 ExecStart,先用空 ExecStart= 清除旧命令再设置新命令;否则普通服务可能因存在多个启动命令而被拒绝。
确认新目录、应用运行时与权限均就绪后,在维护窗口应用配置:
sudo systemctl daemon-reload
sudo systemctl restart myapp.service
systemctl status myapp.service --no-pager
重启会中断该服务。daemon-reload 只是重读单元,不会把运行中的进程移到新目录。失败时恢复原服务配置和已知可运行的部署路径,再重读单元、重启;数据写入需要按应用的备份流程处理,复制代码不等于回滚数据。
修正成功应看到 CHDIR 错误消失,应用进程真正运行并通过业务检查。若随后出现 203/EXEC、运行时缺失或应用自身错误,说明已经到达下一阶段,按新的第一条错误继续处理。


