-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathdocker-compose.two-container.yml
More file actions
147 lines (143 loc) · 6.41 KB
/
docker-compose.two-container.yml
File metadata and controls
147 lines (143 loc) · 6.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# Two-container Docker Compose: Hermes Agent + Hermes WebUI
#
# QUICK START:
# docker compose -f docker-compose.two-container.yml up -d
# Open http://localhost:8787
#
# This runs the agent and web UI in separate containers connected via shared
# Docker volumes. The WebUI installs the agent's Python dependencies from the
# shared agent source volume at startup.
#
# WHEN TO USE THIS:
# - You want isolation between the agent gateway and the WebUI
# - You're already running hermes-agent in its own container
# - You don't need the dashboard (use docker-compose.three-container.yml for that)
#
# WHEN NOT TO USE THIS:
# - You hit "Permission denied" trying to share an existing ~/.hermes directory
# → use docker-compose.yml (single-container) instead, OR
# → keep this file but switch to NAMED VOLUMES (the default) instead of bind mounts
# - You're on Podman 3.4 or older without keep-id namespace support
# → see https://github.com/sunnysktsang/hermes-suite for an all-in-one image
#
# KNOWN LIMITATION (#681): tools triggered from the WebUI run in the WebUI
# container, not the agent container. If you need git/node/etc. on the
# WebUI's filesystem, install them in the WebUI image — or use a single-
# container setup where everything lives in one place.
#
# NOTE ON VOLUMES:
# This file uses named Docker volumes (hermes-home, hermes-agent-src) which
# work out of the box on every Docker installation. If you prefer bind mounts
# to share an existing host directory:
#
# volumes:
# hermes-home:
# driver: local
# driver_opts:
# type: none
# o: bind
# device: /home/youruser/.hermes
#
# When using bind mounts, BOTH containers must mount the same host path,
# AND your host directory must be readable by UID 1000 (the default). Run:
# id -u && id -g
# to find your host UID/GID, then put them in a .env file:
# echo "UID=$(id -u)" >> .env
# echo "GID=$(id -g)" >> .env
services:
hermes-agent:
image: nousresearch/hermes-agent:latest
container_name: hermes-agent
command: gateway run
ports:
# Gateway API — exposed on localhost only.
# Other containers on hermes-net reach it via http://hermes-agent:8642.
# Remove 127.0.0.1: to expose on the host network (e.g. for remote clients).
- "127.0.0.1:8642:8642"
volumes:
# Persist config, state, sessions, skills, memory across restarts
- hermes-home:/home/hermes/.hermes
# Expose agent source so the WebUI can install dependencies from it
- hermes-agent-src:/opt/hermes
environment:
- HERMES_HOME=/home/hermes/.hermes
# Align UID/GID across containers sharing the hermes-home volume.
# Defaults to 1000 to match WANTED_UID/WANTED_GID in the webui service.
# The agent image's entrypoint already supports usermod remapping.
- HERMES_UID=${UID:-1000}
- HERMES_GID=${GID:-1000}
# Bind-mount permission handling for the agent — narrow set of overrides.
# NOTE: The agent's HERMES_HOME_MODE applies to the HERMES_HOME *directory*
# mode (default 0700) — NOT to credential files like the WebUI's variant.
# If you set this, you MUST keep the owner-execute bit so the agent can
# traverse its own home directory. 0640 BREAKS the agent (no x bit → no
# traversal). Use 0750 for group-traversable or 0701 for x-only.
# The agent's container detection (/.dockerenv) already auto-skips
# credential chmod inside Docker, so HERMES_SKIP_CHMOD is redundant here.
# - HERMES_HOME_MODE=0750
restart: unless-stopped
networks:
- hermes-net
hermes-webui:
image: ghcr.io/nesquena/hermes-webui:latest
container_name: hermes-webui
depends_on:
- hermes-agent
ports:
- "127.0.0.1:8787:8787"
volumes:
# Same hermes home as the agent — shares config, sessions, state
- hermes-home:/home/hermeswebui/.hermes
# Agent source mounted where docker_init.bash expects it.
# Mounted read-only — the WebUI only reads this volume to install
# the agent's Python dependencies at startup (`uv pip install`).
# Read-only enforces that defence-in-depth at the kernel layer.
- hermes-agent-src:/home/hermeswebui/.hermes/hermes-agent:ro
# Workspace directory — browse and edit files from the WebUI.
# Adapt the host path to your project directory.
# Override with: HERMES_WORKSPACE=/your/path docker compose up
# ${HOME} is used rather than `~` so the default resolves the same way
# across Linux, macOS, WSL2, and Docker Desktop on Windows.
- ${HERMES_WORKSPACE:-${HOME}/workspace}:/workspace
environment:
- HERMES_WEBUI_HOST=0.0.0.0
- HERMES_WEBUI_PORT=8787
- HERMES_WEBUI_STATE_DIR=/home/hermeswebui/.hermes/webui
# Match your host user's UID/GID for correct file permissions.
# In two-container setups the WebUI auto-detects UID/GID from the shared
# hermes-home volume, but you can override explicitly if needed (#668):
# Run `id -u` and `id -g` to find your values.
# On macOS, UIDs start at 501 — set these in a .env file:
# echo "UID=$(id -u)" >> .env && echo "GID=$(id -g)" >> .env
- WANTED_UID=${UID:-1000}
- WANTED_GID=${GID:-1000}
# Optional: set a password for remote access
# - HERMES_WEBUI_PASSWORD=your-secret-password
# Bind-mount permission handling for the WebUI (fixes #1389, #1399).
# NOTE: WebUI's HERMES_HOME_MODE is a credential-file threshold (allow
# group bits on .env/.signing_key/etc.), DIFFERENT from the agent's
# which applies to the HERMES_HOME directory itself. 0640 is correct
# for the WebUI; do NOT copy this value to the agent service block.
# - HERMES_SKIP_CHMOD=1
# - HERMES_HOME_MODE=0640
restart: unless-stopped
networks:
- hermes-net
networks:
hermes-net:
driver: bridge
volumes:
# IMPORTANT — upgrading the agent image:
# The `hermes-agent-src` volume is initialised from the agent image's
# `/opt/hermes` on first `up`, and Docker reuses the volume verbatim on
# later runs — even after `docker pull` of a newer agent image. After
# upgrading the agent image, run:
#
# docker compose down
# docker volume rm <project>_hermes-agent-src
# docker compose pull
# docker compose up -d
#
# The full procedure (and why) is documented in docs/docker.md.
hermes-home:
hermes-agent-src: