SSD Nodes Learn RAM 8GB — $66/tahun
Panduan Matt ConnorOleh Matt Connor · Diperbarui 2026-08-01

Arr Stack dalam Satu File Docker Compose

Jalankan Prowlarr, Sonarr, Radarr, dan qBittorrent di VPS dengan satu file Docker Compose, PUID, PGID, serta tata letak volume bersama agar hardlink tetap berfungsi.

Yang Anda bangun

Docker Compose arr stack terdiri dari empat container yang mengelola pustaka media: Prowlarr untuk pengaturan indexer, Sonarr untuk serial, Radarr untuk film, dan qBittorrent sebagai klien unduhan. Container-container tersebut berkomunikasi melalui jaringan Compose menggunakan nama layanan dan berbagi satu struktur folder di host. Instalasinya singkat. Tata letak volume menentukan apakah stack ini dapat berfungsi selama bertahun-tahun atau terus menimbulkan masalah setiap minggu. Karena itu, sebagian besar panduan ini membahas tata letak tersebut.

Stack ini tidak mencari konten untuk Anda. Prowlarr menyimpan indexer yang Anda tambahkan, dan keputusan tentang indexer yang digunakan beserta tanggung jawab hukumnya berada pada Anda. Panduan ini membahas konfigurasi pendukung: pengguna, path, izin, jaringan container, dan pemeriksaan untuk memastikan semuanya berfungsi.

Jika Anda belum pernah menulis file Compose, baca dasar-dasar Docker Compose untuk VPS terlebih dahulu. Panduan ini mengasumsikan docker compose version sudah menampilkan sesuatu di server Anda.

Setelah Sonarr selesai mengunduh, Sonarr mengimpor file ke pustaka Anda. Jika folder unduhan dan folder pustaka berada pada filesystem yang sama, proses impor menggunakan hardlink: nama kedua yang menunjuk ke data yang sama pada disk. Proses ini tidak memerlukan ruang tambahan atau waktu tambahan. Torrent tetap melakukan seeding dari nama lama, sementara server media membaca nama baru.

Jika kedua folder berada pada filesystem yang berbeda, kernel tidak dapat membuat link tersebut. Sonarr beralih ke penyalinan. Season berukuran 40 GB kini menggunakan 80 GB ruang disk dan memerlukan beberapa menit operasi input dan output. Log impor mencatat bahwa hardlink gagal dan file disalin sebagai gantinya. Pada VPS dengan batas ruang disk tetap, inilah yang dapat menyebabkan ruang habis dalam waktu seminggu.

Inilah masalahnya. Di dalam container, bind mount merupakan batas filesystem. Mount /mnt/data/torrents sebagai /downloads dan /mnt/data/media sebagai /tv. Meskipun keduanya berada pada satu disk host, Sonarr melihat dua mount terpisah dan menolak membuat link di antara keduanya. Dokumentasi image LinuxServer.io resmi menyatakan hal ini secara langsung: penggunaan path /downloads dan /tv secara terpisah menghilangkan kemampuan untuk menggunakan hardlink.

Solusinya adalah satu mount. Setiap container yang mengakses media mendapatkan volume tunggal yang sama, yaitu /mnt/data:/data, dan setiap path yang digunakan berada di dalamnya. Satu titik mount, satu filesystem, dan hardlink berfungsi.

Buat pengguna, grup, dan folder

Container menulis file menggunakan ID pengguna numerik yang ditetapkan oleh PUID dan PGID. Gunakan akun Anda sendiri agar Anda dapat membaca dan mengedit file tersebut melalui SSH tanpa sudo.

id -u
id -g

Keduanya biasanya menampilkan 1000 pada Ubuntu VPS yang baru dibuat. Sekarang buat struktur direktorinya. Letakkan struktur tersebut di disk yang menyimpan media Anda, dan pastikan seluruh struktur berada di satu disk itu.

sudo mkdir -p /mnt/data/torrents/movies /mnt/data/torrents/tv
sudo mkdir -p /mnt/data/media/Movies /mnt/data/media/Shows
sudo chown -R 1000:1000 /mnt/data
sudo chmod -R 775 /mnt/data

Pastikan struktur tersebut benar-benar berada pada satu filesystem sebelum melanjutkan:

df --output=source,target /mnt/data/torrents /mnt/data/media

