# docker compose template — ai-memory + Caddy TLS-terminating reverse proxy. # # Three usable variants, all in this one file. Pick one and either: # - Copy this file, prune the variants you don't want, then # `docker compose -f compose.tls.caddy.yml up -d`, or # - Use it verbatim and switch via the `Caddyfile` you put next to # it. The compose service definitions are the same across variants. # # Adjacent files this compose expects: # ./Caddyfile — your reverse-proxy config; see variants below # ./.env.production — AI_MEMORY_AUTH_TOKEN + AI_MEMORY_ALLOWED_HOSTS + # your LLM provider creds. NOT committed. # # Walkthrough + variant explanations + client-side install: # docs/https-via-proxy.md name: ai-memory-tls services: ai-memory: image: akitaonrails/ai-memory:latest container_name: ai-memory restart: unless-stopped # No host port. Caddy reaches ai-memory over the internal docker # network; the only inbound surface is Caddy's 80/443 below. expose: - "49374" volumes: - ai-memory-data:/data env_file: - .env.production environment: - RUST_LOG=ai_memory=info,ai_memory_store=info,ai_memory_wiki=info,ai_memory_mcp=info,tracing_appender=warn healthcheck: test: ["CMD", "/usr/local/bin/ai-memory", "status"] interval: 30s timeout: 5s retries: 3 start_period: 5s caddy: image: caddy:2-alpine container_name: ai-memory-caddy restart: unless-stopped depends_on: - ai-memory ports: # 80 is needed for Let's Encrypt's HTTP-01 challenge during issuance # and renewal. Drop it when using internal-CA mode (Variant B) since # there's no ACME to solve. - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro # Persist Caddy state across recreates. caddy-data holds the # account key and issued certs — back this up; losing it forces a # re-issuance and (in LE's case) brief unavailability. - caddy-data:/data - caddy-config:/config # Only mount this for Variant C (external certs): # - /your/cert/path:/etc/caddy/certs:ro volumes: ai-memory-data: name: ai-memory-data caddy-data: caddy-config: # ────────────────────────────────────────────────────────────────────── # Variant A — Public domain + Let's Encrypt # ────────────────────────────────────────────────────────────────────── # # Put this in ./Caddyfile next to this compose file: # # memory.example.com { # reverse_proxy ai-memory:49374 # } # # Requires: # - A DNS A or AAAA record for memory.example.com → your public IP # - Port 80 + 443 reachable from the internet (for ACME challenges + serving) # # Caddy issues + auto-renews from Let's Encrypt with no operator # action after first start. Browser-trusted by every client out of # the box. # # ────────────────────────────────────────────────────────────────────── # Variant B — LAN-only + Caddy's internal CA # ────────────────────────────────────────────────────────────────────── # # Put this in ./Caddyfile: # # { # local_certs # } # # homelab.local, 192.168.1.50 { # reverse_proxy ai-memory:49374 # } # # List every hostname + IP a client will use in the site address. # Caddy puts them all in the cert's SAN. # # Requires: # - One-time install of Caddy's root cert into each client OS trust # store. Pull it with: # docker compose exec caddy cat /data/caddy/pki/authorities/local/root.crt > caddy-root.crt # Then follow the per-OS install in docs/https-via-proxy.md. # # Skipping that step gives you security theatre, not security. See # the doc for why. # # ────────────────────────────────────────────────────────────────────── # Variant C — External cert files # ────────────────────────────────────────────────────────────────────── # # Put this in ./Caddyfile: # # memory.example.com { # tls /etc/caddy/certs/memory.crt /etc/caddy/certs/memory.key # reverse_proxy ai-memory:49374 # } # # Uncomment the cert volume mount in the caddy service above. # Caddy hot-reloads certs on file change — no compose restart needed # at renewal time.