[Unit] Description=ZCode headless (Xvfb 虚拟屏) —— 供 Web 远控 / 官方中转访问 Documentation=https://zcode.z.ai After=network-online.target Wants=network-online.target [Service] Type=simple # 为什么用虚拟屏而不是 --headless:ZCode 的 Web 远控(web-remote-control)是 # **桌面端发起**的功能(界面上有 copyLink / 二维码,"Try again from desktop")。 # 它没有对应的命令行开关 —— 我一开始把 `--web-remote-navigation-height`(CSS 变量) # 与 `--remote-debugging-port`(Chrome)误读成 ZCode 的开关了。 # 所以要让远控可用,就必须真的把桌面应用跑起来,而无头服务器上没有显示 → # 用 Xvfb 提供一个。 # # --no-sandbox:Electron 以 root 运行时拒绝启用沙箱(会 FATAL 退出)。 # 这是本机的既有取舍(其它服务也以 root 跑),但要知道它降低了渲染进程的隔离。 # # --remote-debugging-port:暴露 CDP,用于程序化驱动界面(登录、开启远控、 # 截图核对状态),不必依赖 xdotool 之类的坐标点击。 # # 为什么套一层 dbus-run-session:Electron 的**单实例 / 深链转发**依赖会话总线, # 而下面把 DBUS_SESSION_BUS_ADDRESS 设成了 disabled:(无会话总线时的既有噪声)。 # 这里用 dbus-run-session 给本服务单独起一个会话总线 —— 只为该子进程提供, # **不动系统总线配置**。 # # 启动命令只在此处定义一次(唯一的 ExecStart)。需要改启动方式就改这里, # 不要在 drop-in 里整条重写 —— drop-in 重写会**静默盖住**本行, # 导致这里的改动不生效(历史上已因此出现过崩溃循环)。 ExecStart=/usr/bin/dbus-run-session -- /usr/bin/xvfb-run -a -s "-screen 0 1600x1000x24" /opt/ZCode/zcode --no-sandbox --disable-gpu --remote-debugging-port=9333 Environment=HOME=/root # 把 xdg-open 包装放到 PATH 最前:用于抓取 shell.openExternal 的目标 URL # (无头机上没有浏览器,否则这个信息会丢失,登录链接就拿不到) Environment=PATH=/root/gotmp/zcodewrap:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin Environment=ELECTRON_DISABLE_SECURITY_WARNINGS=1 # 无会话总线时的既有噪声(dbus 报错),不影响功能,不因此改系统总线配置 Environment=DBUS_SESSION_BUS_ADDRESS=disabled: Restart=always RestartSec=5 # 崩溃可见性:与 AgentMail 其它宿主同款约定(失败要有人知道,不能静默) ExecStopPost=-/usr/bin/node /opt/agentmail/bin/service-failure-notify.mjs --report --service zcode.service ExecStartPost=-/usr/bin/node /opt/agentmail/bin/service-failure-notify.mjs --flush --service zcode.service [Install] WantedBy=multi-user.target