Hermes Agent runs well in Docker, but Docker failures often look scarier than they are because the real problem is usually ownership, mounted state, provider config, or gateway reachability. Start with the container boundary before you rewrite Hermes config, then compare the broader install and update troubleshooting guide if the same failure also appears outside Docker.
Quick answer#
When Hermes fails in Docker, keep ~/.hermes mounted and intact, update to the latest Hermes image or checkout, run hermes doctor inside the container, inspect file ownership on the mounted Hermes home, confirm provider secrets are visible to the container, then restart the gateway and dashboard separately. Do not solve a Docker UID error by deleting memory, sessions, skills, or config. If you do not want to own this operational loop, use FlyHermes for the hosted path instead of running a 24/7 VPS yourself.
Fix vision tool failures inside Docker#
A current community report describes Hermes running with LM Studio or OMLX while every vision-tool call fails inside Docker. Do not treat that as one generic “vision is broken” problem. Test four boundaries in order:
- Model capability: confirm the selected chat model actually accepts images. A model can be excellent at text and tool calling while lacking multimodal input. Compare the local LLM guide before assuming the container is at fault.
- Vision tool availability: run
hermes tools listinside the same container and confirm the vision toolset is enabled and its provider requirements are satisfied. Tool changes require a new session. - Image reachability: a host path such as
/Users/name/Desktop/test.pngdoes not exist inside the container unless it is mounted. Copy one small known image into a mounted path, then test that exact container-visible path. For remote images, verify the container can resolve DNS and fetch the HTTPS URL. - Provider routing: model-native vision and Hermes auxiliary vision are separate paths. Verify the configured provider, credentials, model name, and one direct smoke test before debugging browser automation.
Use this copy-paste boundary check inside the container:
hermes doctor
hermes tools list
python3 - <<'PY'
from pathlib import Path
p = Path('/opt/data/vision-smoke-test.png')
print({'exists': p.exists(), 'bytes': p.stat().st_size if p.exists() else 0})
PY
Then start a new Hermes session and ask it to describe only that known image. Record the exact failing layer: model rejects image input, vision tool is absent, file is missing, HTTPS fetch fails, or provider returns an authentication/rate-limit error. That evidence is more useful than repeatedly changing Docker networking.
Vision is not browser automation#
The Hermes browser automation troubleshooting guide covers cloud sessions, Chrome DevTools Protocol, 502 responses, CAPTCHAs, and browser-container networking. Use it only after a known-image vision smoke test passes. A browser can fail while model vision works, and model vision can fail while the browser opens normally.
Host paths, container paths, and localhost#
Three path mistakes explain many Docker vision failures:
- A host file path was never volume-mounted into the container.
- The file exists, but the container user cannot read it because of UID or permission mismatch.
- A local model or image server is bound to host
127.0.0.1; inside Docker,localhostpoints back to the container, not the host.
On Docker Desktop, a host service may be reachable through host.docker.internal; on Linux, configure an explicit host-gateway or shared network rather than copying that hostname blindly. Keep the model endpoint private and prove reachability with a harmless health request before exposing any port. The Docker Compose setup guide covers persistent mounts, while the browser automation setup guide owns Chrome-specific networking.
The common Docker failure pattern#
Recent self-hosting discussions keep surfacing the same buyer objection: the agent is valuable, but the container work is not the job. If debugging UID remaps, mounted state, missing .env values, gateway ports, or dashboard exposure becomes the main task, use the self-hosted vs hosted AI agent guide to decide whether FlyHermes is a better fit for this workflow.
Most Docker support threads fall into one of these buckets:
- The container cannot write to the mounted Hermes home.
- A config file was created by an older Hermes version and did not migrate during boot.
- Provider or MCP credentials exist on the host but not inside the container.
- The gateway is running, but the network, topic, token, or allowed-channel config is wrong.
- The dashboard is reachable on the wrong interface or exposed more widely than intended.
That is why Docker debugging should start with the runtime boundary, not with a reinstall.
Step 1: preserve state before touching the container#
Your Hermes home contains config, memory, skills, sessions, cron jobs, and gateway state. Back it up before destructive experiments:
cp -a ~/.hermes ~/.hermes.backup.$(date +%Y%m%d-%H%M%S)
Then check whether the same path is mounted into the container. A rebuilt image is normal. A missing or replaced Hermes home is not.
Step 2: update before debugging old container bugs#
The v0.15.2 patch wave and June 2026 mainline fixes matter for Docker. Recent changes added container boot config migrations, clearer rejection of unsupported arbitrary --user starts, better UID-remap ownership handling, and safer Docker command resolution for MCP servers that call npx, npm, or node.
Use the latest image or checkout, then run:
hermes doctor
hermes tools
inside the container. If hermes doctor cannot see your provider config, fix the mounted env/config first.
Step 3: fix UID and ownership issues directly#
If the container cannot write to ~/.hermes, inspect ownership instead of rotating tokens:
id
ls -la ~/.hermes
Avoid forcing docker run --user <random-uid> unless the image explicitly supports that path. The recent Hermes Docker fixes now fail unsupported arbitrary UID starts with clearer guidance because a random user can leave build trees, caches, or the Hermes home unwritable.
Step 4: verify provider and MCP credentials inside Docker#
A host shell may have ANTHROPIC_API_KEY, OPENAI_API_KEY, XAI_API_KEY, or MCP header secrets while the container does not. Confirm the container can see what Hermes needs without printing secret values:
python - <<'PY'
import os
for key in ['ANTHROPIC_API_KEY','OPENAI_API_KEY','XAI_API_KEY']:
print(key, 'set' if os.getenv(key) else 'missing')
PY
For MCP servers, prefer environment placeholders in config only when the container actually receives those environment variables. Recent Hermes discovery probes expand ${ENV} in header auth, so update before assuming the MCP server itself is broken.
Step 5: separate dashboard access from gateway uptime#
The Hermes Web UI is an operations dashboard. The gateway is what answers Telegram, Discord, Slack, webhooks, or other channels. Debug them separately:
- Dashboard problem: check bind host, port, reverse proxy, and auth mode.
- Gateway problem: check token, allowed channel, topic/thread routing, webhook reachability, and process logs.
- Provider problem: check model/provider credentials and rate-limit errors.
Do not expose the dashboard publicly just to make it convenient. Use localhost, VPN, SSH tunnel, or a trusted reverse proxy.
When Docker is the wrong answer#
Self-hosting gives control, but it also gives you uptime work: image updates, config migrations, mounted volumes, provider secrets, gateway restarts, and dashboard security. If the job is “give me a phone-accessible agent that keeps running,” compare self-hosted versus hosted AI agents and the 24/7 Hermes setup guide before turning one Docker error into a weekend ops project.
Docker troubleshooting checklist#
- Back up the Hermes home.
- Update Hermes image or checkout.
- Run
hermes doctorinside the container. - Confirm the mounted Hermes home path and ownership.
- Confirm provider and MCP env vars exist inside the container.
- Restart gateway and dashboard separately.
- Check logs before changing config.
- If you need managed uptime, use FlyHermes instead of maintaining a VPS.
Docker failures that look like gateway or model failures#
A container problem often surfaces as a Telegram, Discord, MCP, or provider symptom. Before changing prompts or model routes, prove the container boundary:
hermes config pathandhermes config env-pathinside the container point at the mounted Hermes home you expect.hermes doctorcan see the provider credentials without printing secrets.- File ownership lets Hermes write sessions, memory, logs, skills, and cron output.
- Gateway logs are coming from the running container, not from a stale host process.
- The dashboard/Web UI is bound only where you intend, with auth for any non-local exposure.
If the Docker checks are green but messaging still fails, move to the gateway troubleshooting guide. If Docker itself is the recurring tax, compare the hosted FlyHermes path.
Docker note: Obsidian vaults need mounted paths#
If Hermes can edit an Obsidian vault from the local CLI but not from Docker, the container probably cannot see the desktop folder. Mount the scoped vault folder explicitly and avoid mounting your entire home directory. For the safer workflow, see the Hermes Agent Obsidian integration guide and the Docker Compose setup page.
Current official-image checks: s6, /opt/data, and dashboard auth#
For the official image, add three checks before changing tokens or rebuilding:
- Confirm the host Hermes directory is mounted to container
/opt/data, not to the immutable/opt/hermesapplication tree. - Read both
docker logs -f hermesand the persistent per-profile log at host~/.hermes/logs/gateways/default/current. s6 supervises gateway processes, so a running container and a restarted inner gateway are different states. - If the dashboard exits, check authentication first. A non-loopback dashboard requires Basic Auth, Nous OAuth, or OIDC and fails closed when no provider is configured.
Then run docker exec hermes hermes doctor, docker exec hermes hermes gateway status, and one real Telegram/Discord delivery test. The official Docker Compose guide covers the complete state and port contract; the dashboard guide explains what should remain private.
A running container can still have a failing gateway child#
Treat container uptime, s6 supervision, and platform delivery as three separate checks. Inspect the persistent per-profile gateway log, run hermes gateway status inside the container, and test the exact Telegram or Discord destination. A port collision or bad profile environment can make the child process respawn while the container remains green. Continue with the gateway troubleshooting runbook before recreating volumes.
Decision tree: host Ollama, sidecar Ollama, or wrong model ID#
A host-shell success is not a container success. First decide where Ollama runs. For host Ollama on macOS/Windows, test http://host.docker.internal:11434/v1/models from inside Hermes. For a sidecar, test http://ollama:11434/v1/models on the shared network. If JSON returns but Hermes fails, copy the exact tagged model ID. Continue with the Docker Compose runbook and local Ollama setup.
Host browser profiles do not become container credentials#
A host Chrome profile depends on host files, process state, and often the OS keychain. Do not copy it casually into a Hermes container. If an authenticated browser task must use local identity, keep that browser path host-local or use a deliberately isolated backend, then follow the real-profile browser troubleshooting guide.