Dankserver's node-exporter has been dead since a reboot: `podman ps -a` showed
it `Exited (143)` and Prometheus' `node-dankserver` job has been scraping
nothing. It ran only from `dankserver/compose.yaml`, which is the failure mode
this repository's boot-persistence rule exists for (rootless Podman does not
restart bare containers after the stop that shutdown performs), and the compose
form bound the wildcard address — the unauthenticated-metrics-API-on-every-
interface posture already removed on Dankclaw.
- dankserver/observability/quadlet/node-exporter.container — mirrors the
Dankclaw unit, listening on exactly 127.0.0.1:9100 (host-local probes) and
192.168.0.235:9100 (Prometheus on Dankclaw), with Restart=always and
WantedBy=default.target.
- the compose service is deleted: one owner per container name.
- deploy_observability now installs from "$TARGET/observability/quadlet"; it
hardcoded the Dankclaw path, so a Dankserver unit could not be installed by
the shared dispatcher at all.
- planner: "node-exporter" joins the Dankserver service set, with a path rule
for dankserver/observability/**; the dispatcher's allowlist gains
dankserver:node-exporter.
Seams cover the silent halves: both listen addresses present and the wildcard
absent, the compose service gone, the allowlist entry present, and the planner
mapping the path to the service.
155 lines
5.5 KiB
YAML
155 lines
5.5 KiB
YAML
# Dankserver stack — media & library services.
|
|
# Deploy: cd /home/dank/serverAppConfigs && podman-compose -f dankserver/compose.yaml up -d
|
|
# See ../docs/Dankserver/ for service documentation.
|
|
|
|
networks:
|
|
appnet:
|
|
driver: bridge
|
|
|
|
services:
|
|
# ═══════════════════════════════════════════════
|
|
# RomM — retro game manager (requires MariaDB + Redis)
|
|
# ═══════════════════════════════════════════════
|
|
mariadb:
|
|
image: docker.io/mariadb:11
|
|
container_name: romm-mariadb
|
|
restart: unless-stopped
|
|
environment:
|
|
MARIADB_ROOT_PASSWORD: "${MARIADB_ROOT_PASSWORD}"
|
|
MARIADB_DATABASE: romm
|
|
MARIADB_USER: "${ROMM_DB_USER}"
|
|
MARIADB_PASSWORD: "${ROMM_DB_PASSWD}"
|
|
volumes:
|
|
- /opt/romm/mariadb:/var/lib/mysql
|
|
healthcheck:
|
|
test: ["CMD", "mariadb-admin", "ping", "-h", "localhost"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
|
|
redis:
|
|
image: docker.io/redis:7-alpine
|
|
container_name: romm-redis
|
|
restart: unless-stopped
|
|
volumes:
|
|
- /opt/romm/redis:/data
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 3
|
|
|
|
romm:
|
|
image: ghcr.io/rommapp/romm:latest
|
|
container_name: romm
|
|
restart: unless-stopped
|
|
environment:
|
|
ROMM_USERNAME: "${ROMM_USERNAME}"
|
|
ROMM_PASSWORD: "${ROMM_PASSWORD}"
|
|
ROMM_AUTH_SECRET_KEY: "${ROMM_AUTH_SECRET_KEY}"
|
|
DB_HOST: mariadb
|
|
DB_NAME: romm
|
|
DB_USER: "${ROMM_DB_USER}"
|
|
DB_PASSWD: "${ROMM_DB_PASSWD}"
|
|
REDIS_HOST: redis
|
|
HASHEOUS_API_ENABLED: "true"
|
|
ports:
|
|
- "8085:8080"
|
|
volumes:
|
|
- /opt/romm/library:/romm/library
|
|
- /opt/romm/resources:/romm/resources
|
|
- /opt/romm/config:/romm/config
|
|
depends_on:
|
|
mariadb:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
# ═══════════════════════════════════════════════
|
|
# Copyparty — file sharing and streaming
|
|
# ═══════════════════════════════════════════════
|
|
copyparty:
|
|
image: ghcr.io/9001/copyparty-ac:latest
|
|
container_name: copyparty
|
|
restart: unless-stopped
|
|
# read-only since 2026-08-31: copyparty perms are per-field "letters[,user]"
|
|
# with no user = every unauthenticated request. Anonymous gets r (browse +
|
|
# download; the guarded files.franksdank.cloud chain reaches copyparty
|
|
# unauthenticated after authentik). dank gets ra (admin panel). No w/m/d
|
|
# anywhere: uploads, moves, deletes rejected server-side. Interface: `--help-accounts` in-image.
|
|
command: ["-a", "dank:${COPAY_PASS}", "-v", "/w::r:ra,dank"]
|
|
ports:
|
|
- "3923:3923"
|
|
volumes:
|
|
- /mnt/entropy:/w:ro
|
|
- /opt/copyparty/cfg:/cfg
|
|
healthcheck:
|
|
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:3923/')"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
# ═══════════════════════════════════════════════
|
|
# Jellyfin — media server (movies, TV, music)
|
|
# ═══════════════════════════════════════════════
|
|
jellyfin:
|
|
image: jellyfin/jellyfin:latest
|
|
container_name: jellyfin
|
|
restart: unless-stopped
|
|
ports:
|
|
- "8096:8096/tcp"
|
|
- "8920:8920/tcp"
|
|
- "7359:7359/udp"
|
|
- "1900:1900/udp"
|
|
environment:
|
|
- JELLYFIN_PublishedServerUrl=http://192.168.0.235:8096
|
|
- DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true
|
|
volumes:
|
|
- /opt/jellyfin/config:/config
|
|
- /opt/jellyfin/cache:/cache
|
|
- /mnt/entropy:/data:ro
|
|
devices:
|
|
- /dev/dri:/dev/dri
|
|
group_add:
|
|
- "992"
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8096/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
# ═══════════════════════════════════════════════
|
|
# Calibre-Web — e-book web frontend
|
|
# ═══════════════════════════════════════════════
|
|
calibre-web:
|
|
image: lscr.io/linuxserver/calibre-web:0.6.27-ls397
|
|
container_name: calibre-web
|
|
restart: unless-stopped
|
|
environment:
|
|
PUID: "1000"
|
|
PGID: "1000"
|
|
TZ: Etc/UTC
|
|
OAUTHLIB_RELAX_TOKEN_SCOPE: "1"
|
|
ports:
|
|
- "8083:8083"
|
|
volumes:
|
|
- /opt/calibre-web/config:/config
|
|
- /opt/calibre-web/books:/books
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8083/"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
|
|
|
|
# node-exporter left this file on 2026-09-16 for
|
|
# dankserver/observability/quadlet/node-exporter.container: a compose-only
|
|
# container does not survive a reboot here — it died `Exited (143)` and stayed
|
|
# dead, leaving Prometheus' node-dankserver job scraping nothing — and the
|
|
# compose form bound the wildcard address. One owner per container name.
|