Kedua baris harus menampilkan perangkat sumber yang sama. Dua perangkat yang berbeda berarti hardlink tidak akan pernah berfungsi, apa pun yang Anda tetapkan dalam konfigurasi container.

Folder pustaka sengaja diberi nama Movies dan Shows. Jika Anda sudah menjalankan Jellyfin sebagai server media, mount /mnt/data/media ke Jellyfin sebagai /media, dan pustakanya akan berada di /media/Movies dan /media/Shows, tepat seperti yang ditetapkan panduan tersebut.

File lingkungan

Simpan nilai yang berbeda untuk setiap server di .env, di sebelah file Compose.

mkdir -p ~/arr && cd ~/arr

Tulis ~/arr/.env:

PUID=1000
PGID=1000
TZ=Etc/UTC
DATA_ROOT=/mnt/data

Tetapkan TZ ke zona Anda sendiri, seperti Europe/Berlin. Aplikasi arr menjadwalkan tugas dan memberi cap waktu pada baris log berdasarkan zona tersebut. Nilai yang salah akan membuat semua log sulit dipahami nantinya.

File Compose

Tulis ~/arr/docker-compose.yml:

services:
  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    container_name: prowlarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - ./config/prowlarr:/config
    ports:
      - 127.0.0.1:9696:9696
    restart: unless-stopped

  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - ./config/sonarr:/config
      - ${DATA_ROOT}:/data
    ports:
      - 127.0.0.1:8989:8989
    restart: unless-stopped

  radarr:
    image: lscr.io/linuxserver/radarr:latest
    container_name: radarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - ./config/radarr:/config
      - ${DATA_ROOT}:/data
    ports:
      - 127.0.0.1:7878:7878
    restart: unless-stopped

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - WEBUI_PORT=8080
      - TORRENTING_PORT=6881
    volumes:
      - ./config/qbittorrent:/config
      - ${DATA_ROOT}:/data
    ports:
      - 127.0.0.1:8080:8080
      - 6881:6881
      - 6881:6881/udp
    stop_grace_period: "10s"
    restart: unless-stopped

Ada empat hal dalam file tersebut yang menjalankan fungsi penting.

${DATA_ROOT}:/data sama pada ketiga container yang mengakses media. Prowlarr tidak memerlukannya karena Prowlarr tidak pernah membuka file media.

Setiap port web diikat ke 127.0.0.1, sehingga Docker hanya memublikasikannya pada alamat loopback. 8989:8989 biasa akan memublikasikannya pada semua interface, dan aturan firewall Docker sendiri akan meneruskan traffic tersebut langsung melewati aturan deny ufw. Perilaku ini sering mengejutkan pengguna. Penjelasannya tersedia dalam alasan Docker memublikasikan port langsung melewati ufw.

Port 6881 sengaja dipublikasikan pada semua interface. Port tersebut adalah port listening torrent dan harus dapat dijangkau untuk koneksi peer masuk. Izinkan port tersebut dengan sudo ufw allow 6881. Jika perintah itu masih baru bagi Anda, baca dasar-dasar firewall ufw untuk VPS.

Direktori konfigurasi dipisahkan untuk setiap aplikasi. Hanya volume media yang digunakan bersama. Buat direktori tersebut sebelum menjalankan layanan untuk pertama kali agar direktori dimiliki oleh user Anda, bukan oleh root:

mkdir -p ~/arr/config/prowlarr ~/arr/config/sonarr ~/arr/config/radarr ~/arr/config/qbittorrent
docker compose up -d
docker compose ps

Keempat layanan harus membaca running. Per Juli 2026, image ini dipublikasikan di lscr.io, dan tag latest mengikuti rilis stabil saat ini. Gunakan tag versi tertentu jika Anda ingin menjadikan upgrade sebagai keputusan, bukan kejutan.

Akses antarmuka web dengan aman

Karena port tersebut berada pada loopback, belum ada layanan yang terekspos. Teruskan port tersebut melalui SSH dari komputer Anda sendiri:

ssh -L 9696:127.0.0.1:9696 -L 8989:127.0.0.1:8989 \
    -L 7878:127.0.0.1:7878 -L 8080:127.0.0.1:8080 you@your-server

Sekarang http://127.0.0.1:8989 di browser Anda mengakses Sonarr pada server. Untuk akses permanen, tempatkan stack di belakang Traefik dengan sertifikat TLS untuk beberapa aplikasi, atau akses server melalui VPN WireGuard yang Anda kelola sendiri. Jangan menempatkan aplikasi-aplikasi ini di internet publik hanya dengan halaman login masing-masing sebagai perlindungan.

