How to Run Hermes Agent in Docker Compose with Caddy Reverse Proxy & Keycloak Authentication

Running autonomous AI agents in production requires robust infrastructure, proper network isolation, automated TLS certificates, and secure access control. In this guide, we walk through deploying Hermes Agent inside Docker containers using Docker Compose, fronted by a Caddy reverse proxy for automated HTTPS management, and integrated with Keycloak for robust identity and access management.

Architecture Overview

Our stack consists of three primary services running on a shared Docker bridge network (multiwp):

  • Caddy (v2): Acts as our edge reverse proxy, handling incoming HTTP/HTTPS traffic on ports 80 and 443, automatically provisioning SSL/TLS certificates via Let’s Encrypt, and routing traffic to internal container endpoints.
  • Keycloak: Provides authentication and identity management (oauth.example.com).
  • Hermes Agent: The core autonomous agent container (nousresearch/hermes-agent:latest), running the gateway service with dashboard capabilities enabled (hermes.example.com).

1. Requirements

There a few requirements to implement this stack:

  • A Linux server (VPS) to host the stack. This articles describes setting up hermes on the public internet. There are plenty of guides on the Internet how to acquire a VPS server.
  • Make sure the servers is provisioned with a public IP address, this is important for the step above.
  • Docker and Docker compose installed on the VPS

Once the requirements are fulfilled, proceed with the post.

2. Setting Up DNS

Before deploying your containers, configure your domain’s DNS records to point to your server’s public IP address using any provider of choice (e.g., Cloudflare, Route53, Namecheap, DigitalOcean DNS). Refer to the provider’s documentation to update A records.

*** MAKE SURE TO REPLACE example.com WITH A DOMAIN YOU ACTUALLY OWN ***

Create A Records for your services:

  • hermes.example.com → Points to your server public VPS server IP
  • oauth.example.com → Points to your server public VPS server IP

3. Docker Compose Configuration

The following docker-compose.yml file defines our network, resource limits, persistent volumes, and container settings:

services:

  caddy:
    container_name: caddy
    image: caddy:2
    deploy:
      resources:
        limits:
          memory: 256M
        reservations:
          memory: 128M
    depends_on:
      - keycloak
      - hermes
    restart: always
    volumes:
      - caddydata:/data
      - type: bind
        source: ./caddy/etc/caddy
        target: /etc/caddy
    ports:
      - "80:80"
      - "443:443"
    networks:
      multiwp:
        ipv4_address: 172.18.0.10

  keycloak:
    image: keycloak/keycloak:latest
    container_name: keycloak-auth
    environment:
      KC_BOOTSTRAP_ADMIN_USERNAME: admin
      KC_BOOTSTRAP_ADMIN_PASSWORD: THESECUREPASSWORD
      KC_HOSTNAME: https://oauth.example.com
      KC_HTTP_ENABLED: "true"
    deploy:
      resources:
        limits:
          memory: 1G
        reservations:
          memory: 512M
    restart: always
    volumes:
      - keycloak_data:/opt/keycloak/data/
    networks:
      multiwp:
        ipv4_address: 172.18.0.20
    command:
      - start
      - --proxy-headers=xforwarded

  hermes:
    image: nousresearch/hermes-agent:latest
    container_name: hermes
    restart: always
    command: gateway run
    volumes:
      - /opt/hermes-stack/hermes-data:/opt/data
    environment:
      - HERMES_DASHBOARD=1
    deploy:
      resources:
        limits:
          memory: 4G
        reservations:
          memory: 1G
    networks:
      multiwp:
        ipv4_address: 172.18.0.30

volumes:
  caddydata:
  keycloak_data:
  
networks:
  multiwp:
    internal: false
    ipam:
      config:
        - subnet: 172.18.0.0/16

4. Caddy Reverse Proxy Configuration

Caddy makes TLS termination and proxy routing effortless. Create your Caddyfile at ./caddy/etc/caddy/Caddyfile:

{
	on_demand_tls {
		ask http://localhost:5555/
	}
}

http://localhost:5555 {
	respond 200
}

# Keycloak SSO
oauth.example.com {
        tls {
                on_demand
        }
        reverse_proxy http://keycloak:8080
}

# Hermes Agent Dashboard & Gateway
hermes.example.com {
        tls {
                on_demand
        }
        reverse_proxy http://hermes:9119
}

5. Deployment & Verification

  1. Create your directory structure and save the configuration files:
    mkdir -p /opt/hermes-stack/caddy/etc/caddy
    cd /opt/hermes-stack
  2. Place docker-compose.yml in /opt/hermes-stack/ and Caddyfile in /opt/hermes-stack/caddy/etc/caddy/.
  3. Spin up the containers:
    docker compose up -d
  4. Verify logs to ensure all services initialized correctly:
    docker compose logs -f

You now have a fully containerized, secure Hermes Agent deployment running behind Caddy with automated HTTPS and Keycloak authentication ready for production use!

6. Loggin in to Keycloak and Hermes and finish the initial Setup

At this point, you can access the two domains from your browser oauth.example.com and hermes.example.com.

Setting up keycloak and hermes will be discuss in the Part 2 of this post. Coming soon…

Leave a Reply