# 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 (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: 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