qBittorrent membuat kata sandi administrator acak saat pertama kali dijalankan dan menampilkannya di log container. Baca kata sandi tersebut, lalu ubah melalui antarmuka web:

docker compose logs qbittorrent | grep -i password

Jika Anda melewatkan perubahan ini, kata sandi acak baru akan dibuat setiap kali container dimulai ulang, sehingga Anda harus kembali memeriksa log setiap kali.

Tetapkan path di dalam setiap aplikasi

Di qBittorrent, buka Options, lalu Downloads, dan tetapkan path penyimpanan default ke /data/torrents. Simpan folder unduhan yang belum selesai di dalam tree yang sama, misalnya /data/torrents/incomplete. Unduhan yang selesai di lokasi mana pun di luar /data tidak dapat dibuatkan hard link ke dalam pustaka.

Di Sonarr, buka Settings, lalu Media Management, dan tambahkan root folder /data/media/Shows. Di Radarr, root folder-nya adalah /data/media/Movies. Path ini berada di dalam container. Path host /mnt/data/media/Shows ditolak karena direktori tersebut tidak ada dari sudut pandang container.

Di Sonarr dan Radarr, buka Settings, lalu Download Clients, dan tambahkan qBittorrent. Host-nya adalah qbittorrent dan port-nya adalah 8080. Nama service dapat digunakan sebagai hostname karena Compose menempatkan keempat container pada satu network dengan service DNS (domain name system) internal. Jangan gunakan localhost di sini: di dalam container Sonarr, localhost adalah Sonarr.

Biarkan Remote Path Mappings kosong. Fitur ini digunakan untuk menerjemahkan path yang dilaporkan oleh download client menjadi path yang dapat dilihat oleh aplikasi arr. Dengan satu mount /data yang digunakan bersama, kedua container sudah menggunakan path yang sama. Ini adalah alasan kedua mengapa tata letak ini sepadan dengan upaya tersebut.

Menghubungkan Prowlarr ke Sonarr dan Radarr

Prowlarr meneruskan definisi indexer ke aplikasi lain. Dengan demikian, Anda mengonfigurasi indexer satu kali, bukan dua kali. Prowlarr memerlukan kunci API (application programming interface) dari setiap aplikasi.

Di Sonarr, buka Settings, lalu General, dan salin kunci API. Di Prowlarr, buka Settings, lalu Apps, tambahkan aplikasi Sonarr, dan isi tiga bidang. Prowlarr Server adalah http://prowlarr:9696. Sonarr Server adalah http://sonarr:8989. API Key adalah nilai yang Anda salin. Tekan Test. Hasil berwarna hijau berarti Prowlarr berhasil terhubung ke Sonarr melalui jaringan Compose. Ulangi langkah ini untuk Radarr di http://radarr:7878.

Hasil berwarna merah yang menyatakan bahwa koneksi ditolak hampir selalu berarti nama layanan salah atau prefiks http:// tidak ada. Pastikan nama tersebut dapat di-resolve dari dalam container:

docker compose exec prowlarr curl -sS -o /dev/null -w '%{http_code}\n' http://sonarr:8989

Kode status HTTP membuktikan bahwa jalur jaringan berfungsi. Kesalahan resolusi nama membuktikan bahwa nama layanan salah.

Jangan mempercayai konfigurasi sebelum Anda melihat jumlah tautan. Setelah satu item diimpor, bandingkan file yang diunduh dengan file di pustaka:

