Files
serverAppConfigs/dankclaw/compose.yaml
T
Frank e3eb5334cb feat: initialize serverAppConfigs with podman stacks for Dankserver and Dankclaw
- Dankserver stack: RomM, Copyparty, Calibre-Web, node-exporter
- Dankclaw stack: Gluetun VPN (SearXNG tunnel), SearXNG+Valkey, ComfyUI
  (CPU backend), OpenWebUI, Hermes, Gitea+Postgres (migrated), Caddy
  reverse proxy, Grafana+Prometheus+Loki+Alloy observability
- Caddyfiles with .local hostname convention and basicauth homepage
- bind-mount storage policy, no named volumes
- deploy.sh mirroring vllmScripts git workflow (push -> pull -> restart -> health)
- docs/ Obsidian vault: per-service docs from frank-default-small research
  subagents (promtail EOL -> Alloy; gitea SECRET_KEY preservation; ComfyUI --cpu)
- bats test suite at 6 seams — 22 tests green
2026-08-13 20:19:41 -07:00

276 lines
7.7 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:
# --- VPN tunnel: SearXNG outbound traffic only ---------------------------
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
restart: always
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
VPN_SERVICE_PROVIDER: "${VPN_SERVICE_PROVIDER}"
VPN_TYPE: "${VPN_TYPE}"
WIREGUARD_PRIVATE_KEY: "${WIREGUARD_PRIVATE_KEY}"
ports:
# SearXNG's published port lives on gluetun (network_mode: service:gluetun)
- "8081:8080"
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:8000/health"]
interval: 60s
timeout: 10s
retries: 3
searxng:
image: ghcr.io/searxng/searxng:latest
container_name: searxng
restart: unless-stopped
network_mode: "service:gluetun"
depends_on:
- gluetun
- valkey
environment:
SEARXNG_SECRET: "${SEARXNG_SECRET}"
SEARXNG_BASE_URL: "${SEARXNG_BASE_URL}"
volumes:
- /opt/searxng/config:/etc/searxng
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8080/healthz')"]
interval: 30s
timeout: 10s
retries: 3
valkey:
image: valkey/valkey:9-alpine
container_name: searxng-valkey
restart: always
volumes:
- /opt/searxng/valkey:/data
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
interval: 30s
timeout: 10s
retries: 3
# --- AI image generation (CPU backend; ROCm does not support gfx1151) ----
comfyui:
image: ghcr.io/comfyanonymous/comfyui:latest
container_name: comfyui
restart: unless-stopped
command: ["python", "main.py", "--cpu", "--listen", "0.0.0.0", "--port", "8188"]
ports:
- "8188:8188"
volumes:
- /opt/comfyui:/workspace
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8188/')"]
interval: 30s
timeout: 10s
retries: 3
# --- 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
environment:
HERMES_DATA_DIR: /data
ports:
- "8090:8090"
volumes:
- /opt/hermes/data:/data
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8090/')"]
interval: 30s
timeout: 10s
retries: 3
# --- 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: 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