hermes-agent/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/docker.md
Ben fb51253620 docker: opt in to dashboard --insecure via env var, never derive from bind host
The s6 dashboard run script flipped `--insecure` on whenever
`HERMES_DASHBOARD_HOST` was anything other than 127.0.0.1 / localhost.
That comment ("the dashboard refuses otherwise") predates the OAuth
auth gate: back when it was written, `start_server` would SystemExit
on any non-loopback bind, so the run script's `--insecure` was the
only way to make in-container deployments work at all.

The gate has since been replaced by `should_require_auth(host,
allow_public)`, which engages the OAuth flow when a
`DashboardAuthProvider` is registered (the bundled `dashboard_auth/nous`
provider auto-registers on `HERMES_DASHBOARD_OAUTH_CLIENT_ID`) and
fails closed with a specific operator-facing error when none is. The
host-derived `--insecure` ran upstream of all that and silently
disabled the gate on every container-deployed dashboard.

Most visible under the portal's wildcard-subdomain rollout: every Fly
machine binds 0.0.0.0 so the edge can reach Flycast, every machine
boots with the correct `HERMES_DASHBOARD_OAUTH_CLIENT_ID`, the nous
provider registers — and `/api/status` still returns
`{"auth_required": false, "auth_providers": ["nous"]}` because the
run script disabled the gate before `start_server` ever saw the
request. The dashboard SPA was served to anyone, no `/login` redirect,
no OAuth challenge.

Fix: derive `--insecure` from an explicit opt-in env var,
`HERMES_DASHBOARD_INSECURE` (truthy values matching the rest of the
s6 boolean envs: 1, true, TRUE, True, yes, YES, Yes). Operators on
trusted LANs behind a reverse proxy without the OAuth contract
(the existing `docker-compose.windows.yml` use case) opt in
explicitly; portal-managed agent deployments leave it unset and let
the gate engage.

`docker-compose.windows.yml` already passes `--insecure` on the
`command:` array directly (line 38), so it doesn't depend on the s6
auto-injection. No compose-file change required.

Tests:
* `tests/test_docker_home_override_scripts.py` — extends the existing
  static-text guard with a regression assertion that the legacy
  host-derived case-statement is gone and the new env-var opt-in is
  present (locks against accidental revert).
* `tests/docker/test_dashboard.py` — adds two Docker-in-Docker tests
  exercising the actual `/api/status` round-trip:
  - 0.0.0.0 bind + `HERMES_DASHBOARD_OAUTH_CLIENT_ID` → gate engaged
  - 0.0.0.0 bind + `HERMES_DASHBOARD_INSECURE=1` → gate disabled

Docs:
* `website/docs/user-guide/docker.md` + zh-Hans i18n — adds the new
  env var to the table, replaces the stale prose ("the entrypoint
  no longer auto-enables insecure mode" — which until this PR was
  flat-out wrong) with an accurate description of the gate's
  trigger conditions and the explicit opt-out.

shellcheck clean. Python static-text test passes locally. Behavioural
test will run against any future image build (CI's Docker harness).
2026-05-29 09:56:40 +10:00

25 KiB
Raw Blame History

sidebar_position title description
7 Docker 在 Docker 中运行 Hermes Agent 以及将 Docker 用作终端后端

Hermes Agent — Docker

Docker 与 Hermes Agent 的交集有两种截然不同的方式:

  1. 在 Docker 中运行 Hermes — agent 本身在容器内运行(本页的主要内容)
  2. Docker 作为终端后端 — agent 在宿主机上运行,但将每条命令在单个持久化 Docker 沙箱容器中执行,该容器在工具调用、/new 和子 agent 之间保持存活,直至 Hermes 进程结束(参见 配置 → Docker 后端

本页介绍选项 1。容器将所有用户数据配置、API 密钥、会话、技能、记忆)存储在从宿主机挂载于 /opt/data 的单个目录中。镜像本身是无状态的,可通过拉取新版本进行升级而不会丢失任何配置。

快速开始

如果这是你第一次运行 Hermes Agent请在宿主机上创建一个数据目录并以交互方式启动容器以运行设置向导

mkdir -p ~/.hermes
docker run -it --rm \
  -v ~/.hermes:/opt/data \
  nousresearch/hermes-agent setup

这将进入设置向导,向导会提示你输入 API 密钥并将其写入 ~/.hermes/.env。你只需执行一次。强烈建议此时为 gateway 配置一个聊天系统。

以 gateway 模式运行

配置完成后,将容器作为持久化 gatewayTelegram、Discord、Slack、WhatsApp 等)在后台运行:

docker run -d \
  --name hermes \
  --restart unless-stopped \
  -v ~/.hermes:/opt/data \
  -p 8642:8642 \
  nousresearch/hermes-agent gateway run

端口 8642 暴露 gateway 的 OpenAI 兼容 API 服务器和健康检查端点。如果你只使用聊天平台Telegram、Discord 等),该端口是可选的;但如果你希望 dashboard 或外部工具访问 gateway则必须开放。

注意API 服务器需设置 API_SERVER_ENABLED=true 才会启用。若要在容器内将其暴露至 127.0.0.1 以外,还需设置 API_SERVER_HOST=0.0.0.0API_SERVER_KEY(最少 8 个字符——可用 openssl rand -hex 32 生成)。示例:

docker run -d \
  --name hermes \
  --restart unless-stopped \
  -v ~/.hermes:/opt/data \
  -p 8642:8642 \
  -e API_SERVER_ENABLED=true \
  -e API_SERVER_HOST=0.0.0.0 \
  -e API_SERVER_KEY="$(openssl rand -hex 32)" \
  -e API_SERVER_CORS_ORIGINS='*' \
  nousresearch/hermes-agent gateway run

在面向互联网的机器上开放任何端口都存在安全风险。除非你了解相关风险,否则不应这样做。

运行 dashboard

内置 Web dashboard 作为可选的子进程在与 gateway 相同的容器内运行。设置 HERMES_DASHBOARD=1 可在容器回环地址(127.0.0.1)上默认运行 dashboard

docker run -d \
  --name hermes \
  --restart unless-stopped \
  -v ~/.hermes:/opt/data \
  -p 8642:8642 \
  -e HERMES_DASHBOARD=1 \
  nousresearch/hermes-agent gateway run

入口点在 exec 主命令之前,以非 root 用户 hermes 在后台启动 hermes dashboard。Dashboard 输出在 docker logs 中以 [dashboard] 为前缀,便于与 gateway 日志区分。

环境变量 描述 默认值
HERMES_DASHBOARD 设为 1(或 true / yes)以在主命令旁启动 dashboard (未设置——不启动 dashboard
HERMES_DASHBOARD_HOST dashboard HTTP 服务器的绑定地址 127.0.0.1
HERMES_DASHBOARD_PORT dashboard HTTP 服务器的端口 9119
HERMES_DASHBOARD_TUI 设为 1 以启用浏览器内 Chat 标签页(通过 PTY/WebSocket 嵌入 hermes --tui (未设置)
HERMES_DASHBOARD_INSECURE 设为 1(或 true / yes)以在不启用 OAuth 鉴权门控的情况下绑定。仅在可信网络(且通过没有 OAuth 契约的反向代理时使用——dashboard 会暴露 API 密钥与会话数据 (未设置——当注册了 DashboardAuthProvider 时启用门控)

默认情况下dashboard 保持在回环地址(127.0.0.1),以避免将 Web 界面暴露到网络。若要有意发布,请设置 HERMES_DASHBOARD_HOST=0.0.0.0。当以下两项同时满足时, dashboard 的 OAuth 鉴权门控会自动启用:

  1. 绑定地址为非回环地址,
  2. 注册了一个 DashboardAuthProvider 插件。

捆绑的 dashboard_auth/nous 提供者会在设置 HERMES_DASHBOARD_OAUTH_CLIENT_ID 时自动激活(参见 Web Dashboard → 鉴权)。门控启用后, 浏览器调用方会先被重定向到所配置门户的 OAuth 流,然后才能 访问任何受保护路由。

如果未注册提供者且绑定为非回环地址dashboard 会在启动时 失败关闭,并给出指向缺失环境变量的具体错误信息。要显式 退出门控——用于不使用 OAuth 契约、通过你自己的反向代理部署 在可信局域网中的场景——请设置 HERMES_DASHBOARD_INSECURE=1。 这会恢复旧的“无鉴权,但发出告警”模式,也是唯一可以禁用门控的 路径;绑定地址不再隐式决定 --insecure

:::note dashboard 在容器内作为受监管的 s6 服务运行。如果 dashboard 进程崩溃s6-overlay 会在短暂退避后自动 重启它——你会看到新的 PID无需重启容器。日志和崩溃输出可通过 docker logs <container> 查看s6 将服务的 stdout/stderr 转发至此)。

不支持将 dashboard 作为独立容器运行:其 gateway 存活检测需要与 gateway 进程共享 PID 命名空间。 :::

交互式运行CLI 聊天)

对已有数据目录打开交互式聊天会话:

docker run -it --rm \
  -v ~/.hermes:/opt/data \
  nousresearch/hermes-agent

或者,如果你已通过 Docker Desktop 等方式在运行中的容器内打开了终端,直接运行:

/opt/hermes/.venv/bin/hermes

持久化卷

/opt/data 卷是所有 Hermes 状态的唯一数据来源。它映射到宿主机的 ~/.hermes/ 目录,包含:

路径 内容
.env API 密钥和机密
config.yaml 所有 Hermes 配置
SOUL.md Agent 个性/身份
sessions/ 对话历史
memories/ 持久化记忆存储
skills/ 已安装的技能
cron/ 定时任务定义
hooks/ 事件 hook
logs/ 运行时日志
skins/ 自定义 CLI 皮肤

:::warning 切勿同时对同一数据目录运行两个 Hermes gateway 容器——会话文件和记忆存储不支持并发写入。 :::

多 profile 支持

Hermes 支持多个 profile——独立的 ~/.hermes/ 目录,让你可以从单个安装运行独立的 agent不同的 SOUL、技能、记忆、会话、凭据在 Docker 下运行时,不建议使用 Hermes 内置的多 profile 功能。

推荐的模式是每个 profile 一个容器,每个容器将各自的宿主机目录绑定挂载为 /opt/data

# 工作 profile
docker run -d \
  --name hermes-work \
  --restart unless-stopped \
  -v ~/.hermes-work:/opt/data \
  -p 8642:8642 \
  nousresearch/hermes-agent gateway run

# 个人 profile
docker run -d \
  --name hermes-personal \
  --restart unless-stopped \
  -v ~/.hermes-personal:/opt/data \
  -p 8643:8642 \
  nousresearch/hermes-agent gateway run

在 Docker 中使用独立容器而非 profile 的原因:

  • 隔离性 — 每个容器有独立的文件系统、进程表和资源限制。一个 profile 中的崩溃、依赖变更或失控会话不会影响另一个。
  • 独立生命周期 — 可独立升级、重启、暂停或回滚每个 agentdocker restart hermes-work 不会影响 hermes-personal)。
  • 清晰的端口和网络隔离 — 每个 gateway 绑定各自的宿主机端口;聊天平台或 API 服务器之间不存在串扰风险。
  • 更简单的心智模型 — 容器即 profile。备份、迁移和权限管理都跟随绑定挂载的目录无需记住额外的 --profile 标志。
  • 避免并发写入风险 — 上述关于不得对同一数据目录运行两个 gateway 的警告同样适用于单个容器内的 profile。

在 Docker Compose 中,只需为每个 profile 声明一个服务,使用不同的 container_namevolumesports

services:
  hermes-work:
    image: nousresearch/hermes-agent:latest
    container_name: hermes-work
    restart: unless-stopped
    command: gateway run
    ports:
      - "8642:8642"
    volumes:
      - ~/.hermes-work:/opt/data

  hermes-personal:
    image: nousresearch/hermes-agent:latest
    container_name: hermes-personal
    restart: unless-stopped
    command: gateway run
    ports:
      - "8643:8642"
    volumes:
      - ~/.hermes-personal:/opt/data

环境变量转发

API 密钥从容器内的 /opt/data/.env 读取。你也可以直接传递环境变量:

