Jellyfin di VPS: Streaming Media Pribadi dengan Docker
Pelajari cara menjalankan Jellyfin di VPS dengan Docker, mengatur block storage dan izin media, serta menghindari transcoding CPU tanpa GPU saat akses jarak jauh.
Yang Anda bangun
Server media Jellyfin pada VPS: satu container, tiga volume, dan disk block storage yang menyimpan film serta serial Anda. Server ini dapat diakses dari browser atau aplikasi Jellyfin mana pun. Instalasinya menggunakan file compose yang terdiri atas 15 baris. Semua masalah yang muncul setelahnya berasal dari dua hal: izin file yang tidak dapat dibaca oleh container, dan permintaan transcoding video kepada VPS tanpa GPU yang tidak sesuai untuk pekerjaan tersebut. Sebagian besar panduan ini membahas dua hal itu karena keduanya paling sering menimbulkan tiket dukungan.
Jellyfin gratis dan sepenuhnya open source. Jellyfin tidak memerlukan akun, tidak memiliki fitur berbayar, dan tidak mengumpulkan telemetry. Karena itu, Jellyfin hampir selalu masuk dalam daftar hal yang layak di-self-host pada 2026. Jellyfin memutar media yang Anda miliki. Jellyfin tidak menyediakan konten, dan panduan ini tidak membahas cara mendapatkannya.
Realitas transcoding sebelum menyewa apa pun
Baca bagian ini terlebih dahulu karena informasi ini memengaruhi pilihan yang Anda beli. Media server melakukan salah satu dari dua hal saat Anda menekan tombol putar. Direct play mengalirkan file apa adanya: VPS membaca byte dari disk lalu mengirimkannya melalui jaringan, dengan penggunaan CPU yang hampir nol. Transcoding melakukan encoding ulang video secara langsung, misalnya ke resolusi baru, codec baru, atau dengan subtitle yang dibakar ke dalam video. Proses ini sepenuhnya menggunakan CPU.
VPS biasanya tidak memiliki GPU. Karena itu, setiap proses transcoding berjalan pada CPU dengan libx264/libx265, dan encoding berbasis software membutuhkan banyak sumber daya. Satu proses transcoding H.264 1080p dapat memenuhi beberapa vCPU bersama. Transcoding 4K atau HEVC biasanya sama sekali tidak mampu mengikuti waktu nyata, sehingga pemutaran berhenti dan terus melakukan buffering. Hardware transcoding, yang membuat proses ini murah pada komputer rumahan dengan iGPU Intel atau kartu Nvidia, tidak tersedia bagi Anda kecuali provider menyediakan instance GPU.
Karena itu, strategi utama pada VPS adalah: hindari transcoding. Simpan koleksi media dalam codec yang dapat diputar langsung oleh client, yaitu video H.264, audio AAC atau AC3, dalam container MP4 atau MKV. Pilih aplikasi client yang mendukung direct play: aplikasi Jellyfin native untuk Android TV, iOS, dan Roku, serta Infuse, Kodi, dan Jellyfin Media Player untuk desktop. Dengan cara ini, VPS tidak perlu menjalankan ffmpeg, dan VPS sederhana dengan 2 vCPU dapat mengalirkan media kepada beberapa orang sekaligus. Jika Anda berencana menggunakan transcoding, Anda memerlukan VPS yang jauh lebih besar dan lebih mahal. Bahkan dengan VPS tersebut, 4K tetap merupakan pilihan yang berisiko.
Hitung juga kebutuhan bandwidth karena ini merupakan kejutan lainnya. Direct play mengirim file pada bitrate aslinya. File 1080p terkompresi menggunakan 8-12 Mbps; remux Blu-ray 1080p menggunakan 20-30 Mbps; 4K HDR menggunakan 40-80 Mbps. Tiga orang yang melakukan direct play terhadap file 10 Mbps menghasilkan upload berkelanjutan sebesar 30 Mbps dari VPS Anda. Periksa dua angka pada paket Anda: kecepatan port (apakah port tersebut dapat mengirim 30 Mbps secara upstream?) dan batas transfer bulanan. Satu film berdurasi dua jam dengan bitrate 10 Mbps menghasilkan sekitar 9 GB traffic keluar. Jadi, paket dengan kuota 1 TB/bulan hanya mendukung sedikit lebih dari seratus film seperti itu per bulan, atau tiga hingga empat film per hari. Rumah tangga yang menonton 4K, dengan bitrate empat hingga delapan kali lebih tinggi, akan menghabiskan kuota tersebut jauh lebih cepat. Perhitungkan semua hal lain yang mengirim traffic keluar dari server yang sama ke dalam anggaran yang sama, termasuk relay RustDesk yang di-host sendiri, yang membawa seluruh sesi remote desktop setiap kali dua peer tidak dapat terhubung secara langsung.
Prasyarat
- KVM VPS Ubuntu 24.04 baru dengan akses root atau sudo, serta Docker dan plugin Compose yang sudah terpasang.
- Volume block storage untuk media, dengan kapasitas yang sesuai dengan koleksi Anda (lihat panduan penentuan kapasitas di bawah). Disk root kecil yang disertakan bersama VPS bukan tempat untuk menyimpan film.
- Nama domain jika Anda menginginkan akses HTTPS publik, atau VPN WireGuard pada VPS yang sama jika Anda ingin seluruh layanan tetap privat.
- Media yang secara hukum boleh Anda streaming, rip pribadi, rekaman pribadi, atau file milik Anda sendiri.
Pasang penyimpanan blok terlebih dahulu
Pasang volume melalui panel provider Anda, lalu temukan dan mount volume tersebut. Dapatkan nama device dari lsblk. Namanya akan terlihat seperti /dev/sdb atau /dev/vdb, dan tidak pernah merupakan root disk.
lsblk
sudo mkfs.ext4 /dev/sdb # ONLY on a new, empty volume — this ERASES it
sudo mkdir -p /mnt/media
sudo blkid /dev/sdb # copy the UUID shown for this deviceMount volume berdasarkan UUID, bukan berdasarkan /dev/sdb, karena urutan huruf device dapat berubah setelah reboot dan Anda dapat memformat atau me-mount disk yang salah. Tambahkan satu baris ke /etc/fstab:
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/media ext4 defaults,nofail 0 2sudo mount -a
df -h /mnt/medianofail penting. Tanpa opsi ini, jika block volume terlepas, server tidak dapat boot dan masuk ke emergency shell. Kesalahan terbesar dalam langkah ini adalah menjalankan mkfs.ext4 pada volume yang sudah berisi data karena perintah tersebut akan menghapusnya. Format hanya volume baru. Jika disk sudah berisi library Anda, langsung lanjutkan ke baris fstab.
Susun media sesuai ekspektasi Jellyfin
Jellyfin mencocokkan metadata berdasarkan nama folder dan file. Jika susunannya salah, film akan muncul sebagai file tanpa judul dan poster, atau sebuah episode akan dicocokkan dengan serial yang salah. Ada tepat tiga aturan: setiap film harus berada dalam folder Name (Year) tersendiri dengan nama file yang sama; folder musim harus diberi nama Season 01, bukan S01; file episode harus menggunakan S01E01; dan episode khusus harus ditempatkan dalam Season 00.
/mnt/media
├── Movies
│ ├── Blade Runner (1982)
│ │ └── Blade Runner (1982).mkv
│ └── Arrival (2016)
│ └── Arrival (2016).mkv
└── Shows
└── Severance (2022)
├── Season 01
│ ├── Severance - S01E01.mkv
│ └── Severance - S01E02.mkv
└── Season 00
└── Severance - The Lexington Letter.mkv(Year) pada film bukan sekadar hiasan. Elemen ini membedakan film versi baru dari remake agar pencocokan mengambil judul yang benar. Pertahankan Movies dan Shows sebagai folder tingkat teratas yang terpisah karena masing-masing menjadi library Jellyfin dengan jenis konten tertentu. Mencampurnya dapat membingungkan penyedia metadata. Jellyfin juga dapat mengindeks folder ketiga yang berisi foto, tetapi pengalaman pengguna yang diberikan terbatas dibandingkan server foto khusus. Jadi, jika album Anda penting, sediakan server tersendiri yang menjalankan PhotoPrism atau Immich, dan gunakan server ini hanya untuk film dan TV.
Permissions: alasan utama library tidak menampilkan apa pun
Berikut miskonsepsi yang dapat menghabiskan waktu sepanjang malam. Image resmi jellyfin/jellyfin tidak mengenali environment variable PUID/PGID. Variable tersebut digunakan oleh image LinuxServer.io (lscr.io/linuxserver/jellyfin). Pada image resmi, pengguna dikendalikan melalui key user: dalam compose. Jika key tersebut dihilangkan, container berjalan sebagai root. Apa pun image yang digunakan, aturannya sama: uid/gid yang digunakan container harus dapat membaca dan menelusuri setiap direktori media.
Kita akan menjalankan container sebagai uid/gid 1000, yaitu pengguna non-root pertama pada instalasi Ubuntu standar. Pastikan nilai yang digunakan dan atur ownership:
id # confirm your user is uid=1000 gid=1000
sudo chown -R 1000:1000 /mnt/media
sudo find /mnt/media -type d -exec chmod 755 {} \;
sudo find /mnt/media -type f -exec chmod 644 {} \;
mkdir -p ~/jellyfin/config ~/jellyfin/cache
sudo chown -R 1000:1000 ~/jellyfinDirektori memerlukan bit execute (x dalam 755), bukan hanya bit read. Tanpa bit tersebut, container tidak dapat masuk ke folder meskipun dapat melihat namanya. Penyebab yang sering mengosongkan seluruh library adalah direktori induk. Jika uid container tidak dapat menelusuri mount itu sendiri, container tidak pernah mencapai /media/Movies atau /media/Shows. Akibatnya, semua library langsung kosong dan Access to the path ... is denied tercatat dalam log. Setiap folder media yang tidak dapat dibaca akan dicatat dalam log dan dilewati. Karena itu, sekumpulan file yang disalin sebagai root dapat menghilang secara diam-diam dari library. Inilah alasan kita menjalankan chown secara rekursif dan menetapkan bit execute pada setiap direktori, bukan hanya memperbaiki satu folder.
File docker-compose
services:
jellyfin:
image: jellyfin/jellyfin:10
container_name: jellyfin
user: "1000:1000"
restart: unless-stopped
ports:
- "127.0.0.1:8096:8096"
volumes:
- ./config:/config
- ./cache:/cache
- /mnt/media:/media:ro
environment:
- JELLYFIN_PublishedServerUrl=https://jellyfin.example.comBaris per baris: user: "1000:1000" adalah bagian yang benar-benar menetapkan izin file sesuai kepemilikan di atas. /config menampung seluruh server, akun, library, metadata, serta status pemantauan, sehingga direktori ini harus dapat ditulisi dan menjadi bagian yang Anda cadangkan. /cache adalah ruang kerja sementara yang dapat dibuang. Mount media adalah :ro (read-only) secara sengaja: secara default, Jellyfin menyimpan artwork dan metadata di /config, sehingga Jellyfin tidak perlu menulis ke library Anda. Mode read-only juga melindungi file dari penghapusan yang tidak disengaja atau plugin yang bermasalah. Port sengaja di-bind ke 127.0.0.1. Login web Jellyfin menggunakan HTTP biasa, sehingga kita tidak pernah mengekspos 8096 ke Internet publik. JELLYFIN_PublishedServerUrl adalah alamat yang diiklankan server untuk autodiscovery lokal, yaitu broadcast UDP di LAN. Karena itu, klien di Internet tidak pernah melihatnya dan cukup menggunakan URL yang Anda masukkan ke aplikasi. Tetapkan alamat yang harus diberikan kepada klien, lalu bersiaplah memasukkan URL tersebut secara manual pada perangkat remote.
Jalankan dari direktori compose:
docker compose up -d
docker logs -f jellyfinPertama kali dijalankan: wizard penyiapan dan pustaka Anda
Karena port terikat ke localhost, akses wizard melalui tunnel SSH dari laptop Anda, bukan dengan membuka celah pada firewall:
ssh -L 8096:127.0.0.1:8096 you@your-vps-ipSekarang buka http://localhost:8096. Wizard memandu Anda memilih bahasa, lalu membuat pengguna admin dengan kata sandi yang kuat. Akun ini digunakan untuk server Anda, jadi jangan gunakan kembali kata sandi sementara. Tambahkan pustaka pertama Anda: pilih jenis konten Movies, arahkan ke /media/Movies (path di dalam container, bukan path pada host), lalu ulangi dengan Shows di /media/Shows. Selesaikan prosesnya, lalu Jellyfin akan melakukan pemindaian. Jika konfigurasi benar, poster dan judul akan muncul dalam satu atau dua menit untuk pustaka berukuran kecil. Anda dapat menambahkan atau mengedit pustaka nanti melalui Dashboard → Libraries, lalu memaksa pemindaian ulang dengan Scan All Libraries.
Jika Anda menggunakan transcoding, buka Dashboard → Playback → Transcoding dan atur path sementara transcoding ke /cache/transcodes agar aktivitas tersebut menggunakan volume cache, bukan memperbesar /config. Biarkan akselerasi perangkat keras pada None karena tidak ada GPU yang dapat digunakan untuk akselerasi.
Akses jarak jauh: reverse proxy TLS, atau tetap gunakan VPN
Ada dua cara aman untuk mengakses Jellyfin dari luar, serta satu cara tidak aman yang harus dihindari. Cara tidak aman tersebut adalah memublikasikan port 8096 langsung ke Internet: kredensial login dikirim dalam teks biasa dan port itu akan menjadi sasaran brute-force dalam hitungan jam.
Opsi A, reverse proxy TLS. Tempatkan Jellyfin pada subdomain di belakang Traefik dengan TLS otomatis untuk aplikasi Docker Anda, atau di belakang nginx dengan sertifikat Let's Encrypt yang diterbitkan oleh Certbot. Jellyfin menggunakan WebSockets untuk pembaruan real-time, sehingga proxy harus meneruskan header upgrade. Traefik melakukannya secara otomatis; nginx memerlukan konfigurasi header tersebut secara eksplisit dan memerlukan HTTP/1.1 ke upstream. Jika tidak, proses upgrade tidak akan berlangsung:
location / {
proxy_pass http://127.0.0.1:8096;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}Atur JELLYFIN_PublishedServerUrl ke alamat https:// agar autodiscovery lokal mengiklankan URL yang benar dan aplikasi jarak jauh menggunakan alamat yang Anda berikan. Tambahkan fail2ban untuk memperlambat percobaan brute-force terhadap login. Setelah server dapat diakses publik, arahkan Uptime Kuma ke URL tersebut agar Anda mengetahui gangguan layanan sebelum penonton Anda menyadarinya.
Opsi B, tetap privat melalui VPN. Jangan publikasikan port 8096 sama sekali. Akses Jellyfin hanya melalui tunnel WireGuard yang berakhir pada mesin yang sama. Untuk penggunaan rumah tangga, ini adalah pilihan aman yang paling sederhana: tanpa sertifikat, tanpa eksposur publik, dan tanpa permukaan serangan brute-force. Bind container ke alamat tunnel atau localhost, lalu lakukan koneksi melalui VPN. Lihat penyiapan VPN WireGuard untuk VPS privat untuk konfigurasi tunnel itu sendiri.
Ukuran penyimpanan dan pencadangan
Tentukan anggaran berdasarkan kualitas, bukan jumlah file. Film 1080p terkompresi berukuran 4-15 GB per film; remux 1080p berukuran 20-40 GB; satu musim serial TV 1080p berukuran 15-40 GB; konten 4K apa pun berukuran 40-100 GB per film. Pustaka yang berisi beberapa ratus film dan sejumlah serial memerlukan volume 2-4 TB. Menyediakan kapasitas volume blok berlebih sejak awal lebih murah daripada melakukan migrasi nanti.
/config adalah seluruh status server. Karena itu, bagian ini yang harus Anda cadangkan. Buat snapshot, atau hentikan server lalu buat arsip tar, kemudian simpan salinannya di luar server:
docker compose down
sudo tar czf jellyfin-config-$(date +%F).tgz -C ~/jellyfin config
docker compose up -d/cache dan folder transcode dapat dihapus dan dibuat ulang. Media di /mnt/media dapat Anda cadangkan secara terpisah, atau Anda dapat menganggapnya dapat di-rip ulang. Sebagian besar orang memilih opsi kedua karena ukurannya. Upgrade dilakukan menggunakan docker compose pull && docker compose up -d. Tag :10 di atas tetap berada dalam major version 10.x. Jadi, perpindahan ke major version berikutnya harus dilakukan dengan mengedit tag secara sengaja. Baca sekilas catatan rilis Jellyfin sebelum melakukannya karena migrasi skema pustaka terjadi pada major version. Tag yang dipatok dan satu direktori status yang dicadangkan adalah seluruh resep untuk container yang selalu aktif. Pola yang sama digunakan untuk mempertahankan memori dan jadwal agent yang di-host sendiri setelah reboot.
Mode kegagalan, beserta string yang akan Anda lihat
Library kosong setelah pemindaian. Log di Dashboard → Logs (atau ~/jellyfin/config/log/log_*.log) menampilkan:
System.UnauthorizedAccessException: Access to the path '/media/Movies' is denied.uid container tidak dapat membaca path tersebut. Penyebabnya: media dimiliki oleh root atau uid selain nilai user: Anda, direktori tidak memiliki bit execute, atau mount induknya sendiri tidak dapat dilalui oleh uid tersebut. Perbaikan: chown -R 1000:1000 /mnt/media, direktori 755, file 644, lalu lakukan pemindaian ulang.
Pemutaran membuat CPU bekerja penuh dan mengalami buffering. docker stats jellyfin menampilkan penggunaan CPU mendekati 100% dikalikan jumlah core Anda, dan Dashboard → Playback mencantumkan sesi sebagai Transcode dengan kecepatan di bawah 1.0x. Client tidak melakukan direct play. VPS melakukan transcoding menggunakan CPU dengan kecepatan lebih rendah daripada waktu nyata sehingga pemutaran tertinggal. Penyebabnya dapat berupa codec atau container yang tidak didukung, burn-in subtitle, atau tone-mapping HDR. Perbaikan: gunakan client direct-play, pertahankan sumber dalam H.264/AAC, gunakan subtitle text (SRT), bukan subtitle image (PGS/VOBSUB) yang memaksa burn-in, dan jangan gunakan HDR 4K pada mesin yang hanya mengandalkan CPU.
"No compatible streams are available." Pesan lengkapnya biasanya adalah "This client isn't compatible with the media and the server isn't sending a compatible media format." Client menolak sumber tersebut dan transcoding fallback juga gagal dimulai. Penyebabnya dapat berupa perintah ffmpeg yang rusak, file yang tidak dapat dibaca, atau profil pengguna yang memblokir konversi video. Perbaikan: baca baris ffmpeg di Dashboard → Logs, pastikan file tersebut memang dapat diputar, periksa izin pemutaran pengguna jika Anda bergantung pada transcoding, dan coba client kedua untuk memastikan masalahnya bukan quirks codec browser.
Film tidak memiliki poster atau menggunakan poster yang salah. Metadata tidak cocok. Penyebabnya dapat berupa film yang tidak berada dalam folder Name (Year) miliknya sendiri, folder season yang diberi nama S01, bukan Season 01, episode yang tidak menggunakan format S01E01, atau tahun yang tidak dicantumkan. Perbaikan: ubah nama sesuai struktur di atas, lalu pilih Refresh metadata → Replace all, atau gunakan Identify pada satu item untuk menetapkan entri TMDB/TVDB yang benar.
FAQ
Dapatkah VPS melakukan transcoding video tanpa GPU?
Ya, tetapi hanya menggunakan CPU dan biayanya tinggi. Satu proses transcoding software 1080p dapat memenuhi kapasitas beberapa vCPU, sedangkan 4K atau HEVC biasanya tidak mampu mengikuti waktu nyata sehingga pemutaran mengalami buffering. Pilihan yang lebih baik adalah menghindari transcoding: simpan koleksi dalam format H.264/AAC dan gunakan aplikasi klien yang mendukung direct play, sehingga VPS hanya mengalirkan data. Sewa instance GPU hanya jika Anda benar-benar memerlukan transcoding secara langsung.
Mengapa koleksi Jellyfin saya kosong setelah pemindaian?
Hampir selalu penyebabnya adalah izin akses. Image resmi jellyfin/jellyfin berjalan sebagai pengguna yang ditetapkan melalui user:, atau sebagai root. Jika file tidak dapat dibaca oleh uid tersebut, log pemindaian mencatat Access to the path ... is denied dan melewatinya. Perbaiki kepemilikan dengan chown -R 1000:1000 /mnt/media, berikan bit execute pada direktori menggunakan 755, lalu lakukan pemindaian ulang. Periksa juga direktori induknya, karena jika uid container tidak dapat menelusuri /mnt/media itu sendiri, container tidak pernah mencapai folder koleksi dan hasilnya tetap kosong. Penyebab umum kedua adalah tata letak folder yang tidak sesuai dengan yang diharapkan Jellyfin.
Bagaimana cara mengakses Jellyfin dari jarak jauh dengan aman?
Ada 2 pilihan yang baik. Tempatkan Jellyfin di balik reverse proxy TLS pada subdomain agar login dan streaming terenkripsi, lalu tambahkan fail2ban. Jangan pernah mengekspos port biasa 8096, karena port tersebut mengirimkan kata sandi dalam teks biasa. Atau, jaga agar Jellyfin sepenuhnya privat dan akses hanya melalui VPN. Untuk penggunaan rumah tangga, ini adalah pilihan aman yang paling sederhana. Berikan alamat publik secara langsung kepada aplikasi. Autodiscovery adalah broadcast jaringan lokal, sehingga tidak menjangkau klien yang terhubung melalui Internet.
Berapa kapasitas disk dan bandwidth yang dibutuhkan VPS Jellyfin?
Kebutuhan disk bergantung pada kualitas: siapkan 4-15 GB per film 1080p terkompresi, 20-40 GB per remux, dan 40-100 GB untuk 4K. Karena itu, sebagian besar koleksi memerlukan block volume berkapasitas 2-4 TB. Bandwidth ditentukan oleh bitrate direct play, yaitu 8-12 Mbps per streaming 1080p dan jauh lebih tinggi untuk 4K. Pastikan kecepatan port Anda mampu menangani jumlah penonton simultan, lalu pantau batas transfer bulanan. Tambahkan cadangan kapasitas CPU jika Anda berencana melakukan transcoding. Jika Anda berencana menggunakan direct play, prioritaskan bandwidth daripada jumlah core.
Apakah menjalankan Jellyfin pada VPS legal?
Jellyfin sendiri adalah software gratis dan open source, sehingga menjalankannya sepenuhnya legal. Hal yang penting adalah kontennya: lakukan streaming hanya terhadap media yang Anda miliki atau yang lisensinya mengizinkan Anda menyimpannya, seperti rip dari disk milik sendiri, rekaman, atau file yang memang boleh Anda gunakan. Jellyfin tidak menyediakan media dan tidak menyediakan cara untuk mendapatkannya. Jellyfin adalah pemutar untuk koleksi yang sudah Anda miliki.