docs: clarify docker host and home paths
This commit is contained in:
@@ -3,6 +3,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Docker docs now explain host-localhost URLs (`host.docker.internal` / `host.containers.internal`) and the `sudo docker compose` `$HOME=/root` bind-mount pitfall for users whose WebUI cannot reach host APIs or see `~/.hermes` (#3012, #3006).
|
||||
|
||||
## [v0.51.168] — 2026-05-30 — Release EN (stage-batch50 — hotfix: mobile "Failed to load conversation messages")
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -245,6 +245,8 @@ docker compose up -d
|
||||
# Open http://localhost:8787
|
||||
```
|
||||
|
||||
Run Compose as the user who owns your Hermes home. `sudo docker compose up -d` can make `${HOME}` expand to the root user's home, so Docker mounts the wrong `.hermes` directory instead of your real `~/.hermes` and the WebUI starts with `config.yaml (not found, using defaults)`. Prefer adding your user to the Docker group and running `docker compose up -d`; if you must use sudo, set absolute paths first, for example `HERMES_HOME=/home/you/.hermes HERMES_WORKSPACE=/home/you/workspace sudo -E docker compose up -d`, then verify with `docker compose config`.
|
||||
|
||||
The container auto-detects your UID/GID from the mounted `~/.hermes` volume so files written by the agent stay readable by you on the host.
|
||||
|
||||
To enable password protection (required if you expose the port outside `127.0.0.1`):
|
||||
@@ -308,6 +310,8 @@ Both compose files use **named Docker volumes** by default, which solves the UID
|
||||
| `git: command not found` in chat | Two-container architectural limit (#681) | Use single-container or extend Dockerfile |
|
||||
| WebUI can't find agent source | `hermes-agent-src` volume misconfigured | Use the named volumes from compose files as-is |
|
||||
| Podman shared `.hermes` fails | Podman 3.4 `keep-id` limitation | Use Podman 4+ or single-container |
|
||||
| Host API at `localhost` fails from WebUI | Container `localhost` means the container, not your host (#3012) | Use `http://host.docker.internal:<port>` on Docker Desktop, or `http://host.containers.internal:<port>` on Podman |
|
||||
| WebUI can't see `~/.hermes` after `sudo docker compose` | `${HOME}` expanded to the root user's home (#3006) | Run Compose as your user, or pass absolute `HERMES_HOME`/`HERMES_WORKSPACE` with `sudo -E` |
|
||||
|
||||
For the deep dive on each of these, see [`docs/docker.md`](docs/docker.md).
|
||||
|
||||
|
||||
@@ -188,6 +188,27 @@ If you must use a bind mount: pick a host path, then mount it to `/opt/hermes` i
|
||||
|
||||
**Fix**: Either upgrade to Podman 4+ (which fixes this), or use the [single-container setup](#5-minute-quickstart-single-container), or use the [community all-in-one image](https://github.com/sunnysktsang/hermes-suite).
|
||||
|
||||
### 8. "API base URL set to localhost fails from Docker" (#3012)
|
||||
|
||||
**Symptom**: A provider, local model server, webhook, or custom API works on the host at `http://localhost:<port>`, but fails when the same URL is configured in Hermes WebUI running in Docker.
|
||||
|
||||
**Cause**: Inside a container, `localhost` means *that container*, not your laptop/host. The WebUI process cannot reach host services through `127.0.0.1` unless the service is running inside the same container.
|
||||
|
||||
**Fix**: Point Docker-hosted WebUI at the host gateway name instead:
|
||||
|
||||
- Docker Desktop on macOS/Windows: `http://host.docker.internal:<port>`
|
||||
- Podman: `http://host.containers.internal:<port>`
|
||||
- Linux Docker Engine: either publish the host service on the Docker bridge address, or add a host-gateway alias to your compose service:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
hermes-webui:
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
```
|
||||
|
||||
Then configure the URL as `http://host.docker.internal:<port>`. Also ensure the host service binds to an address reachable from containers (not only a loopback interface the Docker bridge cannot reach) and that your host firewall allows the connection.
|
||||
|
||||
## Multi-container architecture
|
||||
|
||||
The two- and three-container setups use **named Docker volumes** (not bind mounts) by default for a reason: named volumes solve the UID/GID problem by construction. Docker creates the volume's root directory with the correct ownership, all containers reading/writing to it see the same files, no host-side permission setup required.
|
||||
@@ -284,7 +305,8 @@ volumes:
|
||||
|
||||
1. The host directory MUST be readable by your container UID. Run `id -u` on the host and ensure `~/.hermes` is owned by that UID (or readable via group bits).
|
||||
2. ALL containers sharing the volume must run as the SAME UID/GID. Set `UID=$(id -u)` and `GID=$(id -g)` in `.env`.
|
||||
3. If your host `.env` is mode 0640, set `HERMES_SKIP_CHMOD=1` or `HERMES_HOME_MODE=0640` so the startup hook doesn't try to enforce 0600.
|
||||
3. If you run Compose with sudo, do not rely on `${HOME}` defaults: `sudo` often changes `$HOME` to `/root`, so `${HERMES_HOME:-${HOME}/.hermes}` becomes `/root/.hermes`. Prefer running Docker as your user; otherwise pass absolute paths with `sudo -E`, for example `HERMES_HOME=/home/youruser/.hermes HERMES_WORKSPACE=/home/youruser/workspace sudo -E docker compose up -d`, and confirm the rendered bind mount with `docker compose config`.
|
||||
4. If your host `.env` is mode 0640, set `HERMES_SKIP_CHMOD=1` or `HERMES_HOME_MODE=0640` so the startup hook doesn't try to enforce 0600.
|
||||
|
||||
## Reference
|
||||
|
||||
@@ -300,6 +322,8 @@ volumes:
|
||||
- #1416 — agent-image upgrade requires removing `hermes-agent-src` named volume (see [Upgrading the agent container](#upgrading-the-agent-container))
|
||||
- #1389 — `HERMES_HOME_MODE` override (fixed in v0.50.254 — agent honors `HERMES_SKIP_CHMOD` and `HERMES_HOME_MODE`)
|
||||
- #1399 — UID alignment in compose files (fixed in v0.50.260 via PR #1428 + this guide)
|
||||
- #3012 — host `localhost` API URLs fail from Docker containers (use `host.docker.internal` / `host.containers.internal`)
|
||||
- #3006 — `sudo docker compose` can mount `/root/.hermes` instead of the user's Hermes home
|
||||
- #858 — two-container `/opt/hermes` path confusion
|
||||
- #681 — tools running in WebUI container, not agent container (architectural)
|
||||
- #668 — auto-detect UID/GID from mounted volume
|
||||
|
||||
38
tests/test_issue3012_3006_docker_docs.py
Normal file
38
tests/test_issue3012_3006_docker_docs.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
README = (REPO / "README.md").read_text(encoding="utf-8")
|
||||
DOCKER_MD = (REPO / "docs" / "docker.md").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_docker_docs_explain_host_localhost_for_api_urls():
|
||||
"""#3012: container localhost is not the Docker host localhost."""
|
||||
assert "API base URL set to localhost fails from Docker" in DOCKER_MD
|
||||
assert "Inside a container, `localhost` means *that container*" in DOCKER_MD
|
||||
assert "host.docker.internal" in DOCKER_MD
|
||||
assert "host.containers.internal" in DOCKER_MD
|
||||
assert "host-gateway" in DOCKER_MD
|
||||
|
||||
|
||||
def test_readme_common_failures_mentions_host_localhost():
|
||||
assert "Host API at `localhost` fails from WebUI" in README
|
||||
assert "Container `localhost` means the container" in README
|
||||
assert "host.docker.internal" in README
|
||||
|
||||
|
||||
def test_docker_docs_warn_sudo_changes_home_bind_mount():
|
||||
"""#3006: sudo can render ${HOME}/.hermes as /root/.hermes."""
|
||||
assert "`sudo docker compose up -d` can make `${HOME}` expand to the root user's home" in README
|
||||
assert "Docker mounts the wrong `.hermes` directory instead of your real `~/.hermes`" in README
|
||||
assert "HERMES_HOME=/home/you/.hermes" in README
|
||||
|
||||
assert "sudo` often changes `$HOME` to `/root`" in DOCKER_MD
|
||||
assert "`${HERMES_HOME:-${HOME}/.hermes}` becomes `/root/.hermes`" in DOCKER_MD
|
||||
assert "HERMES_HOME=/home/youruser/.hermes" in DOCKER_MD
|
||||
assert "docker compose config" in DOCKER_MD
|
||||
|
||||
|
||||
def test_related_issues_index_references_3012_and_3006():
|
||||
related = DOCKER_MD[DOCKER_MD.index("## Related issues"):]
|
||||
assert "#3012" in related
|
||||
assert "#3006" in related
|
||||
Reference in New Issue
Block a user