SSD Nodes Learn Hosting plans →
गाइड Matt Connorलेखक: Matt Connor · अपडेट किया गया: 2026-08-23

Jellyfin को 90s वीडियो स्टोर कैसे बनाएं: Halcyon गाइड

Halcyon के जरिए अपनी Jellyfin लाइब्रेरी को 90 के दशक के वीडियो स्टोर में बदलें। इस गाइड में Docker कमांड, रिवर्स प्रॉक्सी सेटअप और प्रोजेक्ट की सीमाओं की पूरी जानकारी दी गई है।

Halcyon आपकी Jellyfin लाइब्रेरी के साथ क्या करता है

Halcyon Video आपकी Jellyfin लाइब्रेरी को ब्राउज़र में 1990 के दशक की एक ऐसी वीडियो दुकान के रूप में दिखाता है जिसमें आप घूम सकते हैं। आपकी हर फिल्म शेल्फ पर एक केस बन जाती है। आप स्ट्रिप लाइट्स के नीचे गलियारों में चलते हैं, एक बॉक्स नीचे उतारते हैं, पीछे की जानकारी पढ़ने के लिए उसे पलटते हैं, और प्लेबैक शुरू करने के लिए उसे काउंटर तक ले जाते हैं। प्लेबैक शुरू होने, प्रगति और रुकने की रिपोर्ट वापस Jellyfin को भेजी जाती है, ताकि रिज्यूम पॉइंट्स और वॉच हिस्ट्री सही बनी रहे।

Halcyon Jellyfin API के माध्यम से मौजूदा Jellyfin सर्वर को पढ़ता है और अपनी कोई अलग लाइब्रेरी नहीं रखता है। यह गाइड मानती है कि Jellyfin पहले से चल रहा है और ठीक से स्कैन हो रहा है। यदि ऐसा नहीं है, तो पहले VPS पर मीडिया सर्वर के रूप में Jellyfin सेट करें और जब आपकी लाइब्रेरी सामान्य वेब क्लाइंट में सही दिखने लगे, तब वापस आएं। इसे आप इसलिए इंस्टॉल करते हैं क्योंकि लाइब्रेरी पहले से मौजूद है, न कि इसलिए कि आपको अपनी सेल्फ-होस्टिंग सूची में किसी और सर्विस की आवश्यकता थी।

यह प्रोजेक्ट GPL-3.0 लाइसेंस के तहत है और इसे एक व्यक्ति द्वारा लिखा गया है। README में स्पष्ट रूप से लिखा है कि यह पुल रिक्वेस्ट स्वीकार नहीं करता है। डेवलपमेंट तेजी से होता है और रिग्रेशन को संभालने के लिए कोई दूसरा मेंटेनर नहीं है, इसलिए किसी और को स्टोर दिखाने से पहले इमेज वर्जन को पिन कर लें। अंतिम सेक्शन में बताया गया है कि यह कैसे करना है।

रेंडरिंग कहाँ होती है?

ब्राउज़र में। Halcyon एक Vite और TypeScript ऐप है जिसे three.js पर बनाया गया है। यह एक JavaScript लाइब्रेरी है जो WebGL (वेब ग्राफिक्स लाइब्रेरी, जो GPU के लिए ब्राउज़र का इंटरफ़ेस है) के माध्यम से 3D ग्राफिक्स बनाती है। स्टोर की ज्यामिति (geometry) और बॉक्स आर्ट को उस मशीन द्वारा कंपोजिट किया जाता है जिस पर स्क्रीन लगी है।

कंटेनर बहुत कम काम करता है। यह npm run serve चलाता है, जो vite preview --port 1420 --strictPort --host है, और बिल्ट फाइलों के साथ कुछ छोटे मिडलवेयर रूट्स को सर्व करता है। Halcyon सर्वर पर कोई ट्रांसकोडिंग नहीं जोड़ता और न ही कोई इंजन चलाता है।

इसलिए GPU का प्रश्न क्लाइंट से संबंधित है। एक छोटा VPS इसे आसानी से सर्व कर सकता है, क्योंकि इसे सर्व करने का अर्थ है HTTP पर स्टेटिक फाइलें भेजना। ब्राउज़र चलाने वाला लैपटॉप, टैबलेट या टेलीविज़न ही यह तय करता है कि स्टोर सुचारू रूप से चलेगा या धीमा हो जाएगा।

एक फीचर इस नियम को तोड़ता है। Remote Play सर्वर पर हेडलेस Chromium इंस्टेंस शुरू करता है और रेंडर किए गए स्टोर को WebRTC (वेब रियल टाइम कम्युनिकेशन) के माध्यम से फोन या सेट टॉप बॉक्स पर स्ट्रीम करता है। वह पाथ सर्वर पर रेंडर होता है, जो डिफ़ॉल्ट रूप से दो इंस्टेंस तक सीमित है और इसे REMOTE_PLAY_MAX_INSTANCES के साथ समायोजित किया जा सकता है। बिना किसी मैप्ड /dev/dri डिवाइस के, वे इंस्टेंस CPU पर रेंडर होते हैं, इसलिए दो कोर वाला VPS हर अतिरिक्त दर्शक का भार महसूस करता है।

स्टोर आपकी लाइब्रेरी से क्या पढ़ता है

ये गलियारे Jellyfin की अपनी संरचना से आते हैं। Halcyon आपकी लाइब्रेरी और जॉनर (genres) से सेक्शन तैयार करता है, और यह आपके BoxSets से सीक्वल को एक साथ समूहबद्ध करता है। प्रत्येक केस के पीछे छपे स्पेसिफिकेशन उस MediaStreams मेटाडेटा से आते हैं जो Jellyfin में पहले से मौजूद है, जिसका अर्थ है कि जो कुछ भी Jellyfin में गायब है, वह शेल्फ पर भी नहीं दिखेगा।

यह स्टोर को आपके मेटाडेटा का एक सटीक प्रतिबिंब बनाता है। एक ऐसी लाइब्रेरी जो Docker Compose में एक arr stack से फीड होती है, जिसमें आर्टवर्क और जॉनर पहले से भरे हुए हैं, यहाँ उन फाइलों के फोल्डर की तुलना में बहुत बेहतर दिखती है जिनके नाम सामान्य (generic) हैं। फोटो लाइब्रेरी की निर्भरता भी उसी पर होती है जिसने उन्हें इंडेक्स किया है, जिसे याद रखना महत्वपूर्ण है जब आप एक ही सर्वर पर मौजूद तस्वीरों के लिए PhotoPrism बनाम Immich का मूल्यांकन करते हैं।

कुछ भी install करने से पहले video store demo को आजमाएं

यह प्रोजेक्ट एक synthetic library पर चलने वाले पूरे स्टोर को hosted demo पर प्रकाशित करता है। किसी भी Halcyon URL के अंत में ?demo=1 जोड़ने पर आपके अपने deployment पर भी यही परिणाम मिलता है।

इसे hardware test के रूप में उपयोग करें। demo library में लगभग 2,000 titles हैं और इसे ब्राउज़र की लगभग 2 GB memory की आवश्यकता होती है, जो अधिकांश personal libraries की तुलना में अधिक है। यदि demo उस device पर अटकता है जिसका उपयोग आप browse करने के लिए करने वाले हैं, तो आपकी अपनी library भी अटकेगी। इसका समाधान एक बड़ा VPS लेने के बजाय नीचे वर्णित 2.5D mode का उपयोग करना है।

इसे Docker के साथ चलाएं

यह वह command है जिसे upstream documentation में दिया गया है।

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

इसके बाद जांचें कि क्या यह चल पड़ा है।

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

Log में दिखना चाहिए कि preview server port 1420 पर listen कर रहा है, और curl को HTTP/1.1 200 OK का जवाब देना चाहिए। यदि कोई container कुछ ही seconds में बंद हो जाता है, तो इसका कारण लगभग हमेशा port होता है। --strictPort का अर्थ है कि server port 1420 के व्यस्त होने पर 1421 पर जाने से मना कर देता है, इसलिए वह बंद हो जाता है।

--network host का उपयोग Remote Play के लिए है, store के लिए नहीं। WebRTC को stream चाहने वाले device को machine का वास्तविक address बताना होता है। default Docker bridge के पीछे container केवल अपना 172.x address जानता है, जिस तक आपके network का कोई phone नहीं पहुँच सकता, इसलिए stream कभी connect नहीं होती। यदि आप केवल browser में store देखना चाहते हैं, तो port को publish करें।

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

VPS पर यह बेहतर default है, क्योंकि host networking container को machine के हर interface पर डाल देती है, जिसमें public interface भी शामिल है। VPS पर Docker चलाना इस विषय के बाकी पहलुओं को कवर करता है। --restart unless-stopped वह है जो reboot के बाद store को वापस लाता है, यह boot पर start होने वाली Compose services के समान ही है।

Repository को clone करके docker compose up -d चलाने से image locally build होती है। commit की गई Compose file default रूप से source से build करती है और इसमें पूर्व-निर्मित image: line comment की गई होती है, इसलिए यदि आप Compose के तहत प्रकाशित image चाहते हैं तो उस line को uncomment करें।

अगस्त 2026 तक एक कठिन सीमा यह है: प्रकाशित image केवल linux/amd64 है। multi-architecture push का arm64 हिस्सा emulation के तहत विफल हो गया था और यह native arm runners की प्रतीक्षा कर रहा है। arm64 VPS पर pull no matching manifest for linux/arm64/v8 in the manifest list entries के साथ विफल हो जाता है, और clone से build करना ही इसका एकमात्र समाधान है।

इसे अपने Jellyfin सर्वर पर पॉइंट करें

http://<host>:1420 खोलें और अपने Jellyfin सर्वर एड्रेस, यूजरनेम और पासवर्ड के साथ लॉग इन करें। रिपॉजिटरी में मौजूद .env.local.example फाइल केवल लोकल डेवलपमेंट के लिए है। Vite, VITE_ से शुरू होने वाले वेरिएबल्स को क्लाइंट-साइड कोड के लिए एक्सपोज करता है, इसलिए वहां लिखा गया Jellyfin पासवर्ड उस JavaScript बंडल में कंपाइल हो जाता है जिसे हर विजिटर डाउनलोड करता है। ऐसे सर्वर पर जिसे दूसरे लोग एक्सेस कर सकते हैं, इंटरफेस के माध्यम से ही लॉग इन करें।

ब्राउज़र सीधे Jellyfin से बात करता है। Halcyon का कंटेनर Jellyfin API को प्रॉक्सी नहीं करता है, और इसके दो परिणाम हैं जिन्हें डिबगिंग शुरू करने से पहले जानना आवश्यक है।

पहला, Jellyfin को न केवल उस VPS से, जो Halcyon को सर्व करता है, बल्कि ब्राउज़र से भी एक्सेस किया जाना चाहिए। 127.0.0.1:8096 पर बाइंड किया गया Jellyfin लोकल टेस्ट के लिए तो ठीक है, लेकिन यह बाकी सभी के लिए शेल्फ को खाली छोड़ देता है।

दूसरा, यह कॉल क्रॉस-ऑरिजिन है, जो Halcyon के एड्रेस से Jellyfin के एड्रेस पर जाती है। Jellyfin डिफ़ॉल्ट रूप से Access-Control-Allow-Origin: * के साथ API अनुरोधों का उत्तर देता है, इसलिए यह बिना किसी अतिरिक्त कॉन्फ़िगरेशन के काम करता है। यदि आपने उस सेटिंग को सीमित कर दिया है, या Jellyfin API के सामने कोई ऑथेंटिकेशन प्रॉक्सी लगा दी है, तो ब्राउज़र कंसोल blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource रिपोर्ट करेगा और स्टोर बिना किसी डेटा के लोड होगा।

इसे एक reverse proxy के पीछे रखें, और सामने authentication लगाएँ

vite preview एक preview server है। यह किसी भी TLS (transport layer security) को terminate नहीं करता है और इसमें अपना कोई access control नहीं है, इसलिए इसे किसी भी public नेटवर्क पर nginx या Caddy के पीछे रखना अनिवार्य है।

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 name के लिए एक अतिरिक्त सेटिंग की आवश्यकता होती है। DNS rebinding से बचाव के लिए Halcyon localhost, raw IP addresses और उस मशीन के नामों का जवाब देता है जिस पर वह चलता है। कंटेनर के अंदर, जिस मशीन पर यह चलता है वह स्वयं कंटेनर होता है, इसलिए इसका hostname आपका वाला नहीं होता। halcyon.example.com के रूप में आने वाले अनुरोध को अस्वीकार कर दिया जाता है, और प्रतिक्रिया में उस होस्ट का नाम होता है जिसे अस्वीकार किया गया है। उस नाम को जोड़ें।

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

यह मान comma से अलग किए जाते हैं, एक leading dot जैसे कि .example.com subdomains से मेल खाता है, और all इस जाँच को बंद कर देता है। all का उपयोग केवल ऐसी मशीन पर करें जिस तक बाहर से कोई न पहुँच सके।

एक बार जब store को https:// पर serve किया जाता है, तो login के समय आपके द्वारा टाइप किया गया Jellyfin address भी https:// होना चाहिए। एक browser HTTPS पेज से किए गए plain http:// API call को block कर देता है, और console में Mixed Content: The page at 'https://halcyon.example.com/' was loaded over HTTPS, but requested an insecure resource दिखाई देता है। login बस विफल हो जाता है, और Halcyon के अंदर इसका कोई स्पष्टीकरण नहीं मिलता है। दोनों को TLS पर serve करें, या दोनों को private नेटवर्क के अंदर plain HTTP पर रखें।

फिर authentication की बात आती है। store Jellyfin credentials मांगता है, इसलिए जो भी अजनबी URL ढूंढ लेता है, वह login स्क्रीन पर पहुँच जाता है। एक feature इसे बदल देता है। Settings और फिर Connection के अंतर्गत Remote Play को चालू करने पर, आप अपना Jellyfin session सर्वर को दे देते हैं ताकि /remote.html पर आने वाले आगंतुकों को आपकी वास्तविक library का अपना instance मिल सके। यही इस feature का उद्देश्य है, और इसका मतलब है कि URL की गोपनीयता ही internet और आपकी फिल्मों के बीच की दीवार है। यदि आप Remote Play सक्षम करते हैं, तो पूरी साइट के सामने Authentik as a self hosted SSO gateway के साथ single sign on लगाएँ, या public hostname को हटा दें और store तक a WireGuard tunnel managed with wg-easy के माध्यम से पहुँचें।

इसके साथ दो विवरण जुड़े हैं। reverse proxy केवल store को ले जाता है: Remote Play stream UDP पर WebRTC है और यह HTTP proxy के माध्यम से यात्रा नहीं करती है, इसलिए इसे 3478/udp और 49200 से 49260/udp पर अपने स्वयं के path की आवश्यकता होती है जब bundled TURN relay उपयोग में हो। और ऊपर दिया गया plain docker run कोई volume नहीं रखता है, इसलिए Remote Play seed docker rm के बाद सुरक्षित नहीं रहता है। Compose file इसी कारण से /data पर एक halcyon-data volume mount करती है और REMOTE_PLAY_SEED को /data/remote-play-seed.json पर सेट करती है।

जब store ठीक से काम न करे तो क्या करें

Halcyon मांग के अनुसार रेंडर करता है। एक idle store कोई frame composite नहीं करता है, और window focus खोने पर animation loop रुक जाता है, यही कारण है कि खुला हुआ tab laptop की battery खत्म नहीं करता है। यह उन मशीनों के लिए मददगार है जो केवल borderline performance वाली हैं। यह उन मशीनों के लिए कुछ नहीं करता जो store को बिल्कुल भी draw नहीं कर सकतीं।

ऐसे clients के लिए 2.5D mode उपलब्ध है, जो बिना WebGL के plain HTML और CSS का उपयोग करता है, और इसे Raspberry Pi जैसे छोटे hardware के लिए बनाया गया है। आप बिना page reload किए settings या power menu से 3D और 2.5D के बीच स्विच कर सकते हैं, इसलिए एक ही device पर दोनों का परीक्षण करने में कुछ ही सेकंड लगते हैं। आपको क्या मिलेगा, इसके बारे में यथार्थवादी रहें: लेखक flat mode को rough और अभी भी प्रगति पर बताते हैं। इसे कमजोर clients के लिए एक fallback के रूप में देखें।

जब कोई client 3D store के लिए बहुत छोटा होता है, तो विफलता स्पष्ट होती है। tab खुद को reload कर लेता है, या browser WebGL context खोने की रिपोर्ट देता है, आमतौर पर तब जब shelves अभी भी भर रही होती हैं। अपनी library को छोटा करने के बजाय उस device को 2.5D पर ले जाएं।

इमेज को पिन करें और पुल करने से पहले जाँचें

इस हिस्से को गंभीरता से लें। टैग v0.1.0 से v0.3.1 तक सभी कुछ ही दिनों के अंतराल पर आए हैं, और v0.2.1 केवल इसलिए मौजूद है क्योंकि v0.2.0 के लिए इमेज पुश विफल हो गया था। अपस्ट्रीम (upstream) पर बग रिपोर्ट का स्वागत है, लेकिन पैच का नहीं, इसलिए रिलीज़ स्ट्रीम किसी एक व्यक्ति की कार्यशील स्थिति (working state) है।

docker pull की आदत के साथ latest चलाने का मतलब है कि किसी भी सामान्य मंगलवार को स्टोर आपके नीचे बदल सकता है। डाइजेस्ट (digest) द्वारा पिन करें, यह एकमात्र ऐसा संदर्भ है जिसे बदला नहीं जा सकता।

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

यह टैग के पीछे का डाइजेस्ट प्रिंट करता है। टैग के स्थान पर इसका उपयोग करें।

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

वह डाइजेस्ट 10 अगस्त 2026 को 0.3.1 था। इसे कॉपी करने के बजाय स्वयं वर्तमान डाइजेस्ट को पढ़ें, और आगे बढ़ने से पहले रिलीज़ नोट्स पढ़ें, क्योंकि यहाँ एक पैच रिलीज़ में सुधारों के साथ-साथ स्टोर लेआउट में बदलाव भी हो सकते हैं।

FAQ

क्या मेरे VPS पर Halcyon के लिए GPU की आवश्यकता है?

सामान्य उपयोग के लिए नहीं। स्टोर को ब्राउज़र में three.js द्वारा रेंडर किया जाता है, इसलिए क्लाइंट मशीन ही रेंडरिंग करती है और कंटेनर केवल port 1420 पर स्टैटिक फाइलें सर्व करता है। इसका अपवाद Remote Play है, जो सर्वर पर headless Chromium चलाता है और परिणाम को स्ट्रीम करता है। यह पाथ CPU पर रेंडर होता है, जब तक कि आप हार्डवेयर एक्सेलेरेशन के लिए /dev/dri को कंटेनर में मैप न करें।

क्या मैं Halcyon को पब्लिक इंटरनेट पर डाल सकता हूँ?

केवल ऑथेंटिकेशन के पीछे। स्टोर Jellyfin क्रेडेंशियल्स मांगता है, लेकिन Remote Play को चालू करने से आपका Jellyfin सेशन सर्वर को मिल जाता है, इसलिए जो कोई भी /remote.html लोड करेगा, उसे बिना लॉग इन किए आपकी वास्तविक लाइब्रेरी का एक्सेस मिल जाएगा। इसके सामने सिंगल साइन-ऑन वाला एक रिवर्स प्रॉक्सी लगाएँ, या होस्टनेम को पब्लिक DNS से दूर रखें और स्टोर को VPN के माध्यम से एक्सेस करें।

लॉग इन करने के बाद शेल्फ खाली क्यों दिख रहे हैं?

ब्राउज़र सीधे Jellyfin API को कॉल करता है, इसलिए Jellyfin का ब्राउज़र से एक्सेस होना आवश्यक है, न कि केवल VPS से। ब्राउज़र कंसोल देखें। blocked by CORS policy का मतलब है कि Jellyfin, Halcyon के पते से आने वाले अनुरोध को स्वीकार नहीं कर रहा है। Mixed Content संदेश का मतलब है कि पेज HTTPS पर है जबकि आपके द्वारा दर्ज किया गया Jellyfin पता सादा HTTP है।

क्या मुझे --network host की आवश्यकता है?

केवल Remote Play के लिए। WebRTC को मशीन का वास्तविक पता विज्ञापित करना होता है, और Docker ब्रिज के पीछे कंटेनर केवल एक 172.x पता दे सकता है जिसे आपके नेटवर्क पर कोई फोन एक्सेस नहीं कर सकता। ब्राउज़र में स्टोर ब्राउज़ करने के लिए, -p 1420:1420 काम करता है और होस्ट के बहुत कम हिस्से को एक्सपोज़ करता है।

मुझे कौन सा इमेज टैग इस्तेमाल करना चाहिए?

latest के बजाय एक डाइजेस्ट (digest) को पिन करें। docker buildx imagetools inspect ghcr.io/halcyon-video/halcyon-video:0.3.1 वाले वर्ज़न के लिए डाइजेस्ट पढ़ें, उस डाइजेस्ट को चलाएँ, और रिलीज़ नोट्स पढ़ने के बाद ही आगे बढ़ें। अगस्त 2026 तक प्रकाशित इमेज केवल linux/amd64 है, इसलिए arm64 होस्ट को docker compose up -d के साथ क्लोन से बिल्ड करना होगा।