服务启动失败并显示 status=209/STDOUT,说明systemd在真正执行 ExecStart 之前,没能按单元配置建立标准输出通道。此时应用程序可能一行代码都还没有运行。
排查方向应放在 StandardOutput=、输出文件路径、设备节点与服务沙箱,而不是先修改程序启动参数。209/STDOUT和应用自身返回209不是同一类问题。

先读取状态和本次启动日志
用完整输出确认结果码,并查看当前启动周期的日志:
systemctl status example.service --no-pager -l
journalctl -u example.service -b --no-pager -n 120
systemctl show example.service -p Result -p ExecMainCode -p ExecMainStatus
systemd将209定义为 EXIT_STDOUT,含义是标准输出设置失败。这一步发生在服务进程执行之前,应用日志为空并不能证明应用没有问题以外的线索。
查看最终生效的StandardOutput配置
不要只检查 /etc/systemd/system 中某一个文件,先读取合并后的单元内容:
systemctl cat example.service
systemctl show example.service -p StandardOutput -p StandardError
关注主单元和drop-in里是否配置了 file:、append:、truncate:、journal、null、tty 或命名文件描述符。后写入的覆盖项可能改变原本正常的输出目标。
检查日志文件和父目录权限
若配置类似 StandardOutput=append:/var/log/example/output.log,先检查父目录是否存在以及服务管理器能否访问:
namei -l /var/log/example/output.log
ls -ld /var/log/example
ls -l /var/log/example/output.log
目录缺失、只读挂载、符号链接指向不可访问位置,都可能导致输出建立失败。不要用chmod 777解决路径问题,应明确目录所有者、组和所需写权限,并确认日志轮转不会重新创建成错误属主。
核对TTY、socket和文件描述符来源
StandardOutput=tty 需要有效的 TTYPath=;fd:name 需要socket单元传入对应名称的文件描述符。检查关联关系:
systemctl show example.service -p Requires -p After -p Sockets
systemctl status example.socket --no-pager
若服务并不需要终端或socket输出,优先改回 journal,让systemd负责收集日志。不要保留一个并不存在的设备路径,只为了沿用旧模板。
检查沙箱与文件系统限制
ProtectSystem=、ReadOnlyPaths=、InaccessiblePaths=、RootDirectory= 等设置可能让日志目标在服务命名空间中不可写或不可见。查看安全相关属性:
systemctl show example.service \
-p ProtectSystem -p ReadWritePaths -p ReadOnlyPaths \
-p InaccessiblePaths -p RootDirectory
修复时应给需要写入的目录增加最小例外,例如 ReadWritePaths=/var/log/example,而不是关闭全部沙箱。路径仍需在宿主机和服务视图中同时存在。
用drop-in做最小修改
先为现有单元创建覆盖配置:
systemctl edit example.service
可临时回到journal验证输出链路:
[Service]
StandardOutput=journal
StandardError=journal
保存后执行:
systemctl daemon-reload
systemctl restart example.service
需要在隔离服务器复现单元差异时,可使用 萤光云 或 LightNode 建立测试环境。仅复制脱敏后的单元文件,不要带入生产令牌、私钥和真实业务日志。
修复后怎样验收
确认服务进入预期状态,并验证标准输出真的到达目标位置:
systemctl is-active example.service
journalctl -u example.service -b --no-pager -n 30
systemctl show example.service -p Result -p ExecMainStatus
若使用文件输出,还要检查新日志的属主、权限和轮转结果。验收标准是不再出现209/STDOUT,进程成功执行,日志目标可持续写入且权限没有被过度放宽。
FAQ
改了程序代码为什么仍然是209/STDOUT? 因为错误发生在systemd准备标准输出时,程序可能尚未启动,先修正单元的输出目标和访问条件。
StandardOutput=journal会写到哪个文件? journal由systemd-journald管理,不应依赖某个固定文本文件路径,使用 journalctl -u 服务名 查询。
温馨提示
修改前先保存 systemctl cat 和关键属性输出,便于对比回滚。能用journal满足需求时,不必为每个服务手工维护独立日志文件和权限。


