'hermes gateway run' starts the messaging gateway (Signal SSE), not the :8090 web dashboard, so probing 8090 always reported unhealthy. The container's running state plus the daemon's SSE connection are the real health signal.
258 lines
8.3 KiB
YAML
258 lines
8.3 KiB
YAML
# Dankclaw stack — AI, search, development & observability services.
|
|
# Deploy: cd /home/dank/serverAppConfigs && podman-compose -f dankclaw/compose.yaml up -d
|
|
# See ../docs/Dankclaw/ and ../docs/Infrastructure/ for service documentation.
|
|
|
|
services:
|
|
# --- SearXNG stack (gluetun + searxng + valkey) --------------------------
|
|
# These three services are now boot-persistent Quadlet units, not compose
|
|
# services. They live in searxng/quadlet/ and install to
|
|
# ~/.config/containers/systemd/ on the host. searxng reuses gluetun's netns
|
|
# (Network=gluetun.container) so its traffic exits the WireGuard tunnel.
|
|
# Deploy with: scripts/deploy-searxng-quadlet.sh dankclaw
|
|
# See ../docs/Dankclaw/SearXNG.md, Gluetun.md, Valkey.md.
|
|
|
|
# --- AI image generation (ROCm GPU backend, gfx1151) ---------------------
|
|
# Built from Containerfile.comfyui on AMD's gfx1151 torch base. The GPU is
|
|
# reached via the /dev/kfd + /dev/dri passthrough (checked host-side; the run
|
|
# user is already in the render group). Only the 'video' group is added:
|
|
# rootless podman cannot map the render gid into the container namespace.
|
|
# Models + data persist under /home/dank/comfyui-data. See ../docs/Dankclaw/ComfyUI.md.
|
|
comfyui:
|
|
build:
|
|
context: .
|
|
dockerfile: Containerfile.comfyui
|
|
image: comfyui-rocm:gfx1151
|
|
container_name: comfyui
|
|
restart: unless-stopped
|
|
command: ["python", "main.py", "--listen", "0.0.0.0", "--port", "8188"]
|
|
ports:
|
|
- "8188:8188"
|
|
devices:
|
|
- /dev/kfd:/dev/kfd
|
|
- /dev/dri:/dev/dri
|
|
group_add:
|
|
- video
|
|
volumes:
|
|
- /home/dank/comfyui-data/models:/opt/ComfyUI/models
|
|
- /home/dank/comfyui-data/input:/opt/ComfyUI/input
|
|
- /home/dank/comfyui-data/output:/opt/ComfyUI/output
|
|
- /home/dank/comfyui-data/custom_nodes:/opt/ComfyUI/custom_nodes
|
|
healthcheck:
|
|
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8188/')"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 180s
|
|
|
|
# --- Chat UI + agent -----------------------------------------------------
|
|
openwebui:
|
|
image: ghcr.io/open-webui/open-webui:main
|
|
container_name: openwebui
|
|
restart: unless-stopped
|
|
environment:
|
|
OPENAI_API_BASE_URL: "${OPENAI_API_BASE_URL}"
|
|
OPENAI_API_KEY: "${OPENAI_API_KEY}"
|
|
ports:
|
|
- "3000:8080"
|
|
volumes:
|
|
- /opt/openwebui/data:/app/backend/data
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
hermes:
|
|
image: docker.io/nousresearch/hermes-agent:latest
|
|
container_name: hermes
|
|
restart: unless-stopped
|
|
# The image's default s6 entrypoint runs the interactive TUI, which exits
|
|
# without a TTY and crash-loops the container. Override it to run the
|
|
# headless gateway (the documented Docker mode). The gateway drops to the
|
|
# unprivileged hermes user (uid 10000), so the data dir must be writable by it.
|
|
entrypoint: ["bash", "-c", "hermes gateway run --force -v"]
|
|
environment:
|
|
HERMES_DATA_DIR: /data
|
|
# Point hermes's config/.env at the mounted data dir (persistent).
|
|
HERMES_HOME: /data
|
|
# Signal adapter -> the host signal-cli daemon. The container reaches the
|
|
# host via podman's host alias; 127.0.0.1 inside the container is not the host.
|
|
SIGNAL_HTTP_URL: "http://host.containers.internal:8080"
|
|
SIGNAL_ACCOUNT: "${SIGNAL_ACCOUNT}"
|
|
SIGNAL_ALLOWED_USERS: "${SIGNAL_ALLOWED_USERS}"
|
|
ports:
|
|
- "8090:8090"
|
|
volumes:
|
|
- /home/dank/hermes-data:/data
|
|
# No healthcheck: 'hermes gateway run' starts the messaging gateway (Signal
|
|
# SSE), not the :8090 web dashboard, so there is no HTTP endpoint to probe.
|
|
# The container's running state + the daemon's SSE connection are the signal.
|
|
|
|
# --- Git hosting (migrated from /opt/gitea) ------------------------------
|
|
postgres:
|
|
image: docker.io/library/postgres:16-alpine
|
|
container_name: gitea-postgres
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: gitea
|
|
POSTGRES_PASSWORD: "${GITEA_DB_PASSWORD}"
|
|
POSTGRES_DB: gitea
|
|
volumes:
|
|
- /opt/gitea/data/gitea-postgres:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U gitea"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
gitea:
|
|
image: docker.io/gitea/gitea:latest
|
|
container_name: gitea-server
|
|
restart: unless-stopped
|
|
environment:
|
|
DATABASE_TYPE: postgres
|
|
DATABASE_HOST: gitea-postgres
|
|
DATABASE_NAME: gitea
|
|
DATABASE_USER: gitea
|
|
DATABASE_PASSWD: "${GITEA_DB_PASSWORD}"
|
|
DATABASE_PORT: "5432"
|
|
USER_UID: "1000"
|
|
USER_GID: "1000"
|
|
ports:
|
|
- "3001:3000"
|
|
- "2222:22"
|
|
volumes:
|
|
- /opt/gitea/data/gitea-gitea:/data
|
|
- /etc/timezone:/etc/timezone:ro
|
|
- /etc/localtime:/etc/localtime:ro
|
|
depends_on:
|
|
- postgres
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
# --- Observability -------------------------------------------------------
|
|
prometheus:
|
|
image: docker.io/prom/prometheus:latest
|
|
container_name: prometheus
|
|
restart: unless-stopped
|
|
command:
|
|
- --config.file=/etc/prometheus/prometheus.yml
|
|
- --storage.tsdb.path=/prometheus
|
|
- --storage.tsdb.retention.time=30d
|
|
- --web.enable-lifecycle
|
|
ports:
|
|
- "9090:9090"
|
|
volumes:
|
|
- /opt/prometheus/config:/etc/prometheus
|
|
- /opt/prometheus/data:/prometheus
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:9090/-/healthy"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
grafana:
|
|
image: docker.io/grafana/grafana:latest
|
|
container_name: grafana
|
|
restart: unless-stopped
|
|
environment:
|
|
GF_SERVER_ROOT_URL: "http://grafana.dankclaw.local"
|
|
GF_SECURITY_ADMIN_USER: "${GRAFANA_ADMIN_USER}"
|
|
GF_SECURITY_ADMIN_PASSWORD: "${GRAFANA_ADMIN_PASSWORD}"
|
|
ports:
|
|
- "3002:3000"
|
|
volumes:
|
|
- /opt/grafana/data:/var/lib/grafana
|
|
- /opt/grafana/provisioning:/etc/grafana/provisioning:ro
|
|
depends_on:
|
|
- prometheus
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
loki:
|
|
image: docker.io/grafana/loki:latest
|
|
container_name: loki
|
|
restart: unless-stopped
|
|
command: ["-config.file=/etc/loki/loki-config.yaml"]
|
|
ports:
|
|
- "3100:3100"
|
|
volumes:
|
|
- /opt/loki/config:/etc/loki
|
|
- /opt/loki/data:/loki
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3100/ready"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
alloy:
|
|
image: docker.io/grafana/alloy:latest
|
|
container_name: alloy
|
|
restart: unless-stopped
|
|
volumes:
|
|
- /opt/alloy/config:/etc/alloy
|
|
- /run/systemd/journal/socket:/run/systemd/journal/socket:ro
|
|
- /var/log:/var/log:ro
|
|
- /var/lib/containers:/var/lib/containers:ro
|
|
depends_on:
|
|
- loki
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:12345/-/healthy"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
node-exporter:
|
|
image: docker.io/prom/node-exporter:latest
|
|
container_name: node-exporter
|
|
restart: unless-stopped
|
|
network_mode: host
|
|
pid: host
|
|
volumes:
|
|
- /proc:/host/proc:ro
|
|
- /sys:/host/sys:ro
|
|
- /:/rootfs:ro
|
|
command:
|
|
- --path.procfs=/host/proc
|
|
- --path.sysfs=/host/sys
|
|
- --path.rootfs=/rootfs
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:9100/metrics"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
# --- Reverse proxy + homepage -------------------------------------------
|
|
caddy:
|
|
image: docker.io/library/caddy:latest
|
|
container_name: caddy
|
|
restart: unless-stopped
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
- /opt/caddy/data:/data
|
|
- /opt/caddy/config:/config
|
|
- ../shared/homepage:/srv/homepage:ro
|
|
depends_on:
|
|
- searxng
|
|
- comfyui
|
|
- openwebui
|
|
- hermes
|
|
- gitea
|
|
- grafana
|
|
- prometheus
|
|
- loki
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:80/"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|