stat -c '%i %h %n' /mnt/data/torrents/tv/*/*.mkv
stat -c '%i %h %n' /mnt/data/media/Shows/*/*/*.mkv

Angka pertama adalah inode dan angka kedua adalah jumlah tautan. File yang dibuat sebagai hardlink memiliki inode yang sama di kedua lokasi dan jumlah tautan sebesar 2. Dua inode berbeda, masing-masing dengan jumlah tautan 1, berarti Sonarr menyalin file. Log impor akan menyatakan bahwa pembuatan hardlink gagal.

Pantau penggunaan disk juga. df -h /mnt/data seharusnya hampir tidak berubah saat impor berlangsung, karena hardlink hanya menambahkan nama dan tidak menambahkan data.

Penyebab sebenarnya

Kesalahan izin saat impor berarti ID pengguna container tidak dapat menulis ke folder pustaka. Pesannya adalah Access to the path ... is denied. Periksa dengan ls -ln /mnt/data/media bahwa ID pemilik cocok dengan PUID Anda. Ingat bahwa direktori memerlukan bit eksekusi agar container dapat memasukinya.

File yang tampak dimiliki oleh root berarti container dimulai sebelum direktori host tersedia, sehingga Docker membuatnya sebagai root. Hentikan stack, chown direktori tersebut, lalu mulai kembali.

Jika menghapus torrent dari qBittorrent menyebabkan file pustaka ikut hilang, berarti impor dilakukan dengan menyalin file lalu salinannya dihapus, atau Anda menghapus datanya, bukan entri torrent. Pada hardlink yang sebenarnya, menghapus salah satu nama tidak menghapus nama lainnya karena data hanya dibebaskan ketika jumlah link mencapai nol.

Jika disk terisi lebih cepat daripada jumlah media yang Anda tambahkan, masalah penyalinan sedang terjadi dalam bentuk yang paling boros. Jalankan pemeriksaan stat di atas sebelum membeli penyimpanan tambahan.

Kebutuhan stack ini dari VPS

Tiga aplikasi arr tidak membutuhkan banyak sumber daya. Aplikasi tersebut melakukan polling pada indexer, menulis ke database SQLite kecil, dan mengganti nama file. Server dengan RAM 2 GB dapat menjalankan keempat container dengan nyaman. Beban kerja utama berasal dari komponen lain. Klien download dapat memenuhi kapasitas input dan output disk saat menangani torrent berukuran besar. Server media yang melakukan transcoding video pada server yang sama juga akan membebani CPU. Simpan media pada volume dengan throughput nyata. Tetapkan batas bandwidth pada klien download jika server juga menjalankan layanan lain yang penting.

FAQ

Karena dari sudut pandang container, sumber dan tujuan berada pada filesystem yang berbeda. Dua bind mount terpisah, seperti /downloads dan /tv, merupakan dua filesystem meskipun keduanya berasal dari satu disk host. Mount satu direktori induk sebagai /data di setiap container, lalu letakkan direktori unduhan dan pustaka di dalamnya agar link dapat dibuat. Konfirmasikan hasilnya dengan stat -c '%i %h %n' pada kedua file: inode yang sama dan jumlah link sebesar 2.

PUID dan PGID apa yang harus saya gunakan?

Gunakan id numerik akun host yang memiliki pohon media. Nilai tersebut dapat diperoleh dengan id -u dan id -g. Pada Ubuntu VPS baru, biasanya keduanya adalah 1000. Setiap container dalam stack harus menggunakan pasangan yang sama. Jika tidak, satu aplikasi dapat menulis file yang tidak dapat diubah oleh aplikasi lain. Setelah mengubah nilainya, buat ulang container dengan docker compose up -d --force-recreate dan perbaiki file yang ada dengan chown -R.

Apakah antarmuka web ini perlu diekspos ke internet?

Tidak, dan sebaiknya jangan. Bind setiap port yang dipublikasikan ke 127.0.0.1 dalam file Compose, lalu akses antarmuka tersebut melalui tunnel SSH, VPN, atau reverse proxy yang menghentikan TLS (keamanan lapisan transport) dan menambahkan autentikasinya sendiri. Mempublikasikannya secara langsung lebih berisiko daripada yang terlihat, karena Docker memasukkan aturan firewall-nya sendiri dan aturan deny ufw tidak akan menghentikan traffic tersebut.

Di mana saya dapat menemukan kata sandi qBittorrent?

Image LinuxServer.io mencetak kata sandi sementara untuk pengguna admin dalam log startup-nya. Jalankan docker compose logs qbittorrent | grep -i password untuk membacanya, lalu tetapkan kata sandi permanen di bagian Options dan Web UI. Kata sandi sementara baru dibuat setiap kali restart sampai Anda menetapkan kata sandi sendiri.

Apakah Jellyfin dapat menggunakan folder yang sama?

Ya, dan itulah tujuan tata letak ini. Mount /mnt/data/media ke server media sebagai /media. Pustakanya berada di /media/Movies dan /media/Shows, sedangkan Sonarr dan Radarr menulis ke direktori yang sama melalui /data/media. Berikan server media PUID dan PGID yang sama agar dapat membaca file yang ditulis oleh stack arr.

#sonarr#radarr#prowlarr#docker-compose#self-hosting