AdrienPoupa/docker-compose-nas: Bedah Stack NAS Kompleks dengan VPN, Arr Stack, dan Traefik

· Review

Artikel ini review repo orang lain — milik AdrienPoupa (GitHub: AdrienPoupa/docker-compose-nas). Saya bukan maintainer dan tidak terafiliasi dengan proyek ini.

Repo ini menjanjikan “Simple Docker Compose NAS” tapi sebenarnya adalah stack opinionated, production-grade dengan 20+ service, modular profile system, dan integrasi VPN WireGuard + Traefik SSL otomatis. Bintang: 2.152 (saat review). Bahasa: Shell (docker-compose.yml) + Bash (update-config.sh). Ukuran: ~258 KB, 581 baris compose utama.


Arsitektur Keseluruhan

Repo ini tidak cuma satu docker-compose.yml monolitik. Ada file compose modular yang di-include lewat COMPOSE_FILE di .env.example:

COMPOSE_FILE=docker-compose.yml:adguardhome/docker-compose.yml:tandoor/docker-compose.yml:joplin/docker-compose.yml:homeassistant/docker-compose.yml:immich/docker-compose.yml:vaultwarden/docker-compose.yml:privoxy/docker-compose.yml:paperless/docker-compose.yml

File utama (docker-compose.yml) mendefinisikan core services (traefik, sonarr, radarr, lidarr, prowlarr, bazarr, qbittorrent, unpackerr, jellyfin, seerr, homepage, watchtower, autoheal) + optional services via Docker Compose profiles (flaresolverr, sabnzbd, adguardhome, lidarr, tandoor, joplin, homeassistant, immich, vaultwarden, calibre-web, cleanuparr, cross-seed, autobrr, suggestarr, paperless).

Strategi profile memungkinkan user enable service selective tanpa edit file compose:

COMPOSE_PROFILES=adguardhome,sabnzbd,flaresolverr
docker compose up -d

VPN Integration: PIA WireGuard untuk qBittorrent Only

Salah satu desain paling menarik: hanya qBittorrent yang lewat VPN. Service vpn (image ghcr.io/thrnz/docker-wireguard-pia:latest) menyediakan network namespace WireGuard, lalu qBittorrent pakai network_mode: "service:vpn":

qbittorrent:
  image: lscr.io/linuxserver/qbittorrent:libtorrentv1
  network_mode: "service:vpn"
  depends_on:
    vpn:
      condition: service_healthy
  # ... labels traefik & homepage

vpn:
  image: ghcr.io/thrnz/docker-wireguard-pia:latest
  cap_add:
    - NET_ADMIN
    - SYS_MODULE
  environment:
    - LOC=${PIA_LOCATION}
    - USER=${PIA_USER}
    - PASS=${PIA_PASS}
    - LOCAL_NETWORK=${PIA_LOCAL_NETWORK}

Implementasi ini isolasi traffic torrent tanpa mempengaruhi *arr apps, Jellyfin, atau Homepage. VPN container juga handle port forwarding PIA (penting untuk seeding). Healthcheck VPN memastikan koneksi stabil sebelum qBittorrent start.

Kelemahan: Jika PIA token expired atau server down, qBittorrent ikut unhealthy (lihat comment di healthcheck qBittorrent merujuk issue gluetun #641). User butuh PIA subscription aktif — tidak ada fallback VPN gratis.


README menjelaskan struktur direktori untuk hardlink support (instant move, hemat storage 2x):

data/
|-- torrents/          # qBittorrent download folder
|   |-- movies/        # tagged by Radarr
|   `-- tv/            # tagged by Sonarr
`-- media/             # Sonarr/Radarr/Lidarr final files
    |-- movies/
    |-- tv/
    `-- music/

Konfigurasi volume di compose:

volumes:
  - ${DATA_ROOT}:/data

Lalu di *arr apps:

sonarr:
  volumes:
    - ${CONFIG_ROOT:-.}/sonarr:/config
    - ${DATA_ROOT}:/data
  # Root folder di Sonarr: /data/media/tv

radarr:
  volumes:
    - ${CONFIG_ROOT:-.}/radarr:/config
    - ${DATA_ROOT}:/data
  # Root folder di Radarr: /data/media/movies

Pendekatan ini standar Trash Guides dan working out-of-the-box asal user set root folder benar di UI *arr.


Traefik v3 + Let’s Encrypt DNS-01 Challenge

Traefik dikonfigurasi DNS challenge via Cloudflare (bukan HTTP-01), sehingga tidak perlu port 80/443 public. Cocok untuk NAS di belakang CGNAT atau tanpa port forwarding:

traefik:
  image: ghcr.io/traefik/traefik:3.7
  command:
    - --certificatesresolvers.myresolver.acme.dnschallenge=true
    - --certificatesresolvers.myresolver.acme.dnschallenge.provider=cloudflare
    - --certificatesresolvers.myresolver.acme.email=${LETS_ENCRYPT_EMAIL}
    - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
  volumes:
    - ${CONFIG_ROOT:-.}/letsencrypt:/letsencrypt
    - /var/run/docker.sock:/var/run/docker.sock:ro

Setiap service yang butuh HTTPS tinggal tambah label:

labels:
  - traefik.enable=true
  - traefik.http.routers.sonarr.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/sonarr`))
  - traefik.http.routers.sonarr.tls=true
  - traefik.http.routers.sonarr.tls.certresolver=myresolver
  - traefik.http.services.sonarr.loadbalancer.server.port=8989

