Skip to content

How to Deploy Hermes WebUI with Docker: Single, Two, and Three Container Setups

Purpose

This post shows how to deploy Hermes WebUI with Docker. I will cover the three official compose setups, when to use each, and the common permission issues I ran into.

Environment

  • Docker with Compose plugin
  • Pre-built amd64/arm64 images on GHCR
  • docker-compose.yml, docker-compose.two-container.yml, docker-compose.three-container.yml

The Three Setups

Hermes WebUI ships with three official Docker Compose files. Here is how they differ:

SetupContainersUse Case
Single1Recommended for most users; agent runs in-process
Two2Isolates gateway (CLI/Telegram/cron) from the chat UI
Three3Adds a dashboard container for monitoring

Diagram comparing single-container, two-container, and three-container Docker deployments for Hermes WebUI

Single-Container Quickstart

This is the path I started with. It is the simplest and works for most users:

Single-container quickstart
git clone https://github.com/nesquena/hermes-webui
cd hermes-webui
cp .env.docker.example .env
docker compose up -d

The single container runs the agent in-process inside the WebUI container. It mounts ~/.hermes and ~/workspace and auto-detects your UID/GID.

Screenshot of Hermes WebUI dashboard running locally in a browser

Enabling Password Protection

Before exposing the port beyond localhost, I enabled password protection:

Enable password protection
echo "HERMES_WEBUI_PASSWORD=change-me-to-something-strong" >> .env
docker compose up -d --force-recreate

Two-Container Setup

If you need gateway isolation β€” for example, to run scheduled cron jobs or receive Telegram messages independently of the WebUI β€” use the two-container setup:

Two-container setup
docker compose -f docker-compose.two-container.yml up -d

In this mode, tools triggered from the WebUI still run in the WebUI container, but the gateway (CLI, cron, messaging) runs separately.

Manual Docker Run

If you prefer not to use Compose, you can run the pre-built image directly:

Manual docker run
docker pull ghcr.io/nesquena/hermes-webui:latest
docker run -d \
-e WANTED_UID=$(id -u) -e WANTED_GID=$(id -g) \
-v ~/.hermes:/home/hermeswebui/.hermes \
-e HERMES_WEBUI_STATE_DIR=/home/hermeswebui/.hermes/webui \
-v ~/workspace:/workspace \
-p 127.0.0.1:8787:8787 \
ghcr.io/nesquena/hermes-webui:latest

Common Errors and Fixes

I hit a few permission issues when I first tried this. Here is what I learned:

ErrorCauseFix
PermissionError on startupUID/GID mismatch between host and containerUse WANTED_UID and WANTED_GID env vars
.env permission deniedfix_credential_permissions() rejects loose permissionsSet .env to 600
Empty workspace in containerBind mount points to wrong UID homeUse absolute paths, not ~ with sudo
git: command not foundTwo-container setup, tools need git in WebUI containerInstall git in the WebUI image or mount host git

Security Hardening

The production image has a few hardening measures:

  • No sudo and no NOPASSWD
  • Entrypoint starts as root only for UID/GID alignment, then drops to an unprivileged hermeswebui user
  • python:3.12-slim as the base image

Summary

In this post, I showed how to deploy Hermes WebUI with Docker using the official compose files. The key point is to start with the single-container setup, add password protection for remote access, and scale to multi-container only when you need gateway isolation. Watch out for UID/GID mismatches when using bind mounts.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments