SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor

Halcyon: Jellyfin Jadi Toko Video Tahun 1990-an

Halcyon mengubah library Jellyfin menjadi toko rental tahun 1990-an yang bisa dijelajahi di browser. Simak perintah Docker, reverse proxy, dan batasannya.

Yang dilakukan Halcyon terhadap library Jellyfin Anda

Halcyon Video menampilkan ulang library Jellyfin Anda sebagai toko video tahun 1990-an yang dapat dijelajahi di browser. Setiap film yang Anda miliki menjadi satu kaset pada rak. Anda berjalan di antara lorong di bawah lampu strip, mengambil kotak dari rak, membaliknya untuk membaca spesifikasi di bagian belakang, lalu membawanya ke konter untuk memulai playback. Informasi playback berupa mulai, progres, dan berhenti dikirim kembali ke Jellyfin, sehingga titik resume dan riwayat tontonan tetap benar.

Halcyon membaca server Jellyfin yang sudah ada melalui Jellyfin API dan tidak menyimpan library sendiri. Panduan ini mengasumsikan Jellyfin sudah berjalan dan memindai media tanpa masalah. Jika belum, siapkan Jellyfin sebagai server media di VPS terlebih dahulu, lalu kembali setelah library Anda tampil dengan benar di web client biasa. Ini adalah jenis aplikasi yang dipasang karena library-nya sudah tersedia, bukan karena Anda membutuhkan service lain dalam daftar self-hosting Anda.

Proyek ini berlisensi GPL-3.0 dan ditulis oleh satu orang. README menyatakan secara jelas bahwa proyek ini tidak menerima pull request. Pengembangan berlangsung cepat dan tidak ada maintainer kedua untuk menemukan regresi, jadi tetapkan versi image sebelum Anda memperlihatkan toko tersebut kepada orang lain. Bagian terakhir menjelaskan caranya.

Di mana proses rendering berlangsung?

Di browser. Halcyon adalah aplikasi Vite dan TypeScript yang dibangun di atas three.js, yaitu library JavaScript untuk menggambar grafis 3D melalui WebGL (web graphics library, antarmuka browser ke GPU). Geometri toko dan gambar sampul dirender secara komposit oleh perangkat yang menjalankan layar.

Container hanya menjalankan sedikit proses. Container menjalankan npm run serve, yaitu vite preview --port 1420 --strictPort --host, lalu menyajikan file hasil build serta beberapa route middleware kecil. Halcyon tidak melakukan transcoding dan tidak menjalankan engine di server.

Jadi, pertanyaan tentang GPU berkaitan dengan client. VPS kecil dapat menyajikan aplikasi ini tanpa masalah karena tugasnya hanya menyajikan file statis melalui HTTP. Laptop, tablet, atau televisi yang menjalankan browser menentukan apakah toko berjalan lancar atau tersendat.

Satu fitur tidak mengikuti aturan tersebut. Remote Play menjalankan instance Chromium headless di server dan mengalirkan toko yang telah dirender ke ponsel atau set top box melalui WebRTC (web real time communication). Pada jalur ini, rendering berlangsung di server. Secara default, jumlahnya dibatasi hingga dua instance dan dapat disesuaikan dengan REMOTE_PLAY_MAX_INSTANCES. Tanpa perangkat /dev/dri yang dipetakan, instance tersebut melakukan rendering pada CPU. Karena itu, VPS dengan dua core akan terasa terbebani setiap kali ada penonton tambahan.

Informasi yang dibaca toko dari library Anda

Lorong-lorongnya mengikuti struktur internal Jellyfin. Halcyon menyusun bagian berdasarkan library dan genre Anda, serta mengelompokkan sekuel dari BoxSets. Spesifikasi yang tercetak di bagian belakang setiap kotak berasal dari metadata MediaStreams yang sudah disimpan Jellyfin. Artinya, informasi yang tidak ada di Jellyfin juga tidak akan ada di rak.

Dengan demikian, toko ini mencerminkan metadata Anda secara akurat. Library yang diisi oleh stack arr dalam Docker Compose dan sudah dilengkapi artwork serta genre akan terlihat jauh lebih baik di sini daripada folder berisi file lepas dengan nama generik. Library foto juga bergantung pada apa pun yang mengindeksnya. Hal ini perlu diingat saat Anda membandingkan PhotoPrism dengan Immich untuk foto yang tersimpan di server yang sama.

Coba demo video store sebelum memasang apa pun

Proyek ini menyediakan seluruh video store yang berjalan menggunakan pustaka sintetis pada demo yang di-host. Menambahkan ?demo=1 ke URL Halcyon mana pun akan menghasilkan hal yang sama pada deployment Anda sendiri.