docker run -it --rm \
  -v ~/.hermes:/opt/data \
  -e ANTHROPIC_API_KEY="sk-ant-..." \
  -e OPENAI_API_KEY="sk-..." \
  nousresearch/hermes-agent

直接传入的 -e 标志会覆盖 .env 中的值。这对于不希望将密钥写入磁盘的 CI/CD 或密钥管理器集成非常有用。

:::note 寻找 Docker 作为终端后端的说明? 本页介绍在 Docker 内运行 Hermes 本身。如果你希望 Hermes 在 Docker 沙箱容器内执行 agent 的 terminal / execute_code 调用(每个 Hermes 进程对应一个持久容器),那是另一个配置块——terminal.backend: docker 加上 terminal.docker_imageterminal.docker_volumesterminal.docker_forward_envterminal.docker_run_as_host_userterminal.docker_extra_args。完整配置请参见 配置 → Docker 后端。 :::

Docker Compose 示例

对于同时运行 gateway 和 dashboard 的持久化部署,使用 docker-compose.yaml 更为方便:

services:
  hermes:
    image: nousresearch/hermes-agent:latest
    container_name: hermes
    restart: unless-stopped
    command: gateway run
    ports:
      - "8642:8642"   # gateway API
      - "9119:9119"   # dashboard仅在 HERMES_DASHBOARD=1 时生效)
    volumes:
      - ~/.hermes:/opt/data
    environment:
      - HERMES_DASHBOARD=1
      # 取消注释以直接转发特定环境变量而非使用 .env 文件:
      # - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
      # - OPENAI_API_KEY=${OPENAI_API_KEY}
      # - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: "2.0"

使用 docker compose up -d 启动,使用 docker compose logs -f 查看日志。Dashboard 输出以 [dashboard] 为前缀,便于从 gateway 日志中过滤。

资源限制

Hermes 容器需要适量资源。推荐最低配置:

资源 最低 推荐
内存 1 GB 24 GB
CPU 1 核 2 核
磁盘(数据卷) 500 MB 2+ GB随会话/技能增长)

浏览器自动化Playwright/Chromium是最耗内存的功能。如果不需要浏览器工具1 GB 即可。启用浏览器工具时,请至少分配 2 GB。

在 Docker 中设置限制:

docker run -d \
  --name hermes \
  --restart unless-stopped \
  --memory=4g --cpus=2 \
  -v ~/.hermes:/opt/data \
  nousresearch/hermes-agent gateway run

Dockerfile 说明

官方镜像基于 debian:13.4,包含:

  • Python 3 及所有 Hermes 依赖(uv pip install -e ".[all]"
  • Node.js + npm用于浏览器自动化和 WhatsApp 桥接)
  • Playwright 与 Chromiumnpx playwright install --with-deps chromium --only-shell
  • ripgrep、ffmpeg、git 和 xz-utils 作为系统工具
  • docker-cli — 使容器内运行的 agent 可以驱动宿主机的 Docker 守护进程(绑定挂载 /var/run/docker.sock 以启用),用于 docker builddocker run、容器检查等操作
  • openssh-client — 从容器内启用 SSH 终端后端。SSH 后端调用系统 ssh 二进制文件;若缺少此组件,在容器化安装中会静默失败
  • WhatsApp 桥接(scripts/whatsapp-bridge/
  • s6-overlay v3 作为 PID 1替代旧版 tini)——监管 dashboard 和各 profile gateway崩溃后自动重启回收僵尸子进程并转发信号

容器的 ENTRYPOINT 是 s6-overlay 的 /init。启动时:

  1. 以 root 身份运行 /etc/cont-init.d/01-hermes-setup(即 docker/stage2-hook.sh):可选的 UID/GID 重映射、修复卷所有权、首次启动时初始化 .env / config.yaml / SOUL.md、同步内置技能。
  2. 运行 /etc/cont-init.d/02-reconcile-profiles(即 hermes_cli.container_boot):遍历 $HERMES_HOME/profiles/<name>/,在 /run/service/gateway-<profile>/ 下重建各 profile 的 gateway s6 服务槽,并仅自动启动上次记录状态为 running 的 profile参见 Per-profile gateway 监管)。
  3. 启动静态的 main-hermesdashboard s6-rc 服务。
  4. 将容器的 CMD 作为主程序 exec/opt/hermes/docker/main-wrapper.sh),根据用户传给 docker run 的参数进行路由:
    • 无参数 → hermes(默认)
    • 第一个参数是 PATH 上的可执行文件(如 sleepbash)→ 直接 exec
    • 其他情况 → hermes <args>(子命令透传) 主程序退出时容器退出,并使用其退出码。

