AdrienPoupa/docker-compose-nas: Bedah Stack NAS Kompleks dengan VPN, Arr Stack, dan Traefik
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.
Hardlink Strategy: Single Shared Volume
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:
- Update
UrlBasedi config.xml *arr apps (sonarr, radarr, lidarr, prowlarr) agar match subpath Traefik - Extract API key dari config.xml → tulis ke
.env - Set qBittorrent password default (
adminadmin) via PBKDF2 hash - Konfigurasi Bazarr base_url + link ke Sonarr/Radarr
- 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)
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.
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.Single Hostname untuk Semua Service: Semua service expose via subpath (
/sonarr,/radarr,/jellyfin) di satu hostname (HOSTNAMEenv). Tidak support subdomain per service (misalsonarr.domain.com) tanpa edit label Traefik manual. Untuk Seerr, wajib subdomain terpisah (SEERR_HOSTNAME) karena Seerr tidak support subpath.No IPv6 in Traefik Config: EntryPoints hanya
:80&:443IPv4. User dual-stack harus tambah config manual.update-config.sh Tidak Idempotent untuk Bazarr: Logic sed Bazarr complex & fragile (match YAML dengan regex). Sudah dilaporkan issue upstream tapi belum fix.
Secrets di .env Plaintext: PIA credentials, Cloudflare API token, API keys *arr semua di
.envplaintext. Tidak ada integration Docker Secrets / 1Password / SOPS. Untuk production butuh secret management terpisah.Resource Limits Tidak Ada: Tidak ada
deploy.resources.limitsdi compose. Container seperti Jellyfin (transcode), Immich (ML), Paperless (OCR) bisa makan RAM/CPU tak terbatas — berbahaya di hardware kecil.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 User | Cocok? | Alasan |
|---|---|---|
| Homelabber punya VPS/NAS + domain + Cloudflare + PIA subscription | Ya | Stack lengkap, SSL auto, VPN integrated, dashboard ready |
| Pemula ingin belajar Docker Compose | Mungkin | Terlalu complex untuk “first stack”. Lebih baik mulai dari 3-4 service manual |
| User tanpa domain public / CGNAT | Ya | DNS-01 challenge tidak butuh port 80/443 open |
| User mau multi-VPN provider | Tidak | Hardcoded PIA WireGuard |
| Hardware terbatas (≤2GB RAM, no GPU) | Tidak | Jellyfin transcode, Immich ML, Paperless OCR butuh resource |
| Butuh IPv6 native | Manual | Traefik 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.