Gunakan demo ini sebagai pengujian perangkat keras, dengan satu pengecualian: demo menyesuaikan ukurannya dengan perangkat. Browser dengan kapasitas GPU yang masih besar akan memuat seluruh video store, sekitar 2,000 judul. GPU kelas menengah akan memuat sekitar 800 judul. Ponsel, atau browser apa pun yang melaporkan memori perangkat sebesar 4 GB atau kurang, akan memuat sekitar 300 judul. Demo yang berjalan lancar pada perangkat dengan kemampuan rendah sudah mengecilkan ukurannya sendiri, sehingga hasilnya tidak banyak memberi informasi tentang kinerja seluruh pustaka Anda pada perangkat tersebut. Pengujian yang berguna adalah menggunakan perangkat yang memuat seluruh video store. Jika tampilan tersendat, pustaka Anda sendiri dengan ukuran serupa juga akan tersendat. Solusinya adalah mode 2.5D yang dijelaskan di bawah, bukan VPS yang lebih besar.

Jalankan dengan Docker

Berikut adalah perintah yang didokumentasikan oleh upstream.

docker run -d --name halcyon --network host --restart unless-stopped \
  ghcr.io/halcyon-video/halcyon-video

Selanjutnya, periksa apakah layanan berhasil berjalan.

docker logs halcyon
curl -I http://127.0.0.1:1420

Log seharusnya menunjukkan bahwa server pratinjau mendengarkan pada port 1420, dan curl seharusnya merespons HTTP/1.1 200 OK. Container yang berhenti dalam beberapa detik hampir selalu mengalami masalah port. --strictPort berarti server menolak berpindah ke 1421 ketika 1420 sudah digunakan, sehingga server berhenti.

--network host diperlukan untuk Remote Play, bukan untuk store. WebRTC harus mengiklankan alamat mesin yang sebenarnya kepada perangkat yang meminta stream. Di balik bridge Docker default, container hanya mengetahui alamat 172.x miliknya sendiri. Tidak ada ponsel di jaringan Anda yang dapat menjangkaunya, sehingga stream tidak pernah tersambung. Jika Anda hanya ingin menggunakan store di browser, publikasikan port tersebut.

docker run -d --name halcyon -p 1420:1420 --restart unless-stopped \
  ghcr.io/halcyon-video/halcyon-video

Ini adalah konfigurasi default yang lebih baik pada VPS karena host networking menempatkan container pada setiap interface yang dimiliki mesin, termasuk interface publik. Menjalankan Docker pada VPS membahas konsekuensi lainnya. --restart unless-stopped yang menjalankan kembali store setelah reboot, dengan konsep yang sama seperti Service Compose yang berjalan saat boot.

Cloning repository dan menjalankan docker compose up -d akan membangun image secara lokal. File Compose yang dikomit secara default membangun image dari source dan menyertakan baris image: untuk image yang telah dibangun sebelumnya dalam keadaan dikomentari. Hapus komentar pada baris tersebut jika Anda ingin menggunakan image yang dipublikasikan melalui Compose.

Image yang dipublikasikan mendukung linux/amd64 dan linux/arm64. Berdasarkan pemeriksaan pada 9 October 2026, rilis 0.25.0 saat ini mencantumkan digest terpisah untuk setiap platform. Karena itu, VPS arm64 mengambil image dengan perintah yang sama seperti host lainnya. Periode khusus amd64 tersebut singkat: changelog menghapus image arm64 pada v0.2.1 tanggal 8 August 2026, lalu mengembalikannya dengan build pada runner native pada v0.4.0 tanggal 11 August 2026. Hanya host yang dikunci pada tag dari periode tersebut yang perlu membangun image dari hasil clone.

Arahkan ke server Jellyfin Anda

Buka http://<host>:1420, lalu masuk menggunakan alamat server Jellyfin, nama pengguna, dan kata sandi Anda. File .env.local.example dalam repositori hanya digunakan untuk pengembangan lokal. Vite mengekspos variabel dengan awalan VITE_ ke kode sisi klien. Karena itu, kata sandi Jellyfin yang ditulis di sana akan dikompilasi ke dalam bundel JavaScript yang diunduh oleh setiap pengunjung. Pada server yang dapat diakses orang lain, lakukan login melalui antarmuka.

Browser berkomunikasi langsung dengan Jellyfin. Container Halcyon tidak mem-proxy API Jellyfin. Hal ini menimbulkan dua konsekuensi yang perlu diketahui sebelum Anda mulai melakukan debugging.

Pertama, Jellyfin harus dapat dijangkau dari browser, bukan hanya dari VPS yang menyajikan Halcyon. Jellyfin yang terikat ke 127.0.0.1:8096 dapat digunakan untuk pengujian lokal, tetapi rak akan kosong bagi pengguna lain.

Kedua, panggilan tersebut bersifat lintas origin, dari alamat Halcyon ke alamat Jellyfin. Secara default, Jellyfin menjawab permintaan API dengan Access-Control-Allow-Origin: *, sehingga tidak memerlukan konfigurasi tambahan. Jika Anda mempersempit pengaturan tersebut atau menempatkan proxy autentikasi di depan API Jellyfin, konsol browser akan melaporkan blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource dan store akan dimuat dengan rak kosong.

Letakkan di belakang reverse proxy, dengan autentikasi di depannya

vite preview adalah server pratinjau. Server ini tidak melakukan TLS termination (transport layer security) dan tidak memiliki kontrol akses sendiri, sehingga harus ditempatkan di belakang nginx atau Caddy jika diakses publik.

server {
  listen 443 ssl;
  server_name halcyon.example.com;

  location / {
    proxy_pass http://127.0.0.1:1420;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

Domain yang ditempatkan di depan container memerlukan satu pengaturan tambahan. Halcyon merespons localhost, alamat IP langsung, dan nama mesin tempatnya berjalan sebagai perlindungan terhadap DNS rebinding. Di dalam container, mesin tempatnya berjalan adalah container tersebut, sehingga hostname-nya bukan hostname Anda. Permintaan yang tiba sebagai halcyon.example.com akan ditolak, dan responsnya menyebutkan host yang ditolak. Tambahkan nama tersebut.

docker run -d --name halcyon -p 127.0.0.1:1420:1420 --restart unless-stopped \
  -e HALCYON_ALLOWED_HOSTS=halcyon.example.com \
  ghcr.io/halcyon-video/halcyon-video

Nilainya dipisahkan dengan koma. Titik di awal, seperti .example.com, cocok dengan subdomain, sedangkan all menonaktifkan pemeriksaan. Gunakan all hanya pada mesin yang tidak dapat dijangkau dari luar.

Setelah store disajikan melalui https://, alamat Jellyfin yang Anda masukkan saat login juga harus berupa https://. Browser memblokir panggilan API http:// biasa yang dibuat dari halaman HTTPS, dan console menampilkan Mixed Content: The page at 'https://halcyon.example.com/' was loaded over HTTPS, but requested an insecure resource. Login akan gagal begitu saja tanpa penjelasan di dalam Halcyon. Sajikan keduanya melalui TLS, atau gunakan HTTP biasa untuk keduanya di dalam jaringan privat.

Selanjutnya, autentikasi. Store meminta kredensial Jellyfin, sehingga orang asing yang menemukan URL akan melihat halaman login. Namun, satu fitur mengubah kondisi ini. Mengaktifkan Remote Play melalui Settings lalu Connection memberikan sesi Jellyfin Anda kepada server, sehingga pengunjung /remote.html mendapatkan instance mereka sendiri dari library Anda yang sebenarnya. Itulah tujuan fitur ini, dan artinya kerahasiaan URL menjadi satu-satunya pembatas antara Internet dan film-film Anda. Jika mengaktifkan Remote Play, tempatkan single sign-on di depan seluruh situs menggunakan Authentik sebagai gateway SSO self-hosted, atau hapus hostname publik dan akses store melalui tunnel WireGuard yang dikelola dengan wg-easy.

Ada dua hal yang perlu diperhatikan. Reverse proxy hanya meneruskan store. Stream Remote Play menggunakan WebRTC melalui UDP dan tidak melewati proxy HTTP, sehingga memerlukan jalurnya sendiri pada 3478/udp serta 49200 hingga 49260/udp ketika bundled TURN relay digunakan. Selain itu, docker run biasa di atas tidak menyimpan volume, sehingga seed Remote Play tidak bertahan setelah docker rm. File Compose memasang volume halcyon-data pada /data dan menetapkan REMOTE_PLAY_SEED ke /data/remote-play-seed.json untuk alasan tersebut.

Apa yang harus dilakukan jika store berjalan buruk

Halcyon melakukan rendering sesuai permintaan. Store yang tidak aktif tidak merender frame apa pun, dan hilangnya fokus jendela menghentikan loop animasi. Karena itu, tab yang dibiarkan terbuka tidak menguras baterai laptop. Hal ini membantu perangkat yang hanya sedikit di bawah batas kemampuan. Namun, cara ini tidak membantu perangkat yang sama sekali tidak dapat merender store.

Untuk client tersebut, tersedia mode 2.5D berupa HTML dan CSS biasa tanpa WebGL. Mode ini ditujukan untuk perangkat dengan kemampuan serendah Raspberry Pi. Anda dapat beralih antara mode 3D dan 2.5D dari pengaturan atau menu daya tanpa memuat ulang halaman. Dengan demikian, pengujian kedua mode pada perangkat yang sama hanya memerlukan beberapa detik. Tetapkan ekspektasi yang realistis. Penulis menjelaskan bahwa mode datar tersebut masih kasar dan dalam pengembangan. Gunakan mode ini sebagai fallback untuk client yang lemah.

Jika client terlalu lemah untuk menjalankan store 3D, kegagalannya akan terlihat jelas. Tab dapat memuat ulang sendiri, atau browser melaporkan bahwa konteks WebGL terputus, biasanya saat rak masih diisi. Alihkan perangkat tersebut ke mode 2.5D, bukan mengurangi koleksi Anda.

Sematkan image, lalu periksa sebelum melakukan pull

Perhatikan bagian ini dengan serius. Tag v0.1.0 hingga v0.3.1 dirilis dalam rentang beberapa hari, dan v0.2.1 hanya ada karena image push untuk v0.2.0 gagal. Sejak saat itu, ritmenya tidak melambat: v0.25.0 dipublikasikan pada 7 October 2026, tiga hari setelah v0.23.0. Laporan bug diterima oleh upstream, tetapi patch tidak, sehingga rangkaian rilis ini mencerminkan kondisi kerja satu orang.

Menjalankan latest dengan kebiasaan docker pull berarti isi store dapat berubah tanpa pemberitahuan pada hari biasa. Sematkan berdasarkan digest, satu-satunya referensi yang tidak dapat berubah.

docker buildx imagetools inspect ghcr.io/halcyon-video/halcyon-video:0.25.0

Perintah tersebut menampilkan digest di balik tag. Gunakan digest itu sebagai pengganti tag.

docker run -d --name halcyon -p 1420:1420 --restart unless-stopped \
  ghcr.io/halcyon-video/halcyon-video@sha256:7fc00e619a30004d275faa79ad36d810e5a8530757132603065ba4e848dd67de

Digest tersebut adalah 0.25.0 pada 9 October 2026. Baca digest terbaru sendiri, jangan menyalinnya, dan baca catatan rilis sebelum melakukan pembaruan, karena patch release di sini dapat membawa perubahan tata letak store selain perbaikan.

FAQ

Apakah Halcyon memerlukan GPU pada VPS saya?

Tidak untuk penggunaan normal. Store dirender oleh three.js di browser, sehingga mesin klien melakukan rendering dan container hanya menyajikan file statis pada port 1420. Pengecualiannya adalah Remote Play, yang menjalankan headless Chromium di server dan melakukan streaming hasilnya. Jalur ini melakukan rendering pada CPU, kecuali Anda memetakan /dev/dri ke dalam container untuk akselerasi perangkat keras.

Apakah Halcyon dapat ditempatkan di Internet publik?

Hanya jika berada di balik autentikasi. Store meminta kredensial Jellyfin, tetapi saat Remote Play diaktifkan, sesi Jellyfin Anda diberikan kepada server. Akibatnya, siapa pun yang memuat /remote.html dapat memperoleh instance library nyata Anda tanpa login. Tempatkan reverse proxy dengan single sign on di depannya, atau jangan masukkan hostname tersebut ke DNS publik dan akses store melalui VPN.

Mengapa rak kosong setelah saya login?

Browser memanggil API Jellyfin secara langsung, sehingga Jellyfin harus dapat dijangkau dari browser, bukan hanya dari VPS. Buka konsol browser. blocked by CORS policy berarti Jellyfin tidak menerima permintaan dari alamat Halcyon. Pesan Mixed Content berarti halaman menggunakan HTTPS, sedangkan alamat Jellyfin yang Anda masukkan menggunakan HTTP biasa.

Apakah saya memerlukan --network host?

Hanya untuk Remote Play. WebRTC harus mengiklankan alamat sebenarnya mesin tersebut. Di balik Docker bridge, container hanya dapat menawarkan alamat 172.x yang tidak dapat dijangkau oleh ponsel mana pun di jaringan Anda. Untuk menjelajahi store di browser, -p 1420:1420 sudah memadai dan mengekspos host jauh lebih sedikit.

Tag image mana yang harus saya gunakan?

Tetapkan digest, bukan latest. Baca digest untuk versi yang memiliki docker buildx imagetools inspect ghcr.io/halcyon-video/halcyon-video:0.25.0, jalankan digest tersebut, dan lakukan pembaruan hanya setelah membaca catatan rilis. Per 9 October 2026, image yang dipublikasikan mencakup linux/amd64 dan linux/arm64. Dengan demikian, host arm64 dapat menariknya seperti biasa dan tidak perlu melakukan build dari clone.