目录

Ubuntu 上安全部署 OpenClaw & Hermes:systemd 多用户多服务、容器与脚本服务架构实战指南

从单用户暴力自启到 AI 工厂式分层架构,彻底告别桌面卡顿

前提:你已经读过

-Ubuntu 桌面启动卡顿与 xdg-desktop-portal 超时:完整排查实录

本文在此基础上,把 OpenClaw / Hermes 的部署方式,从"随便挂一堆自启服务"升级为"可维护、可回滚、不影响桌面"的 AI 工厂式架构。


一、目标:一套"不影响桌面"的 AI 自动化基础设施

你要达成的效果是:

  1. 主桌面账号(如 oklife):

    • 登录秒进,不卡顿;
    • 不随登录自动启动任何网关、代理、浏览器自动化;
    • 只在需要时,用脚本或命令手动启动服务。
  2. 自动化服务(OpenClaw、Hermes、headless Chrome 等):

    • 可以长期运行,但运行在独立账号或容器中;
    • 即使挂了,也不会导致主桌面登录失败或启动卡顿;
    • 日志、配置、脚本都清晰可查,方便回滚和升级。
  3. 未来扩展:

    • 可以轻易增加新的服务(新网关、新代理、新自动化脚本);
    • 不会破坏现有桌面体验。
Ubuntu 多用户 systemd 三层架构:oklife 操作员层 → yuntian 自动化层 → 容器层

二、整体架构:三层设计

1. 层 1:主桌面账号(操作员)

账号示例:oklife

职责:

  • 写代码、调试、跑本地模型;
  • 手动启动需要的服务(如临时测试某个网关);
  • 日常使用浏览器、IDE、终端。

原则:

  • ~/.config/systemd/user 保持干净,不挂任何自启链接;
  • 所有自建服务都通过 systemctl --user start 手动启动;
  • 不执行 systemctl --user enable,避免自动挂到 default.target.wants

2. 层 2:自动化专用账号(后台节点)

账号示例:yuntian

职责:

  • 长期运行:

    • headless Chrome(DevTools 9222);
    • openclaw-gateway;
    • hermes-gateway;
    • 其他代理/脚本。
  • 不登录 GNOME 桌面,只在 TTY / systemd 层运行。

特点:

  • 有 sudo 权限,方便安装/维护;

  • 登录方式:

    • TTY(Ctrl + Alt + F3 等);
    • 或 SSH(如果你开了远程登录);
  • 即使这个账号的服务全挂,也不影响 oklife 的图形桌面。

参考systemd 用户级服务官方文档

3. 层 3(可选):容器化节点

如果你希望更隔离,可以用 Docker / Podman 跑:

  • headless Chrome;
  • OpenClaw / Hermes 网关;
  • 其他自动化脚本。

容器内:

  • 使用自己的用户空间;
  • 通过端口映射暴露服务(如 9222、网关端口);
  • 宿主机上的 oklifeyuntian 都只负责"启动/停止容器"。

这一层可以单独再写一篇,本文先聚焦在"多用户 + systemd"的方案。


三、目录结构与命名规范(建议)

yuntian 账号下,推荐统一目录结构,方便维护:

/home/yuntian/
  ai-services/
    openclaw/
      config/
      bin/
      logs/
      systemd/
    hermes/
      config/
      bin/
      logs/
      systemd/
    chrome/
      bin/
      logs/
      systemd/
    scripts/
      start-all.sh
      stop-all.sh
      status-all.sh

说明:

  • config/:各服务的配置文件(JSON/YAML/ENV);
  • bin/:可执行脚本或二进制;
  • logs/:服务日志(如果用 journalctl 也可以不写文件);
  • systemd/:对应的 .service 文件;
  • scripts/:统一启停脚本。

命名规范建议:

  • 服务名:openclaw-gateway, hermes-gateway, chrome-debug
  • systemd unit:openclaw-gateway.service, hermes-gateway.service, chrome-debug.service
  • 日志目录:/home/yuntian/ai-services/<组件>/logs/
yuntian 账号下 ai-services 目录树结构

四、手把手:在 yuntian 账号下部署 OpenClaw / Hermes

以下命令都在 yuntian 账号下执行(TTY 或 SSH)。

1. 创建基础目录

mkdir -p ~/ai-services/{openclaw,hermes,chrome,scripts}
for d in openclaw hermes chrome; do
  mkdir -p ~/ai-services/$d/{config,bin,logs,systemd}
done

2. 放置 OpenClaw 网关脚本

假设你已有 OpenClaw 网关的可执行文件或脚本,放在:

~/ai-services/openclaw/bin/openclaw-gateway

确保可执行:

chmod +x ~/ai-services/openclaw/bin/openclaw-gateway

参考OpenClaw 官方文档

3. 编写 systemd unit(openclaw-gateway.service)

yuntian 的用户 systemd 目录中创建 unit:

mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/openclaw-gateway.service << 'EOF'
[Unit]
Description=OpenClaw Gateway Service
After=network.target

[Service]
Type=simple
ExecStart=/home/yuntian/ai-services/openclaw/bin/openclaw-gateway
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment=HOME=/home/yuntian
Environment=USER=yuntian

[Install]
WantedBy=default.target
EOF

注意:这里虽然写了 WantedBy=default.target,但我们不执行 enable,所以不会自动随登录启动,只用于手动 start

4. 同样方式部署 Hermes 网关

# 放脚本
chmod +x ~/ai-services/hermes/bin/hermes-gateway

# 写 unit
cat > ~/.config/systemd/user/hermes-gateway.service << 'EOF'
[Unit]
Description=Hermes Gateway Service
After=network.target

[Service]
Type=simple
ExecStart=/home/yuntian/ai-services/hermes/bin/hermes-gateway
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment=HOME=/home/yuntian
Environment=USER=yuntian

[Install]
WantedBy=default.target
EOF

参考Hermes GitHub 仓库

5. 部署 headless Chrome(chrome-debug)

# 放启动脚本
cat > ~/ai-services/chrome/bin/chrome-debug << 'EOF'
#!/bin/bash
set -e
exec /usr/bin/google-chrome \
  --remote-debugging-port=9222 \
  --headless=new \
  --no-sandbox \
  --disable-gpu \
  --disable-dev-shm-usage
EOF

chmod +x ~/ai-services/chrome/bin/chrome-debug

systemd unit:

cat > ~/.config/systemd/user/chrome-debug.service << 'EOF'
[Unit]
Description=Chrome Headless Debug (DevTools 9222)
After=network.target

[Service]
Type=simple
ExecStart=/home/yuntian/ai-services/chrome/bin/chrome-debug
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment=HOME=/home/yuntian
Environment=USER=yuntian
Environment=DISPLAY=:0

[Install]
WantedBy=default.target
EOF

注意:如果 yuntian 不跑图形桌面,DISPLAY=:0 可能无效;如果你只用 headless 模式,一般不需要 DISPLAY,可以去掉。


五、启动与管理服务(yuntian 账号)

1. 重载 systemd 并启动服务

yuntian 账号下:

systemctl --user daemon-reload

systemctl --user start openclaw-gateway.service
systemctl --user start hermes-gateway.service
systemctl --user start chrome-debug.service

查看状态:

systemctl --user status openclaw-gateway.service
systemctl --user status hermes-gateway.service
systemctl --user status chrome-debug.service

查看日志:

journalctl --user -u openclaw-gateway.service -f
journalctl --user -u hermes-gateway.service -f
journalctl --user -u chrome-debug.service -f

2. 统一启停脚本(可选)

yuntian 下创建:

cat > ~/ai-services/scripts/start-all.sh << 'EOF'
#!/bin/bash
set -e
systemctl --user daemon-reload
systemctl --user start openclaw-gateway.service
systemctl --user start hermes-gateway.service
systemctl --user start chrome-debug.service
echo "All services started."
EOF

cat > ~/ai-services/scripts/stop-all.sh << 'EOF'
#!/bin/bash
set -e
systemctl --user stop openclaw-gateway.service
systemctl --user stop hermes-gateway.service
systemctl --user stop chrome-debug.service
echo "All services stopped."
EOF

cat > ~/ai-services/scripts/status-all.sh << 'EOF'
#!/bin/bash
systemctl --user status openclaw-gateway.service hermes-gateway.service chrome-debug.service --no-pager
EOF

chmod +x ~/ai-services/scripts/*.sh

使用:

~/ai-services/scripts/start-all.sh
~/ai-services/scripts/stop-all.sh
~/ai-services/scripts/status-all.sh

六、在 oklife 桌面中按需使用这些服务

1. 通过 SSH / 本地命令控制 yuntian 的服务

oklife 桌面终端中,你可以:

  • 本地:su - yuntian 然后执行启停脚本;
  • 或配置 SSH key,从 oklife SSH 到本机 yuntian 执行命令。

示例(本地 su):

sudo -u yuntian bash -c 'systemctl --user start openclaw-gateway.service'
sudo -u yuntian bash -c 'systemctl --user status openclaw-gateway.service'

注意:systemctl --user 在非登录会话中有时需要额外配置(如 XDG_RUNTIME_DIR),更稳妥的方式是:

  • yuntian 的 TTY 会话中直接操作;
  • 或写一个 root 可调用的 wrapper 脚本,由 root 调用 systemctl --user

如果上述命令报错 Failed to connect to bus,请使用以下 workaround:

sudo -u yuntian bash -c 'XDG_RUNTIME_DIR=/run/user/$(id -u yuntian) systemctl --user start openclaw-gateway.service'

这个 workaround 显式设置了 XDG_RUNTIME_DIR,避免了非登录会话中 runtime dir 缺失的问题。

2. 在 oklife 下临时跑自己的服务(不挂自启)

如果你想在 oklife 下临时测试某个服务:

# 从 yuntian 的备份目录复制 unit 过来
cp /home/yuntian/.config/systemd/user/openclaw-gateway.service \
   ~/.config/systemd/user/

systemctl --user daemon-reload
systemctl --user start openclaw-gateway.service
systemctl --user status openclaw-gateway.service

# 用完就停
systemctl --user stop openclaw-gateway.service

不执行 enable,就不会自动随登录启动。

oklife 通过 sudo 调用 yuntian systemd 服务的流程图

七、如何安全地开发/测试一个新服务

当你新增一个服务(比如 new-gateway.service)时,遵循这个流程,可以避免再次破坏桌面:

  1. 先在 yuntian 账号下开发和测试

    • 写好脚本和 unit;
    • yuntian 的 TTY 中 start / stop / 看日志;
    • 确认稳定后再考虑长期使用。
  2. 确认不会依赖图形会话

    • 不要依赖 graphical-session.target
    • 不要依赖未设置的 DISPLAY 或 Wayland 环境;
    • 如果必须用图形,就明确在 unit 中声明 After=graphical-session.target,并且只在有桌面的账号下跑。
  3. 在 oklife 下只手动 start,不 enable

    • 每次新服务都先在 oklife 下手动 start 测试;
    • 确认不影响登录和启动后,再决定是否长期保留;
    • 建议永远不 enable,保持"按需启动"的习惯。
  4. 保留备份目录

    • 类似 /home/oklife/.config/systemd/user.broken.*
    • 一旦出问题,可以整体挪走,快速恢复干净桌面。

八、监控与日志:让服务"看得见、管得住"

1. 用 journalctl 看日志

yuntian 账号下:

# 看最近 200 行
journalctl --user -u openclaw-gateway.service -n 200 --no-pager

# 实时跟踪
journalctl --user -u openclaw-gateway.service -f

2. 简单健康检查脚本

可以写一个脚本,定期检查服务是否活着:

cat > ~/ai-services/scripts/health-check.sh << 'EOF'
#!/bin/bash
set -e

for u in openclaw-gateway hermes-gateway chrome-debug; do
  state=$(systemctl --user is-active "$u.service" 2>/dev/null || echo "inactive")
  echo "$u: $state"
done
EOF

chmod +x ~/ai-services/scripts/health-check.sh

配合 cron 或 systemd timer,可以定期运行并记录状态。


九、回滚策略:当新服务搞砸了怎么办

假设你新加了一个服务,结果又出现启动卡顿或登录问题:

  1. 在辅助账号(如另一个 testuser)或 TTY 中登录;

  2. oklife~/.config/systemd/user 再次整体挪到新的备份目录:

    sudo mv /home/oklife/.config/systemd/user \
            /home/oklife/.config/systemd/user.broken.$(date +%s)
  3. 重启,确认 oklife 能正常登录;

  4. 从旧备份中只恢复你确定没问题的服务,逐步测试。

这种"整体软禁 + 逐步恢复"的策略,比一个个删服务要安全得多。


十、可选进阶:容器化部署

如果你希望更彻底隔离,可以考虑:

  • 用 Docker 跑 headless Chrome:

    docker run -d --name chrome-debug \
      -p 9222:9222 \
      some-chrome-image \
      --remote-debugging-port=9222 --headless=new ...
  • 用 Docker Compose 管理 OpenClaw / Hermes 网关;

  • 宿主机上的 oklife / yuntian 只负责:

    • docker compose up -d / down
    • 查看容器日志 docker logs -f <container>

这一层可以单独写一篇文章,这里不再展开。


结语

通过这三篇:

  1. 启动卡顿与 portal 超时;
  2. 登录循环与用户级 systemd 服务;
  3. OpenClaw / Hermes 的安全部署架构;

你实际上已经搭建了一套适合"AI 工厂"的 Ubuntu 基础架构:

  • 桌面干净、响应快;
  • 自动化服务分层运行,互不干扰;
  • 有新服务时,有明确的开发、测试、回滚路径。

如果你后续想写第 4 篇,可以考虑:

  • “用 Docker / Podman 容器化跑 headless Chrome 和网关”;
  • “多机集群:把 yuntian 这类自动化节点扩展到多台机器”;
  • “日志与监控:用 Prometheus + Grafana / Loki 看 AI 工厂运行状态”。

你可以告诉我下一个想写的方向,我继续按这个风格帮你成文。


关联阅读

  • [[Ubuntu 桌面启动卡顿与 xdg-desktop-portal 超时:完整排查实录|第 1 篇:启动卡顿排查]]
  • [[Ubuntu 26.04 登录循环修复:systemd 用户服务故障排查指南|第 2 篇:登录循环修复]]