:::warning 与 pre-s6 镜像的破坏性变更 容器 ENTRYPOINT 现在是 /inits6-overlay而非 /usr/bin/tini。所有五种已记录的 docker run 调用模式(无参数、chat -q "…"sleep infinitybash--tui)的行为与基于 tini 的镜像完全相同。如果你有依赖 tini 特定信号行为或硬编码 /usr/bin/tini -- 调用的下游封装,请固定到之前的镜像标签。 :::

:::warning 权限模型 除非你在命令链中保留 /init(或等效的旧版 docker/entrypoint.sh shim它会转发到 stage2 hook否则不要覆盖镜像入口点。s6-overlay 的 /init 以 root 运行,以便在首次启动时对卷执行 chown然后通过 s6-setuidgid 为每个受监管的服务以及主程序降权至 hermes 用户。在官方镜像内以 root 启动 hermes gateway run 默认会被拒绝,因为这可能在 /opt/data 中留下 root 所有的文件,导致后续 dashboard 或 gateway 启动失败。仅在你有意接受该风险时才设置 HERMES_ALLOW_ROOT_GATEWAY=1。 :::

Per-profile gateway 监管

在容器内,每个通过 hermes profile create <name> 创建的 profile 都会自动在 /run/service/gateway-<name>/ 注册一个受 s6 监管的 gateway 服务。你在宿主机上运行的生命周期命令在此同样适用:

hermes profile create coder            # 注册 gateway-coder s6 槽
hermes -p coder gateway start          # s6-svc -u  → 受监管的 gateway
hermes -p coder gateway stop           # s6-svc -d  → 服务停止
hermes -p coder gateway restart        # s6-svc -t  → 向 supervisor 发送 SIGTERM
hermes profile delete coder            # 拆除 s6 槽

相比 pre-s6 镜像的监管优势:

  • Gateway 崩溃后由 s6-supervise 在约 1 秒退避后自动重启。
  • Dashboard 崩溃后自动重启(设置 HERMES_DASHBOARD=1 以启动)。
  • docker restart 保留运行中的 gatewaycont-init 协调器读取 $HERMES_HOME/profiles/<name>/gateway_state.json,若上次记录状态为 running 则恢复该槽。已停止的 gateway 保持停止状态。
  • 各 profile 的 gateway 日志持久化于 $HERMES_HOME/logs/gateways/<profile>/current(由 s6-log 轮转),协调器的操作记录在每次启动时追加到 $HERMES_HOME/logs/container-boot.log

在容器内执行 hermes status 会显示 Manager: s6 (container supervisor)。使用 /command/s6-svstat /run/service/gateway-<name> 查看原始 supervisor 状态(注意 /command/ 仅在监管树进程的 PATH 中;从 docker exec 调用时请传入绝对路径)。

升级

拉取最新镜像并重建容器。你的数据目录不受影响。

docker pull nousresearch/hermes-agent:latest
docker rm -f hermes
docker run -d \
  --name hermes \
  --restart unless-stopped \
  -v ~/.hermes:/opt/data \
  nousresearch/hermes-agent gateway run

或使用 Docker Compose

docker compose pull
docker compose up -d

技能与凭据文件

当使用 Docker 作为执行环境时(不是上述方法,而是 agent 在 Docker 沙箱内运行命令——参见 配置 → Docker 后端Hermes 为所有工具调用复用单个长期运行的容器,并自动将技能目录(~/.hermes/skills/)和技能声明的所有凭据文件以只读卷的形式绑定挂载到该容器中。技能脚本、模板和引用在沙箱内无需手动配置即可使用,由于容器在 Hermes 进程的整个生命周期内持续存在,你安装的任何依赖或写入的文件都会在下次工具调用时保留。

SSH 和 Modal 后端也会进行相同的同步——技能和凭据文件在每次命令执行前通过 rsync 或 Modal mount API 上传。

在容器中安装更多工具

官方镜像预装了一套精选工具(参见 Dockerfile 说明),但并非 agent 可能需要的每个工具都已预装。以下是五种推荐方式,按工作量和持久性递增排列。

npm 或 Python 工具——使用 npxuvx

对于发布到 npm 或 PyPI 的任何工具,指示 Hermes 通过 npxnpmuvxPython运行并将该命令记入其持久记忆。如果工具需要配置文件或凭据指示其将这些文件放在 /opt/data 下(如 /opt/data/<tool>/config.yaml)。

依赖按需获取并在容器生命周期内缓存。写入 /opt/data 的配置在容器重启后仍然存在,因为它位于绑定挂载的宿主机目录上。包缓存本身在 docker rm 后会重建,但 npxuvx 会在下次运行工具时透明地重新获取。

其他工具apt 包、二进制文件)——安装并记住

对于 npm 或 PyPI 之外的工具——apt 包、预构建二进制文件、镜像中未包含的语言运行时——指示 Hermes 如何安装(如 apt-get update && apt-get install -y <package>并告知它记住该安装命令。工具在容器剩余生命周期内持续可用Hermes 在容器重启后下次需要该工具时会重新运行安装命令。

这种方式适合安装快速且偶尔使用的工具。对于频繁使用的工具,建议采用下一种方式。

持久安装——构建派生镜像

当工具必须在每次容器启动时立即可用且无需重新安装延迟时,构建一个继承自 nousresearch/hermes-agent 并在层中安装该工具的新镜像:

FROM nousresearch/hermes-agent:latest

USER root
RUN apt-get update \
    && apt-get install -y --no-install-recommends <your-package> \
    && rm -rf /var/lib/apt/lists/*
USER hermes

构建并替换官方镜像使用:

docker build -t my-hermes:latest .
docker run -d \
  --name hermes \
  --restart unless-stopped \
  -v ~/.hermes:/opt/data \
  -p 8642:8642 \
  my-hermes:latest gateway run

入口点脚本和 /opt/data 语义原样继承,本页其余内容仍然适用。拉取更新的上游 nousresearch/hermes-agent 时记得重新构建镜像。

复杂工具或多服务栈——运行 sidecar 容器

对于自带服务数据库、Web 服务器、队列、无头浏览器集群)或过于庞大而不适合放在 Hermes 容器内的工具,将其作为独立容器运行在共享 Docker 网络上。Hermes 通过容器名称访问 sidecar与访问本地推理服务器的方式相同参见 连接本地推理服务器)。

services:
  hermes:
    image: nousresearch/hermes-agent:latest
    container_name: hermes
    restart: unless-stopped
    command: gateway run
    ports:
      - "8642:8642"
    volumes:
      - ~/.hermes:/opt/data
    networks:
      - hermes-net

  my-tool:
    image: example/my-tool:latest
    container_name: my-tool
    restart: unless-stopped
    networks:
      - hermes-net

networks:
  hermes-net:
    driver: bridge

在 Hermes 容器内sidecar 可通过 http://my-tool:<port> 访问(或其提供的任何协议)。这种模式使每个服务的生命周期、资源限制和升级节奏保持独立,避免因单个工具的依赖而使 Hermes 镜像臃肿。

广泛有用的工具——提交 issue 或 pull request

如果某个工具可能对大多数 Hermes Agent 用户有用,考虑将其贡献到上游,而不是在私有派生镜像中维护。在 hermes-agent 仓库提交 issue 或 pull request描述该工具及其使用场景。被纳入官方镜像的工具惠及所有用户并避免了维护下游 fork 的开销。

连接本地推理服务器vLLM、Ollama 等)

在 Docker 中运行 Hermes 且推理服务器vLLM、Ollama、text-generation-inference 等)也在宿主机或另一个容器中运行时,网络配置需要额外注意。

Docker Compose推荐

将两个服务放在同一 Docker 网络上。这是最可靠的方式:

services:
  vllm:
    image: vllm/vllm-openai:latest
    container_name: vllm
    command: >
      --model Qwen/Qwen2.5-7B-Instruct
      --served-model-name my-model
      --host 0.0.0.0
      --port 8000
    ports:
      - "8000:8000"
    networks:
      - hermes-net
    deploy:
      resources:
        reservations:
          devices:
            - capabilities: [gpu]

  hermes:
    image: nousresearch/hermes-agent:latest
    container_name: hermes
    restart: unless-stopped
    command: gateway run
    ports:
      - "8642:8642"
    volumes:
      - ~/.hermes:/opt/data
    networks:
      - hermes-net

networks:
  hermes-net:
    driver: bridge

然后在 ~/.hermes/config.yaml 中,使用容器名称作为主机名:

model:
  provider: custom
  model: my-model
  base_url: http://vllm:8000/v1
  api_key: "none"

:::tip 关键点

  • 使用容器名称vllm)作为主机名——而非 localhost127.0.0.1,它们指向 Hermes 容器本身。
  • model 值必须与传给 vLLM 的 --served-model-name 一致。
  • api_key 设为任意非空字符串vLLM 要求该请求头,但默认不验证其值)。
  • base_url 末尾不要加斜杠。 :::

独立 Docker run无 Compose

如果推理服务器直接在宿主机上运行(不在 Docker 中),在 macOS/Windows 上使用 host.docker.internal,在 Linux 上使用 --network host

macOS / Windows

docker run -d \
  --name hermes \
  -v ~/.hermes:/opt/data \
  -p 8642:8642 \
  nousresearch/hermes-agent gateway run
# config.yaml
model:
  provider: custom
  model: my-model
  base_url: http://host.docker.internal:8000/v1
  api_key: "none"

Linuxhost 网络):

docker run -d \
  --name hermes \
  --network host \
  -v ~/.hermes:/opt/data \
  nousresearch/hermes-agent gateway run
# config.yaml
model:
  provider: custom
  model: my-model
  base_url: http://127.0.0.1:8000/v1
  api_key: "none"

:::warning 使用 --network host 时,-p 标志会被忽略——所有容器端口直接暴露在宿主机上。 :::

验证连通性

从 Hermes 容器内部确认推理服务器可达:

docker exec hermes curl -s http://vllm:8000/v1/models

你应该看到列出已服务模型的 JSON 响应。如果失败,请检查:

  1. 两个容器是否在同一 Docker 网络上(docker network inspect hermes-net
  2. 推理服务器是否监听 0.0.0.0 而非 127.0.0.1
  3. 端口号是否匹配

Ollama

Ollama 的配置方式相同。如果 Ollama 在宿主机上运行,使用 host.docker.internal:11434macOS/Windows127.0.0.1:11434Linux 使用 --network host)。如果 Ollama 在同一 Docker 网络的独立容器中运行:

model:
  provider: custom
  model: llama3
  base_url: http://ollama:11434/v1
  api_key: "none"

故障排查

容器立即退出

检查日志:docker logs hermes。常见原因:

  • .env 文件缺失或无效——先以交互方式运行以完成设置
  • 开放端口时存在端口冲突

"Permission denied" 错误

容器的 stage2 hook 通过 s6-setuidgid 在每个受监管的服务内将权限降至非 root 用户 hermesUID 10000。如果宿主机的 ~/.hermes/ 由不同 UID 拥有,请设置 HERMES_UID/HERMES_GID 以匹配宿主机用户,或确保数据目录可写:

chmod -R 755 ~/.hermes

浏览器工具无法使用

Playwright 需要共享内存。在 Docker run 命令中添加 --shm-size=1g

docker run -d \
  --name hermes \
  --shm-size=1g \
  -v ~/.hermes:/opt/data \
  nousresearch/hermes-agent gateway run

网络问题后 gateway 无法重连

--restart unless-stopped 标志可处理大多数瞬时故障。如果 gateway 卡住,重启容器:

docker restart hermes

检查容器健康状态

docker logs --tail 50 hermes          # 最近日志
docker run -it --rm nousresearch/hermes-agent:latest version     # 验证版本
docker stats hermes                    # 资源使用情况