Paano mag-setup ng Jellyfin sa VPS
Matutunan ang pag-setup ng Jellyfin sa Docker gamit ang VPS. Iwasan ang error sa file permissions at alamin ang limitasyon ng CPU transcoding sa VPS.
Ang iyong bubuuin
Isang Jellyfin media server sa isang VPS: isang container, tatlong volume, at isang block-storage disk para sa iyong mga pelikula at palabas, na maaari ma-access mula sa anumang browser o Jellyfin app. Ang installation ay binubuo ng isang fifteen-line compose file. Ang anumang magiging error pagkatapos ay nagmumula sa dalawang bagay — file permissions na hindi mabasa ng container, at ang paggamit ng GPU-less VPS para mag-transcode ng video na hindi nito kayang i-transcode. Nakatuon ang guide na ito sa dalawang aspetong ito dahil dito madalas nagkakaroon ng problema.
Ang Jellyfin ay libre at open source, walang account, walang paywalled features, at walang telemetry — kaya naman kasama ito sa halos lahat ng listahan ng mga bagay na worth i-self-host sa 2026. Nagpe-play ito ng media na pagmamay-ari mo. Wala itong kasamang content, at ang guide na ito ay hindi tungkol sa pagkuha ng anumang content.
Ang realidad ng transcoding, bago ka mag-rent
Basahin muna ito dahil mababago nito ang bibilhin mo. Gumagawa ang media server ng isa sa dalawang bagay kapag pinindot ang play. Ang Direct play ay nag-i-stream ng file nang walang binabago: binabasa ng VPS ang mga bytes mula sa disk at ipinapadala ito, kaya halos walang ginagamit na CPU. Ang Transcoding ay nagre-re-encode ng video habang nagpe-play — bagong resolution, bagong codec, o naka-burn-in na subtitles — at ito ay purong CPU work.
Ang karaniwang VPS ay walang GPU. Kaya ang bawat transcode ay tumatakbo sa CPU gamit ang libx264/libx265, at mahal ang software encoding. Ang isang 1080p H.264 transcode ay maaaring mag-saturate ng ilang shared vCPUs; ang 4K o HEVC transcode ay karaniwang hindi makakasabay sa real time, kaya mag-i-stall at magbu-buffer ang playback nang matagal. Ang hardware transcoding — ang dahilan kung bakit mura ito sa home box na may Intel iGPU o Nvidia card — ay hindi available sa iyo maliban kung nag-aalok ang provider mo ng GPU instances.
Ang buong strategy sa VPS ay: iwasan ang transcoding. Panatilihin ang iyong library sa mga codec na kayang i-play nang native ng iyong mga client — H.264 video, AAC o AC3 audio, sa loob ng MP4 o MKV container — at pumili ng mga client app na may direct-play: ang mga native Jellyfin apps para sa Android TV, iOS at Roku, pati na ang Infuse, Kodi, at ang desktop Jellyfin Media Player. Kung gagawin mo iyan, hindi na gagamit ang VPS ng ffmpeg, at ang isang simpleng 2 vCPU box ay kayang mag-stream sa maraming tao nang sabay-sabay. Kung magpaplano kang mag-transcode, kakailanganin mo ng mas malaki at mas mahal na box, at kahit doon ay hindi sigurado ang 4K.
Kalkulahin din ang bandwidth dahil ito ang isa pang sorpresa. Ang direct play ay nagpapadala ng file sa sarili nitong bitrate. Ang isang compressed na 1080p file ay tumatakbo sa 8-12 Mbps; ang isang 1080p Blu-ray remux ay 20-30 Mbps; ang 4K HDR ay 40-80 Mbps. Ang tatlong tao na nag-di-direct-play ng 10 Mbps na mga file ay nangangailangan ng 30 Mbps na sustained upload mula sa iyong VPS. Suriin ang dalawang numero sa iyong plan: ang port speed (kaya ba nitong mag-push ng 30 Mbps upstream?) at ang monthly transfer cap. Ang isang dalawang-oras na 10 Mbps na pelikula ay humigit-kumulang 9 GB, kaya ang isang metered na 1 TB/month na allowance ay para lamang sa mahigit isang daang pelikula bawat buwan — tatlo o apat bawat araw — at ang isang household na nanonood ng 4K, na may apat hanggang walong beses na mas mataas na bitrate, ay mas mabilis na mauubos ang allowance.
Mga Prerequisites
- Isang bagong Ubuntu 24.04 KVM VPS na may root o sudo access, at naka-install na ang Docker at ang Compose plugin.
- Isang block-storage volume para sa media, na may sapat na laki para sa iyong library (tingnan ang sizing sa ibaba). Huwag ilagay ang iyong mga pelikula sa maliit na root disk na kasama ng VPS.
- Isang domain name kung kailangan mo ng public HTTPS access, o isang WireGuard VPN sa parehong VPS kung nais mong panatilihing private ang lahat.
- Media na legal mong karapatang i-stream — sarili mong rips, sarili mong recordings, o mga file na pagmamay-ari mo.
I-mount muna ang block storage
I-attach ang volume sa panel ng iyong provider, hanapin ito, at i-mount. Kunin ang device name mula sa lsblk — maaaring ito ay /dev/sdb o /dev/vdb; hindi ito ang 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 deviceI-mount ito gamit ang UUID, hindi gamit ang /dev/sdb. Nagbabago ang device letters pagkatapos ng reboot kaya maaaring ma-format o ma-mount ang maling disk. Magdagdag ng isang linya sa /etc/fstab:
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/media ext4 defaults,nofail 0 2sudo mount -a
df -h /mnt/mediaMahalaga ang nofail: kung wala ito, hindi magbu-boot ang server at papasok sa emergency shell kapag na-detach ang block volume. Ang pinakamalaking pagkakamali ay ang pagtakbo ng mkfs.ext4 sa volume na may laman nang data — mabubura nito ang lahat. I-format lamang ang mga bagong volume; kung may laman nang library ang disk, tumalon na agad sa fstab line.
I-ayos ang media ayon sa format ng Jellyfin
Ibinabase ng Jellyfin ang metadata sa pangalan ng folder at file. Kapag mali ang layout, magiging untitled ang mga pelikula at walang poster, o magkakamali ang pag-match ng episode sa maling series. May tatlong pangunahing tuntunin: ang bawat movie ay dapat nasa sariling Name (Year) folder na may katugmang filename; ang season folders ay dapat may pangalang Season 01, hindi S01; ang mga episode files ay dapat gumamit ng S01E01; at ang mga specials ay dapat nasa 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.mkvAng (Year) sa mga movie ay hindi dekorasyon — ginagamit ito para maiba ang mga remake para makuha ng matcher ang tamang title. Panatilihing hiwalay ang Movies at Shows bilang mga top-level folder dahil ang bawat isa ay magiging Jellyfin library para sa partikular na uri ng content. Ang paghahalo sa mga ito ay magpapagulo sa metadata provider.
Permissions: ang pangunahing dahilan kung bakit walang laman ang mga library
Narito ang maling akala na nag-aaksaya ng oras ng maraming user. Ang official jellyfin/jellyfin image ay hindi gumagamit ng PUID/PGID environment variables — ang mga ito ay para sa LinuxServer.io image (lscr.io/linuxserver/jellyfin). Sa official image, kontrolado ang user gamit ang user: key sa compose. Kung hindi ito ilalagay, tatakbo ang container bilang root. Anuman ang gamitin mo, iisa ang panuntunan: dapat may kakayahan ang uid/gid ng container na magbasa (read) at mag-traverse sa lahat ng media directory.
Gagamit tayo ng uid/gid 1000, ang unang non-root user sa isang stock Ubuntu box. I-verify ang iyong uid/gid at i-set ang 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 ~/jellyfinKailangan ng mga directory ang execute bit (ang x sa 755), hindi lang read — kung wala ito, hindi makakapasok ang container sa folder kahit na kaya nitong i-list ang mga pangalan. Ang trap na nagpapawala sa buong library ay ang parent directory: kung hindi ma-traverse ng uid ng container ang mismong mount, hindi nito maaabot ang /media/Movies o /media/Shows. Dahil dito, magiging walang laman ang lahat ng library at magpapakita ng Access to the path ... is denied sa log. Ang bawat media folder na hindi mabasa ay itatala sa log at lalaktawan (skip), kaya ang mga batch ng files na na-copy bilang root ay mawawala nang tahimik sa library. Ito ang dahilan kung bakit gumagamit tayo ng recursive chown at nagse-set ng execute bit sa bawat directory sa halip na isang folder lang ang ayusin.
Ang docker-compose file
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.comLine by line: user: "1000:1000" ang nagtatakda ng file permissions, para tumugma sa ownership sa itaas. /config ang naglalaman ng buong server — accounts, libraries, metadata, at watch state — kaya dapat itong writable at ito ang i-ba-backup mo. Ang /cache ay temporary working space lamang. Ang media mount ay :ro (read-only) sa sadyang paraan: default sa Jellyfin na i-store ang artwork at metadata sa ilalim ng /config, kaya hindi nito kailangang mag-write sa iyong library. Ang read-only ay proteksyon para sa iyong mga file laban sa aksidenteng pag-delete o maling plugin. Ang port ay sadyang naka-bind sa 127.0.0.1 — plain HTTP ang web login ng Jellyfin, kaya hindi natin i-pu-publish ang 8096 sa public internet. Ang JELLYFIN_PublishedServerUrl ay ang address na ginagamit ng server para sa local autodiscovery — isang LAN UDP broadcast, kaya hindi ito makikita ng mga client sa internet at gagamitin lang ang URL na itatype mo sa app. I-set ito sa address na dapat ibigay sa mga client, at asahan na kailangang i-type nang manual ang URL na iyon sa mga remote device.
I-run ito mula sa compose directory:
docker compose up -d
docker logs -f jellyfinUnang pagtakbo: ang setup wizard at ang iyong mga library
Dahil naka-bind ang port sa localhost, i-access ang wizard gamit ang SSH tunnel mula sa iyong laptop sa halip na magbukas ng firewall hole:
ssh -L 8096:127.0.0.1:8096 you@your-vps-ipMag-browse na sa http://localhost:8096. Gabayan ka ng wizard sa pagpili ng wika, pagkatapos ay ang paggawa ng admin user na may malakas na password — ang account na ito ang iyong server, kaya huwag gumamit ng temporary password. Idagdag ang iyong unang library: piliin ang content type na Movies, ituro ito sa /media/Movies (ang path sa loob ng container, hindi ang host path), at ulitin ang proseso para sa Shows sa /media/Shows. Tapusin ang setup, at magsisimulang mag-scan ang Jellyfin. Ang tamang resulta ay ang paglitaw ng mga poster at pamagat sa loob ng isa o dalawang minuto para sa maliit na library. Maaari nang magdagdag o mag-edit ng mga library sa ilalim ng Dashboard → Libraries, at i-force ang rescan gamit ang Scan All Libraries.
Kung gagamit ka ng transcoding, buksan ang Dashboard → Playback → Transcoding at i-set ang transcode temp path sa /cache/transcodes para ang mga temporary files ay mapunta sa cache volume sa halip na magpabusog sa /config. Iwanan ang hardware acceleration na naka-set sa None — walang GPU na magagamit para sa acceleration.
Remote access: TLS reverse proxy, o panatilihin sa VPN
May dalawang ligtas na paraan para ma-access ang Jellyfin mula sa labas, at isang hindi ligtas na paraan na dapat iwasan. Ang hindi ligtas na paraan ay ang pag-publish ng port 8096 nang direkta sa internet: ang login ay dadaan sa cleartext at mabilis na ma-ba-brute-force ang port sa loob ng ilang oras.
Option A — TLS reverse proxy. Ilagay ang Jellyfin sa isang subdomain sa likod ng Traefik na may automatic TLS para sa iyong mga Docker apps, o sa likod ng nginx na may Let's Encrypt certificate na inisyu ng Certbot. Gumagamit ang Jellyfin ng WebSockets para sa real-time updates, kaya dapat i-forward ng proxy ang upgrade headers. Awtomatikong ginagawa ito ng Traefik; kailangan namang i-specify ang mga ito sa nginx, at kailangan ang HTTP/1.1 sa upstream para gumana ang upgrade:
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";
}I-set ang JELLYFIN_PublishedServerUrl sa https:// address para ma-advertise ng local autodiscovery ang tamang URL — ginagamit ng mga remote app ang address na ibibigay mo — at magdagdag ng fail2ban para mapabagal ang brute-force attempts laban sa login. Kapag public na ang server, i-point ang Uptime Kuma sa URL para malaman mo ang downtime bago pa ito malaman ng iyong mga viewers.
Option B — panatilihing private sa VPN. Huwag i-publish ang 8096. I-access ang Jellyfin gamit lamang ang WireGuard tunnel na nakakonekta sa parehong machine. Para sa isang household, ito ang pinakasimpleng secure na opsyon — walang certificate, walang public exposure, at walang brute-force surface. I-bind ang container sa tunnel address o localhost at kumonekta sa pamamagitan ng VPN. Tingnan ang WireGuard VPN setup para sa isang private VPS para sa mismong tunnel.
Storage sizing and backups
Mag-budget base sa kalidad, hindi sa dami ng file. Ang compressed 1080p films ay tumatakbo sa 4-15 GB bawat isa; ang 1080p remux ay 20-40 GB; ang isang season ng 1080p TV ay 15-40 GB; ang anumang 4K ay 40-100 GB bawat film. Ang library na may ilang daang films at ilang shows ay nangangailangan ng 2-4 TB na volume. Mas matipid ang mag-over-provision ng block volume nang minsan kaysa mag-migrate sa hinaharap.
Ang /config ay ang buong server state, kaya ito ang tanging bagay na dapat mong i-back up. I-snapshot o i-stop-and-tar ito at itabi ang kopya sa labas ng machine:
docker compose down
sudo tar czf jellyfin-config-$(date +%F).tgz -C ~/jellyfin config
docker compose up -dAng /cache at ang transcode folder ay disposable. Ang media sa /mnt/media ay i-back up nang hiwalay o tanggapin na maaari itong i-re-rip muli — karamihan ay pinipili ang huli dahil sa laki nito. Ang mga upgrade ay docker compose pull && docker compose up -d; ang :10 tag sa itaas ay mananatili sa loob ng 10.x major, kaya ang paglipat sa susunod na major ay nangangailangan ng sadyang pag-edit ng tag — basahin ang Jellyfin release notes bago ito gawin, dahil ang library schema migrations ay nangyayari sa mga major versions.
Failure modes, with the strings you will see
Library is empty after a scan. Ang log sa Dashboard → Logs (o ~/jellyfin/config/log/log_*.log) ay nagpapakita ng:
System.UnauthorizedAccessException: Access to the path '/media/Movies' is denied.Hindi mabasa ng uid ng container ang path na iyon. Cause: ang media ay pagmamay-ari ng root o ng ibang uid maliban sa iyong user: value, may directory na walang execute bit, o ang parent mount mismo ay hindi traversable ng uid na iyon. Fix: chown -R 1000:1000 /mnt/media, i-set ang directories sa 755, i-set ang files sa 644, at mag-rescan.
Playback pins the CPU and buffers. Ipinapakita ng docker stats jellyfin ang CPU na malapit sa 100% times ang iyong core count, at ang Dashboard → Playback ay naglilista sa session bilang Transcode na may speed na mas mababa sa 1.0x. Hindi direct-playing ang client, kaya ang VPS ay nag-CPU-transcoding nang mas mabagal kaysa sa real time at nagkakaroon ng buffering. Cause: unsupported na codec o container, subtitle burn-in, o HDR tone-mapping. Fix: lumipat sa direct-play client, panatilihin ang mga source sa H.264/AAC, gumamit ng text subtitles (SRT) sa halip na image subtitles (PGS/VOBSUB) na nagpipilit ng burn-in, at huwag gumamit ng 4K HDR sa CPU-only na box.
"No compatible streams are available." Ang buong mensahe ay karaniwang "This client isn't compatible with the media and the server isn't sending a compatible media format." Tinanggihan ng client ang source at ang fallback transcode ay hindi rin nagsimula. Cause: may error sa ffmpeg command, hindi mabasa ang file, o ang user profile ay nagba-block sa video conversion. Fix: basahin ang ffmpeg line sa Dashboard → Logs, kumpirmahin kung gumagana ang file, suriin ang playback permissions ng user kung umaasa ka sa transcoding, at subukan ang ibang client para ma-rule out ang browser codec quirks.
Films have no poster or the wrong one. Hindi nagtugma ang metadata. Cause: ang movie ay wala sa tamang Name (Year) folder, ang season folder ay may pangalang S01 sa halip na Season 01, ang mga episode ay wala sa S01E01 format, o may kulang na taon. Fix: pangalanan muli ayon sa layout sa itaas, pagkatapos ay Refresh metadata → Replace all, o gamitin ang Identify sa isang item para i-pin ang tamang TMDB/TVDB entry.
FAQ
Kayang ba ng VPS mag-transcode ng video nang walang GPU?
Oo, pero CPU lang ang gagamitin nito, at mahal ito. Ang isang 1080p software transcode ay maaaring mag-saturate ng ilang vCPUs. Ang 4K o HEVC ay karaniwang hindi nakakasabay sa real time, kaya nagbu-buffer ang playback. Ang pinakamagandang paraan ay iwasan ang transcoding: panatilihin ang iyong library sa H.264/AAC at gumamit ng mga client app na may direct-play, para bytes lang ang i-stream ng VPS. Mag-rent lamang ng GPU instance kung kailangan mo talaga ng on-the-fly transcoding.
Bakit walang laman ang Jellyfin library ko pagkatapos ng scan?
Halos laging permissions ang sanhi nito. Ang official jellyfin/jellyfin image ay tumatakbo gamit ang anumang user: na itinakda mo (o root), at kung hindi mabasa ang mga file ng uid na iyon, mag-eerror ang scan logs Access to the path ... is denied at lalaktawan ang mga ito. Ayusin ang ownership gamit ang chown -R 1000:1000 /mnt/media, bigyan ang mga directory ng execute bit (755), at mag-rescan — i-check din ang parent directory, dahil kung hindi ma-traverse ng uid ng container ang /mnt/media, hindi nito maaabot ang mga library folder at magiging walang laman ang lahat. Ang pangalawang pinakakaraniwang sanhi ay ang folder layout na hindi tugma sa inaasahan ng Jellyfin.
Paano ko ma-aaccess ang Jellyfin nang remote at safe?
May dalawang mahusay na opsyon. Ilagay ito sa likod ng isang TLS reverse proxy sa isang subdomain para encrypted ang login at stream, at magdagdag ng fail2ban — huwag kailanman i-expose ang plain port 8096 dahil ipinapadala nito ang iyong password sa cleartext. O kaya ay panatilihin itong private at i-access lamang via VPN, ang pinakasimpleng safe choice para sa isang household. Ibigay ang public address nang direkta sa mga app — ang autodiscovery ay isang local-network broadcast, kaya hindi ito umaabot sa mga client na galing sa internet.
Gaano karaming disk at bandwidth ang kailangan ng Jellyfin VPS?
Depende ang disk sa quality: maglaan ng 4-15 GB bawat compressed 1080p film, 20-40 GB bawat remux, at 40-100 GB para sa 4K, kaya ang karamihan ng mga library ay nangangailangan ng 2-4 TB block volume. Ang bandwidth ay nakadepende sa direct-play bitrate — 8-12 Mbps bawat 1080p stream, at mas mataas para sa 4K — kaya siguraduhin na kaya ng port speed ang bilang ng sabay-sabay na viewers at bantayan ang monthly transfer cap. Magdagdag ng CPU headroom kung plano mong mag-transcode; unahin ang bandwidth kaysa sa cores kung plano mong mag-direct-play.
Legal ba ang pagpapatakbo ng Jellyfin sa VPS?
Ang Jellyfin mismo ay free, open-source software at legal ang pagpapatakbo nito. Ang mahalaga ay ang content: mag-stream lamang ng media na pagmamay-ari mo o may lisensya kang hawakan — ang sarili mong disc rips, recordings, o mga file na may karapatan ka. Walang kasamang media ang Jellyfin at wala itong paraan para kumuha ng media; ito ay player para sa library na pagmamay-ari mo na.