Remove gluetun/searxng/valkey from dankclaw/compose.yaml (they are now quadlet units) so podman-compose up can no longer fight them for the netns and port 8081. Add scripts/deploy-searxng-quadlet.sh: an idempotent installer that copies the units to ~/.config/containers/systemd/, daemon-reloads, enables them for boot, and starts them in dependency order. Safe to run on first migration and on every later change.
231 lines
6.7 KiB
YAML
231 lines
6.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:
|
|
# --- 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
|