This repository has been archived on 2026-05-20. You can view files and clone it, but cannot push or open issues or pull requests.
media-acquisition/compose/docker-compose.yml
obsidian-ai d300d83ce1 init: media-acquisition pipeline scaffold
Self-hosted BitTorrent + arr-stack + catalog-update pipeline targeting
nullstone (Debian 13). Replaces the legacy onyx -> rsync -> import
round-trip.

Contents:
- README.md          headline + ASCII architecture diagram + quickstart
- CLAUDE.md          project rules (mirrors beta-flix style)
- .gitignore         secrets dirs (.env, gluetun, qbt config, ssh keys)
- .gitleaksignore    allowlist nullstone LAN addr + Tailscale CGNAT
- docs/architecture.md   the plan in detail (gluetun + qbt + arr + catalog)
- docs/migration.md  onyx-qbt -> nullstone-qbt runbook (3 phases)
- docs/trackers.md   tracker schema + IP-pinning + ratio notes (user-curated)
- compose/docker-compose.yml  gluetun v3.40 + qbt 5.0.5 (netns=gluetun) +
                              sonarr/radarr/prowlarr (hotio) + betaflix-catalog
- compose/.env.example       documented env-var template (no secrets)
- compose/traefik/arr.yml    file-provider for qbt/sonarr/radarr/prowlarr
                             .s8n.ru subdomains, LAN+TS only via
                             trusted-only@file + authentik-forwardauth@file
- catalog/catalog.py         Flask service, ~340 LoC, /sonarr + /radarr +
                             /healthz; pulls beta-flix, inserts alphabetic
                             row into MEDIA-LIST.md, writes run log, commits
                             + pushes as obsidian-ai. Idempotent via
                             payload-hash cache.
- catalog/Dockerfile         python:3.12-slim + git + tini
- catalog/requirements.txt   flask + jinja2 + requests + gitpython + pyyaml (pinned)
- catalog/templates/*.j2     run log + catalog row Jinja templates
- catalog/README.md          service docs
- scripts/migrate-onyx.sh    phase-2 helper (rsync + .torrent ship, dry-run by default)
- scripts/add-tracker.sh     Prowlarr API helper
- scripts/killswitch-test.sh gluetun kill-switch verification (3 steps)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 01:15:43 +01:00

141 lines
3.9 KiB
YAML

# nullstone media-acquisition stack
#
# Compose file for: gluetun (VPN + kill-switch) + qBittorrent + Sonarr +
# Radarr + Prowlarr + betaflix-catalog (Forgejo committer).
#
# Place this directory under /opt/docker/media-acquisition/ on nullstone.
# Run: docker compose up -d
# Verify kill-switch: bash ../scripts/killswitch-test.sh
services:
gluetun:
image: qmcgaw/gluetun:v3.40
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
- VPN_SERVICE_PROVIDER=protonvpn
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${PVPN_WG_PRIVKEY}
- WIREGUARD_ADDRESSES=${PVPN_WG_ADDRESSES}
- SERVER_COUNTRIES=${PVPN_SERVER_COUNTRIES:-Netherlands}
- VPN_PORT_FORWARDING=on
- VPN_PORT_FORWARDING_PROVIDER=protonvpn
- FIREWALL_OUTBOUND_SUBNETS=192.168.0.0/24,172.16.0.0/12,100.64.0.0/10
- DOT=off
- TZ=${TZ:-Europe/London}
ports:
# All published on 127.0.0.1 — Traefik file-provider picks them up.
- "127.0.0.1:8080:8080" # qBittorrent WebUI
- "127.0.0.1:9696:9696" # Prowlarr
- "127.0.0.1:8989:8989" # Sonarr
- "127.0.0.1:7878:7878" # Radarr
volumes:
- ./gluetun:/gluetun
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "--tries=1", "--timeout=10", "https://ipinfo.io"]
interval: 30s
timeout: 15s
retries: 3
start_period: 30s
qbittorrent:
image: qbittorrentofficial/qbittorrent-nox:5.0.5
container_name: qbittorrent
depends_on:
gluetun:
condition: service_healthy
network_mode: "service:gluetun"
user: "1000:1000"
environment:
- QBT_LEGAL_NOTICE=confirm
- QBT_WEBUI_PORT=8080
- UMASK=022
- TZ=${TZ:-Europe/London}
volumes:
- ./qbittorrent/config:/config
- /home/user/media/_downloads:/downloads
- /home/user/media:/media
restart: unless-stopped
prowlarr:
image: ghcr.io/hotio/prowlarr:release
container_name: prowlarr
depends_on:
gluetun:
condition: service_healthy
network_mode: "service:gluetun"
environment:
- PUID=1000
- PGID=1000
- UMASK=022
- TZ=${TZ:-Europe/London}
volumes:
- ./prowlarr:/config
restart: unless-stopped
sonarr:
image: ghcr.io/hotio/sonarr:release
container_name: sonarr
depends_on:
gluetun:
condition: service_healthy
network_mode: "service:gluetun"
environment:
- PUID=1000
- PGID=1000
- UMASK=022
- TZ=${TZ:-Europe/London}
volumes:
- ./sonarr:/config
- /home/user/media:/media
restart: unless-stopped
radarr:
image: ghcr.io/hotio/radarr:release
container_name: radarr
depends_on:
gluetun:
condition: service_healthy
network_mode: "service:gluetun"
environment:
- PUID=1000
- PGID=1000
- UMASK=022
- TZ=${TZ:-Europe/London}
volumes:
- ./radarr:/config
- /home/user/media:/media
restart: unless-stopped
betaflix-catalog:
image: betaflix-catalog:local
container_name: betaflix-catalog
build:
context: ../catalog
dockerfile: Dockerfile
# NOT bound to gluetun — needs to reach Forgejo + Sonarr/Radarr
network_mode: bridge
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- FORGEJO_REMOTE=${FORGEJO_REMOTE:-https://git.s8n.ru/s8n/beta-flix.git}
- FORGEJO_PUSH_TOKEN=${FORGEJO_PUSH_TOKEN}
- GIT_AUTHOR_NAME=obsidian-ai
- GIT_AUTHOR_EMAIL=obsidian-ai@s8n.ru
- GIT_COMMITTER_NAME=obsidian-ai
- GIT_COMMITTER_EMAIL=obsidian-ai@s8n.ru
- SONARR_API_KEY=${SONARR_API_KEY}
- RADARR_API_KEY=${RADARR_API_KEY}
- TZ=${TZ:-Europe/London}
- LISTEN_PORT=5055
ports:
- "127.0.0.1:5055:5055"
volumes:
- ./catalog/repo:/repo
- ./catalog/ssh:/root/.ssh:ro
- ./catalog/state:/state
restart: unless-stopped