Catatan: traefik-certs-dumper (di adguardhome compose) mengekspor sertifikat Let’s Encrypt ke folder adguardhome/certs agar AdGuard Home bisa serve DoH/DoT dengan sertifikat valid. Detail kecil tapi berguna.


Homepage Dashboard: Auto-Generated dari Template

Homepage (gethomepage) dikonfigurasi lewat template YAML di homepage/tpl/ yang di-copy otomatis saat first run:

homepage:
  command:
    [sh, -c, "cp -n /app/config/tpl/*.yaml /app/config && node server.js"]
  volumes:
    - ${CONFIG_ROOT:-.}/homepage:/app/config

Template include services.yaml, docker.yaml, widgets.yaml, settings.yaml. Setiap service di compose utama sudah include label homepage.* sehingga widget & group otomatis muncul tanpa edit manual. Contoh label Sonarr:

labels:
  - homepage.group=Media
  - homepage.name=Sonarr
  - homepage.icon=sonarr.png
  - homepage.href=/sonarr
  - homepage.description=Series management
  - homepage.widget.type=sonarr
  - homepage.widget.url=http://sonarr:8989/sonarr
  - homepage.widget.key=${SONARR_API_KEY}

Ini huge time-saver untuk homelabber yang mau dashboard rapi tanpa belajar schema Homepage dari nol.


update-config.sh: Automation Post-Deploy

Script Bash ini jalan setelah docker compose up -d pertama kali. Fungsinya:

  1. Update UrlBase di config.xml *arr apps (sonarr, radarr, lidarr, prowlarr) agar match subpath Traefik
  2. Extract API key dari config.xml → tulis ke .env
  3. Set qBittorrent password default (adminadmin) via PBKDF2 hash
  4. Konfigurasi Bazarr base_url + link ke Sonarr/Radarr
  5. Restart container terkait

Cuplikan logika update *arr:

function update_arr_config {
  sed -i.bak "s/<UrlBase><\\/UrlBase>/<UrlBase>\\/$1<\\/UrlBase>/" "${CONFIG_ROOT:-.}/$container/config.xml"
  CONTAINER_NAME_UPPER=$(echo "$container" | tr '[:lower:]' '[:upper:]')
  sed -i.bak 's/^'"${CONTAINER_NAME_UPPER}"'_API_KEY=.*/'"${CONTAINER_NAME_UPPER}"'_API_KEY='"
    $(sed -n 's/.*<ApiKey>\\(.*\\)<\\/ApiKey>.*/\\1/p' "${CONFIG_ROOT:-.}/$container/config.xml")"'/' .env
  docker compose restart "$container"
}

Kekurangan: Script ini asumsi container sudah running & config.xml exist. Kalau first-run gagal (misal permission volume), script loop forever di until [ -f ... ]. Tidak ada timeout atau error handling yang jelas.


Service Optional yang Menarik

AdGuard Home dengan DHCP Relay

dhcp-relay:
  image: modem7/dhcprelay:latest
  network_mode: host
  cap_add: [NET_ADMIN]
  command: ["-id", "enp2s0", "-iu", "br_adguard", "10.0.0.10"]
  profiles: [adguardhome-dhcp]

AdGuard Home jalan di custom bridge br_adguard (subnet 10.0.0.0/24) dengan IP statis 10.0.0.10. DHCP relay forward request dari physical interface enp2s0 ke bridge internal. Cocok untuk replace router DNS tapi butuh host network & NET_ADMIN — tidak jalan di rootless Docker atau shared hosting.

Paperless-ngx (Document Management)

paperless:
  image: paperless-ngx/paperless-ngx
  # ... env OCR, REDIS, DB_POSTGRES
  profiles: [paperless]

Include Redis & PostgreSQL sebagai dependency (tidak terlihat di compose utama, tapi di paperless/docker-compose.yml). Cocok untuk paperless office tapi resource heavy (OCR, ML tagging).

Immich (Photo/Video Backup)

immich:
  image: immich-app/immich-server:release
  # ... env DB, UPLOAD_LOCATION, MACHINE_LEARNING
  profiles: [immich]

Butuh PostgreSQL + Redis + Machine Learning container terpisah. Heavy untuk single-board computer (RAM ≥ 4GB recommended).


Kelemahan & Batasan (WAJIB Disebut)

  1. PIA Dependency Hardcoded: VPN container hanya support PIA. User mau NordVPN, Mullvad, atau self-hosted WireGuard harus ganti image & env manual. Tidak ada abstraksi provider VPN.

  2. Hardcoded UID/GID 1000: Default USER_ID=1000, GROUP_ID=1000. Di Synology/Unraid UID sering beda (misal 1026). User harus edit .env sebelum deploy, kalau tidak permission denied di volume.

  3. Single Hostname untuk Semua Service: Semua service expose via subpath (/sonarr, /radarr, /jellyfin) di satu hostname (HOSTNAME env). Tidak support subdomain per service (misal sonarr.domain.com) tanpa edit label Traefik manual. Untuk Seerr, wajib subdomain terpisah (SEERR_HOSTNAME) karena Seerr tidak support subpath.

  4. No IPv6 in Traefik Config: EntryPoints hanya :80 & :443 IPv4. User dual-stack harus tambah config manual.

  5. update-config.sh Tidak Idempotent untuk Bazarr: Logic sed Bazarr complex & fragile (match YAML dengan regex). Sudah dilaporkan issue upstream tapi belum fix.

  6. Secrets di .env Plaintext: PIA credentials, Cloudflare API token, API keys *arr semua di .env plaintext. Tidak ada integration Docker Secrets / 1Password / SOPS. Untuk production butuh secret management terpisah.

  7. Resource Limits Tidak Ada: Tidak ada deploy.resources.limits di compose. Container seperti Jellyfin (transcode), Immich (ML), Paperless (OCR) bisa makan RAM/CPU tak terbatas — berbahaya di hardware kecil.

  8. Healthcheck VPN Ganda: qBittorrent healthcheck curl dua target (localhost:8080 + google.com). Kalau internet down tapi VPN up, qBittorrent marked unhealthy -> autoheal restart -> loop. Logic agak agresif.


Cocok Untuk Siapa?

Profil UserCocok?Alasan
Homelabber punya VPS/NAS + domain + Cloudflare + PIA subscriptionYaStack lengkap, SSL auto, VPN integrated, dashboard ready
Pemula ingin belajar Docker ComposeMungkinTerlalu complex untuk “first stack”. Lebih baik mulai dari 3-4 service manual
User tanpa domain public / CGNATYaDNS-01 challenge tidak butuh port 80/443 open
User mau multi-VPN providerTidakHardcoded PIA WireGuard
Hardware terbatas (≤2GB RAM, no GPU)TidakJellyfin transcode, Immich ML, Paperless OCR butuh resource
Butuh IPv6 nativeManualTraefik config IPv4 only

Kesimpulan

AdrienPoupa/docker-compose-nas adalah salah satu stack homelab paling komprehensif & well-documented di GitHub. Bukan “simple” tapi opinionated production template yang handle:

  • Reverse proxy + SSL otomatis (Traefik + Cloudflare DNS-01)
  • Torrent isolation via WireGuard VPN (PIA)
  • *Arr stack dengan hardlink strategy benar
  • Dashboard Homepage auto-generated dari label
  • Modular profile system untuk 15+ optional service
  • Post-deploy automation via update-config.sh

Trade-off: Kompleksitas tinggi, hardcoded PIA/UID/hostname, secret management manual, resource limits nol. Cocok untuk homelabber intermediate yang sudah punya domain, Cloudflare, PIA, dan hardware decent (≥4GB RAM, CPU support transcode).

Repo: https://github.com/AdrienPoupa/docker-compose-nas — clone, cp .env.example .env, edit, docker compose up -d, lalu ./update-config.sh.