Files
hermes-control-panel/docker-compose.yml
T
ZachariahSharma 74e276af92 fix: bind published ports to loopback and fix runHermes hang
- Ports now bind to HERMES_PUBLISHED_BIND_IP (default 127.0.0.1) so
  NPM on the same host proxies to 127.0.0.1:7843/8645/8646 and direct
  LAN/internet access is blocked without firewall rules
- runHermes: settle promise immediately on timeout (SIGKILL) instead of
  waiting for close event — prevents hanging when hermes spawns children
  that keep stdout/stderr open after the parent is killed
- Add HERMES_ADMIN_COOKIE_SECURE env var to set Secure flag on admin
  session cookie when the admin UI is served over HTTPS
- Document NPM deployment shapes in README

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 21:01:10 -06:00

189 lines
6.0 KiB
YAML

x-hermes-build: &hermes-build
context: .
dockerfile: Dockerfile
x-hermes-environment: &hermes-environment
HOME: /home/hermes
HERMES_HOME: /home/hermes/.hermes
HERMES_EXE: /home/hermes/.hermes/hermes-agent/venv/bin/hermes
CODEX_HOME: /home/hermes/.codex
CLAUDE_CONFIG_DIR: /home/hermes/.claude
GEMINI_CONFIG_DIR: /home/hermes/.gemini
NO_COLOR: "1"
HERMES_NO_TUI: "1"
x-hermes-volumes: &hermes-volumes
- type: bind
source: ${HERMES_HOME_HOST:-/opt/hermes-control-plane/hermes}
target: /home/hermes/.hermes
bind:
create_host_path: true
- type: bind
source: ${CODEX_HOME_HOST:-/opt/hermes-control-plane/codex}
target: /home/hermes/.codex
bind:
create_host_path: true
- type: bind
source: ${CLAUDE_HOME_HOST:-/opt/hermes-control-plane/claude}
target: /home/hermes/.claude
bind:
create_host_path: true
- type: bind
source: ${GEMINI_HOME_HOST:-/opt/hermes-control-plane/gemini}
target: /home/hermes/.gemini
bind:
create_host_path: true
x-db-url: &db-url "postgresql://hermes:${POSTGRES_PASSWORD:-hermes-change-me}@hermes-postgres:5432/hermes"
services:
hermes-postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: hermes
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-hermes-change-me}
POSTGRES_DB: hermes
volumes:
- hermes-postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U hermes -d hermes"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
hermes-control-plane:
build: *hermes-build
image: hermes-control-plane:local
user: ${HERMES_CONTAINER_USER:-0:0}
restart: unless-stopped
ports:
- "${HERMES_PUBLISHED_BIND_IP:-127.0.0.1}:${HERMES_SETUP_UI_PORT:-7843}:7843"
environment:
<<: *hermes-environment
HERMES_SETUP_UI_HOST: 0.0.0.0
HERMES_SETUP_UI_PORT: 7843
DATABASE_URL: *db-url
HERMES_ADMIN_USERNAME: ${HERMES_ADMIN_USERNAME:-admin}
HERMES_ADMIN_PASSWORD: ${HERMES_ADMIN_PASSWORD}
HERMES_ADMIN_SESSION_TTL_HOURS: ${HERMES_ADMIN_SESSION_TTL_HOURS:-12}
HERMES_ADMIN_COOKIE_SECURE: ${HERMES_ADMIN_COOKIE_SECURE:-false}
HERMES_LOG_RETENTION_DAYS: ${HERMES_LOG_RETENTION_DAYS:-90}
volumes: *hermes-volumes
depends_on:
hermes-postgres:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:7843/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
hermes-pre-upstream:
build: *hermes-build
image: hermes-control-plane:local
user: ${HERMES_CONTAINER_USER:-0:0}
restart: unless-stopped
expose:
- "8645"
command:
- /bin/sh
- -lc
- exec "$$HERMES_EXE" proxy start --provider "$$HERMES_PRE_AI_PROVIDER" --host 0.0.0.0 --port 8645
environment:
<<: *hermes-environment
HERMES_PRE_AI_PROVIDER: ${HERMES_PRE_AI_PROVIDER:-nous}
volumes: *hermes-volumes
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:8645/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
hermes-post-upstream:
build: *hermes-build
image: hermes-control-plane:local
user: ${HERMES_CONTAINER_USER:-0:0}
restart: unless-stopped
expose:
- "8642"
command:
- /bin/sh
- -lc
- exec "$$HERMES_EXE" gateway run --replace --accept-hooks
environment:
<<: *hermes-environment
API_SERVER_ENABLED: "true"
API_SERVER_HOST: 0.0.0.0
API_SERVER_PORT: 8642
HERMES_POST_AI_PROVIDER: ${HERMES_POST_AI_PROVIDER:-nous}
volumes: *hermes-volumes
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:8642/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
hermes-pre-api:
build: *hermes-build
image: hermes-control-plane:local
user: ${HERMES_CONTAINER_USER:-0:0}
restart: unless-stopped
command: ["node", "/app/api-gateway.cjs"]
ports:
- "${HERMES_PUBLISHED_BIND_IP:-127.0.0.1}:${HERMES_PRE_AI_API_PORT:-8645}:8645"
environment:
DATABASE_URL: *db-url
HERMES_API_ROUTE_KIND: pre
HERMES_API_GATEWAY_HOST: 0.0.0.0
HERMES_API_GATEWAY_PORT: 8645
HERMES_UPSTREAM_URL: http://hermes-pre-upstream:8645
HERMES_LOG_RETENTION_DAYS: ${HERMES_LOG_RETENTION_DAYS:-90}
HERMES_AUDIT_MAX_BYTES: ${HERMES_AUDIT_MAX_BYTES:-10485760}
depends_on:
hermes-postgres:
condition: service_healthy
hermes-pre-upstream:
condition: service_started
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:8645/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
hermes-post-api:
build: *hermes-build
image: hermes-control-plane:local
user: ${HERMES_CONTAINER_USER:-0:0}
restart: unless-stopped
command: ["node", "/app/api-gateway.cjs"]
ports:
- "${HERMES_PUBLISHED_BIND_IP:-127.0.0.1}:${HERMES_POST_AI_API_PORT:-8646}:8646"
environment:
DATABASE_URL: *db-url
HERMES_API_ROUTE_KIND: post
HERMES_API_GATEWAY_HOST: 0.0.0.0
HERMES_API_GATEWAY_PORT: 8646
HERMES_UPSTREAM_URL: http://hermes-post-upstream:8642
HERMES_LOG_RETENTION_DAYS: ${HERMES_LOG_RETENTION_DAYS:-90}
HERMES_AUDIT_MAX_BYTES: ${HERMES_AUDIT_MAX_BYTES:-10485760}
depends_on:
hermes-postgres:
condition: service_healthy
hermes-post-upstream:
condition: service_started
healthcheck:
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:8646/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
volumes:
hermes-postgres-data: