Docker Compose में Prowlarr Sonarr Radarr सेटअप कैसे करें
एक ही Docker Compose फाइल में Prowlarr, Sonarr, Radarr और qBittorrent को सेटअप करें। हार्डलिंक्स को सही रखने के लिए PUID, PGID और वॉल्यूम लेआउट कॉन्फ़िगर करने का सटीक तरीका जानें।
आप क्या बना रहे हैं
Docker Compose arr स्टैक चार कंटेनरों का एक समूह है जो मीडिया लाइब्रेरी को प्रबंधित करता है: इंडेक्सर सेटिंग्स के लिए Prowlarr, सीरीज के लिए Sonarr, फिल्मों के लिए Radarr, और डाउनलोड क्लाइंट के रूप में qBittorrent। ये सर्विस नाम के माध्यम से Compose नेटवर्क पर एक-दूसरे से संवाद करते हैं और होस्ट पर एक ही फोल्डर ट्री साझा करते हैं। इंस्टॉलेशन संक्षिप्त है। वह हिस्सा जो यह तय करता है कि स्टैक वर्षों तक काम करेगा या हर हफ्ते समस्या पैदा करेगा, वह वॉल्यूम लेआउट है, इसलिए इस गाइड का अधिकांश हिस्सा इसी पर केंद्रित है।
यह स्टैक आपके लिए कंटेंट नहीं खोजता है। Prowlarr में आप जो भी इंडेक्सर जोड़ते हैं, वे इसमें रहते हैं, और आप किन इंडेक्सर्स का उपयोग करते हैं, यह आपका निर्णय और आपकी कानूनी जिम्मेदारी है। यह गाइड प्लंबिंग को कवर करती है: यूजर्स, पाथ, अनुमतियाँ, कंटेनर नेटवर्किंग, और वे जाँच जो यह सिद्ध करती हैं कि यह काम कर रहा है।
यदि आपने कभी Compose फाइल नहीं लिखी है, तो पहले the Docker Compose basics for a VPS पढ़ें। यह पोस्ट मानती है कि docker compose version आपके सर्वर पर पहले से ही कुछ आउटपुट देता है।
हार्डलिंक क्यों विफल होते हैं और यह पूरी प्रक्रिया क्यों महत्वपूर्ण है
जब Sonarr डाउनलोड पूरा करता है, तो वह फ़ाइल को आपकी लाइब्रेरी में इम्पोर्ट करता है। यदि डाउनलोड फ़ोल्डर और लाइब्रेरी फ़ोल्डर एक ही फ़ाइलसिस्टम पर स्थित हैं, तो इम्पोर्ट एक हार्डलिंक के रूप में होता है: एक दूसरा नाम जो डिस्क पर उसी डेटा को इंगित करता है। इसमें कोई अतिरिक्त स्थान या समय नहीं लगता है। टोरेंट पुराने नाम से सीडिंग जारी रखता है जबकि आपका मीडिया सर्वर नए नाम से उसे पढ़ता है।
यदि दोनों फ़ोल्डर अलग-अलग फ़ाइलसिस्टम पर हैं, तो कर्नल वह लिंक नहीं बना सकता है। Sonarr कॉपी करने की प्रक्रिया पर वापस चला जाता है। 40 GB का एक सीज़न अब डिस्क पर 80 GB स्थान लेता है और इसमें कई मिनट का इनपुट और आउटपुट समय लगता है, और इम्पोर्ट लॉग में यह दर्ज होता है कि हार्डलिंक विफल रहा और इसके बजाय फ़ाइल को कॉपी किया गया। एक निश्चित डिस्क क्षमता वाले VPS पर, इसी कारण से लोगों की डिस्क स्पेस एक सप्ताह में समाप्त हो जाती है।
यहाँ मुख्य समस्या है। कंटेनर के अंदर, एक बाइंड माउंट एक फ़ाइलसिस्टम सीमा होती है। यदि आप /mnt/data/torrents को /downloads के रूप में और /mnt/data/media को /tv के रूप में माउंट करते हैं, तो भले ही दोनों एक ही होस्ट डिस्क पर हों, Sonarr उन्हें दो अलग-अलग माउंट के रूप में देखता है और उनके बीच लिंक करने से इनकार कर देता है। आधिकारिक LinuxServer.io इमेज दस्तावेज़ीकरण स्पष्ट रूप से कहता है: अलग-अलग /downloads और /tv पथों का उपयोग करने से हार्डलिंक करने की क्षमता समाप्त हो जाती है।
इसका समाधान एक ही माउंट है। मीडिया से संबंधित प्रत्येक कंटेनर को एक ही वॉल्यूम, /mnt/data:/data प्राप्त होना चाहिए, और उनके द्वारा उपयोग किया जाने वाला प्रत्येक पथ इसके अंदर का एक फ़ोल्डर होना चाहिए। एक माउंट पॉइंट, एक फ़ाइलसिस्टम, और कार्यशील हार्डलिंक्स।
उपयोगकर्ता, समूह और फ़ोल्डर बनाएँ
कंटेनर PUID और PGID द्वारा निर्धारित संख्यात्मक उपयोगकर्ता आईडी (numeric user id) के रूप में फ़ाइलें लिखते हैं। अपने स्वयं के खाते का उपयोग करें ताकि आप sudo के बिना SSH के माध्यम से उन फ़ाइलों को पढ़ और संपादित कर सकें।
id -u
id -gएक नए Ubuntu VPS पर दोनों आमतौर पर 1000 प्रिंट करते हैं। अब ट्री (tree) बनाएँ। इसे उस डिस्क पर रखें जिसमें आपका मीडिया है, और पूरे ट्री को उसी एक डिस्क पर रखें।
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आगे बढ़ने से पहले जाँच लें कि यह वास्तव में एक ही फ़ाइल सिस्टम है:
df --output=source,target /mnt/data/torrents /mnt/data/mediaदोनों पंक्तियों में एक ही स्रोत डिवाइस दिखना चाहिए। दो अलग-अलग डिवाइस का मतलब है कि हार्डलिंक कभी काम नहीं करेंगे, चाहे आप कंटेनर कॉन्फ़िगरेशन में कुछ भी सेट करें।
लाइब्रेरी फ़ोल्डरों का नाम जानबूझकर Movies और Shows रखा गया है। यदि आप पहले से ही अपने मीडिया सर्वर के रूप में Jellyfin चला रहे हैं, तो /mnt/data/media को Jellyfin में /media के रूप में माउंट करें और इसकी लाइब्रेरी /media/Movies और /media/Shows पर आ जाएँगी, ठीक वहीं जहाँ वह गाइड उन्हें रखती है।
एनवायरनमेंट फ़ाइल
सर्वर के अनुसार बदलने वाले मानों को .env में रखें, जो Compose फ़ाइल के बगल में स्थित है।
mkdir -p ~/arr && cd ~/arr~/arr/.env लिखें:
PUID=1000
PGID=1000
TZ=Etc/UTC
DATA_ROOT=/mnt/dataTZ को अपने ज़ोन पर सेट करें, जैसे कि Europe/Berlin। arr एप्लिकेशन इसी ज़ोन में कार्यों को शेड्यूल करते हैं और लॉग लाइनों को स्टैम्प करते हैं, इसलिए गलत मान होने पर बाद में सभी लॉग भ्रमित करने वाले हो जाते हैं।
Compose फ़ाइल
~/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उस फ़ाइल में चार चीज़ें वास्तविक कार्य कर रही हैं।
${DATA_ROOT}:/data उन तीनों कंटेनरों में समान है जो मीडिया का उपयोग करते हैं। Prowlarr में यह नहीं है, क्योंकि Prowlarr कभी भी कोई मीडिया फ़ाइल नहीं खोलता है।
प्रत्येक वेब पोर्ट 127.0.0.1 से बंधा है, इसलिए Docker इसे केवल लूपबैक एड्रेस पर प्रकाशित करता है। एक साधारण 8989:8989 इसे हर इंटरफ़ेस पर प्रकाशित कर देगा, और Docker के अपने फ़ायरवॉल नियम उस ट्रैफ़िक को सीधे ufw deny नियम के पार ले जाएंगे। यह व्यवहार लोगों को लगातार आश्चर्यचकित करता है, और इसे Docker ufw के माध्यम से पोर्ट क्यों प्रकाशित करता है में समझाया गया है।
पोर्ट 6881 को जानबूझकर सभी इंटरफ़ेस पर प्रकाशित किया गया है। यह टोरेंट लिसनिंग पोर्ट है, और आने वाले पीयर कनेक्शन के लिए इसका पहुंच योग्य होना आवश्यक है। इसे sudo ufw allow 6881 के साथ अनुमति दें, और यदि यह कमांड आपके लिए नई है तो VPS के लिए ufw फ़ायरवॉल की बुनियादी बातें पढ़ें।
कॉन्फ़िगरेशन निर्देशिकाएं प्रत्येक एप्लिकेशन के लिए अलग हैं, और केवल मीडिया वॉल्यूम साझा किया गया है। उन्हें पहली बार शुरू करने से पहले बनाएं ताकि वे root के बजाय आपके उपयोगकर्ता के स्वामित्व में हों:
mkdir -p ~/arr/config/prowlarr ~/arr/config/sonarr ~/arr/config/radarr ~/arr/config/qbittorrent
docker compose up -d
docker compose psसभी चार सेवाओं को running पढ़ना चाहिए। जुलाई 2026 तक ये इमेज lscr.io पर प्रकाशित की जाती हैं और latest टैग वर्तमान स्थिर रिलीज़ का अनुसरण करता है, इसलिए यदि आप चाहते हैं कि अपग्रेड एक निर्णय हो न कि आश्चर्य, तो इसके बजाय एक वर्शन टैग पिन करें।
वेब इंटरफेस तक सुरक्षित रूप से पहुँचें
चूंकि पोर्ट्स लूपबैक पर हैं, इसलिए अभी कुछ भी एक्सपोज़ नहीं हुआ है। उन्हें अपनी मशीन से SSH के माध्यम से फॉरवर्ड करें:
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अब आपके ब्राउज़र में http://127.0.0.1:8989 सर्वर पर Sonarr तक पहुँच प्रदान करता है। स्थायी एक्सेस के लिए, स्टैक को कई ऐप्स के लिए TLS प्रमाणपत्रों के साथ Traefik के पीछे रखें, या स्वयं द्वारा होस्ट किए गए WireGuard VPN के माध्यम से सर्वर तक पहुँचें। इनमें से किसी भी एप्लिकेशन को केवल उनके अपने लॉगिन पेज के साथ सार्वजनिक इंटरनेट पर नहीं होना चाहिए।
qBittorrent पहली बार शुरू होने पर एक रैंडम एडमिनिस्ट्रेटर पासवर्ड जेनरेट करता है और उसे कंटेनर लॉग में प्रिंट करता है। इसे पढ़ें, फिर वेब इंटरफेस में इसे बदलें:
docker compose logs qbittorrent | grep -i passwordयदि आप इसे बदलना छोड़ देते हैं, तो हर रीस्टार्ट पर एक नया रैंडम पासवर्ड जेनरेट होगा, और आपको हर बार लॉग्स में वापस जाना पड़ेगा।
Set the paths inside each application
In qBittorrent, open Options, then Downloads, and set the default save path to /data/torrents. Keep the incomplete-downloads folder inside the same tree, such as /data/torrents/incomplete. A download that finishes anywhere outside /data cannot be hardlinked into the library.
In Sonarr, open Settings, then Media Management, and add the root folder /data/media/Shows. In Radarr the root folder is /data/media/Movies. These are paths inside the container. The host path /mnt/data/media/Shows is rejected, because that directory does not exist from the container's point of view.
In both Sonarr and Radarr, open Settings, then Download Clients, and add qBittorrent. The host is qbittorrent and the port is 8080. The service name works as a hostname because Compose puts all four containers on one network with an internal DNS (domain name system) service. Do not use localhost here: inside the Sonarr container, localhost is Sonarr.
Leave Remote Path Mappings empty. That feature exists to translate a path the download client reports into a path the arr application can see. With one shared /data mount, both containers already agree on every path, which is the second reason this layout is worth the effort.
Prowlarr को Sonarr और Radarr से कनेक्ट करना
Prowlarr इंडेक्सर परिभाषाओं को अन्य एप्लिकेशन में भेजता है, इसलिए आपको एक इंडेक्सर को दो बार के बजाय केवल एक बार कॉन्फ़िगर करना होता है। इसके लिए प्रत्येक से एक API (एप्लिकेशन प्रोग्रामिंग इंटरफ़ेस) कुंजी की आवश्यकता होती है।
Sonarr में, Settings खोलें, फिर General पर जाएं, और API कुंजी को कॉपी करें। Prowlarr में, Settings खोलें, फिर Apps पर जाएं, एक Sonarr एप्लिकेशन जोड़ें, और तीन फ़ील्ड भरें। Prowlarr Server http://prowlarr:9696 है। Sonarr Server http://sonarr:8989 है। API Key वह मान है जिसे आपने कॉपी किया था। Test दबाएं। हरे रंग का परिणाम यह दर्शाता है कि Prowlarr ने Compose नेटवर्क के माध्यम से Sonarr से संपर्क कर लिया है। Radarr के साथ http://radarr:7878 पर यही प्रक्रिया दोहराएं।
कनेक्शन अस्वीकार होने का लाल रंग का परिणाम लगभग हमेशा गलत सर्विस नाम या http:// प्रीफ़िक्स के न होने का संकेत देता है। पुष्टि करें कि नाम कंटेनर के अंदर से रिज़ॉल्व हो रहा है:
docker compose exec prowlarr curl -sS -o /dev/null -w '%{http_code}\n' http://sonarr:8989एक HTTP स्टेटस कोड यह साबित करता है कि नेटवर्क पाथ सही है। नाम रिज़ॉल्यूशन त्रुटि यह साबित करती है कि सर्विस नाम गलत है।
हार्डलिंक वास्तव में काम कर रहे हैं, यह सिद्ध करें
जब तक आप लिंक काउंट (link count) न देख लें, तब तक सेटअप पर भरोसा न करें। एक आइटम इम्पोर्ट हो जाने के बाद, डाउनलोड की गई फ़ाइल की तुलना लाइब्रेरी फ़ाइल से करें:
stat -c '%i %h %n' /mnt/data/torrents/tv/*/*.mkv
stat -c '%i %h %n' /mnt/data/media/Shows/*/*/*.mkvपहली संख्या inode है और दूसरी लिंक काउंट है। जिस फ़ाइल को हार्डलिंक किया गया है, वह दोनों स्थानों पर समान inode दिखाएगी और उसका लिंक काउंट 2 होगा। दो अलग-अलग inode, जिनमें से प्रत्येक का लिंक काउंट 1 है, का अर्थ है कि Sonarr ने फ़ाइल को कॉपी किया है, और इम्पोर्ट लॉग में यह लिखा होगा कि हार्डलिंक विफल रहा।
डिस्क पर भी नज़र रखें। जब इम्पोर्ट होता है, तो df -h /mnt/data में बहुत कम बदलाव होना चाहिए, क्योंकि हार्डलिंक केवल एक नाम जोड़ता है, डेटा नहीं।
वास्तव में क्या खराब होता है
इंपोर्ट के दौरान परमिशन संबंधी त्रुटियों का अर्थ है कि कंटेनर की user id लाइब्रेरी फ़ोल्डर में लिख नहीं सकती है। संदेश Access to the path ... is denied है। ls -ln /mnt/data/media के साथ जांचें कि ओनर id आपकी PUID से मेल खाती है या नहीं, और याद रखें कि कंटेनर के प्रवेश करने से पहले डायरेक्टरीज़ में execute बिट का होना आवश्यक है।
जो फ़ाइलें root के स्वामित्व में दिखाई देती हैं, उनका अर्थ है कि कंटेनर होस्ट डायरेक्टरी के अस्तित्व में आने से पहले ही शुरू हो गया था, इसलिए Docker ने इसे root के रूप में बनाया। स्टैक को रोकें, डायरेक्टरी को chown करें, और इसे फिर से शुरू करें।
qBittorrent से किसी टोरेंट को हटाने और लाइब्रेरी फ़ाइल के गायब होने का अर्थ है कि इंपोर्ट एक कॉपी थी जिसे बाद में हटा दिया गया, या आपने टोरेंट एंट्री के बजाय डेटा को हटा दिया। वास्तविक हार्डलिंक के साथ, एक नाम हटाने पर दूसरा सुरक्षित रहता है, क्योंकि डेटा तभी मुक्त होता है जब लिंक काउंट शून्य तक पहुँच जाता है।
डिस्क का आपके द्वारा जोड़ी गई मीडिया से अधिक तेज़ी से भरना कॉपी की समस्या का सबसे महंगा रूप है। अधिक स्टोरेज खरीदने से पहले ऊपर दिया गया stat चेक चलाएं।
इस स्टैक के लिए VPS की आवश्यकताएं
तीनों arr एप्लिकेशन हल्के होते हैं। ये इंडेक्सर्स को पोल करते हैं, एक छोटे SQLite डेटाबेस में लिखते हैं, और फ़ाइलों का नाम बदलते हैं। 2 GB RAM वाला सर्वर सभी चार कंटेनरों को आसानी से चला सकता है। लोड अन्य स्रोतों से आता है। एक डाउनलोड क्लाइंट बड़ी टोरेंट फ़ाइलों के दौरान डिस्क इनपुट और आउटपुट को पूरी तरह उपयोग कर लेता है, और उसी सर्वर पर वीडियो ट्रांसकोडिंग करने वाला मीडिया सर्वर CPU का उपयोग करेगा। मीडिया को ऐसे वॉल्यूम पर रखें जिसमें वास्तविक थ्रूपुट हो, और यदि सर्वर पर कोई अन्य महत्वपूर्ण कार्य चल रहा हो, तो डाउनलोड क्लाइंट पर बैंडविड्थ सीमा निर्धारित करें।
FAQ
Sonarr फ़ाइलों को हार्डलिंक करने के बजाय कॉपी क्यों करता है?
क्योंकि कंटेनर के दृष्टिकोण से स्रोत और गंतव्य अलग-अलग फ़ाइल सिस्टम पर हैं। दो अलग-अलग बाइंड माउंट, जैसे कि /downloads और /tv, दो अलग-अलग फ़ाइल सिस्टम होते हैं, भले ही वे दोनों एक ही होस्ट डिस्क से आ रहे हों। प्रत्येक कंटेनर में एक एकल पैरेंट डायरेक्टरी को /data के रूप में माउंट करें, डाउनलोड और लाइब्रेरी को इसके अंदर रखें, और लिंक संभव हो जाएगा। दोनों फ़ाइलों पर stat -c '%i %h %n' के साथ परिणाम की पुष्टि करें: समान इनोड और 2 की लिंक काउंट।
मुझे कौन सा PUID और PGID उपयोग करना चाहिए?
उस होस्ट अकाउंट की संख्यात्मक आईडी का उपयोग करें जिसके पास मीडिया ट्री का स्वामित्व है, जिसे आप id -u और id -g से प्राप्त करते हैं। एक नए Ubuntu VPS पर यह आमतौर पर दोनों के लिए 1000 होता है। स्टैक में प्रत्येक कंटेनर को एक ही जोड़ी का उपयोग करना चाहिए, अन्यथा एक एप्लिकेशन ऐसी फ़ाइलें लिखता है जिन्हें दूसरा संशोधित नहीं कर सकता। मान बदलने के बाद, docker compose up -d --force-recreate के साथ कंटेनरों को फिर से बनाएं और chown -R के साथ मौजूदा फ़ाइलों को ठीक करें।
क्या मुझे इन वेब इंटरफेस को इंटरनेट पर एक्सपोज़ करने की आवश्यकता है?
नहीं, और आपको ऐसा नहीं करना चाहिए। Compose फ़ाइल में प्रत्येक पब्लिश किए गए पोर्ट को 127.0.0.1 से बाइंड करें, फिर इंटरफेस तक पहुँचने के लिए SSH टनल, VPN, या रिवर्स प्रॉक्सी का उपयोग करें जो TLS (ट्रांसपोर्ट लेयर सिक्योरिटी) को समाप्त करता है और अपना स्वयं का प्रमाणीकरण जोड़ता है। उन्हें सीधे पब्लिश करना दिखने से कहीं अधिक बुरा है, क्योंकि Docker अपने स्वयं के फ़ायरवॉल नियम डालता है और एक ufw deny नियम उस ट्रैफ़िक को नहीं रोकेगा।
मुझे qBittorrent पासवर्ड कहाँ मिलेगा?
LinuxServer.io इमेज अपने स्टार्टअप लॉग में admin उपयोगकर्ता के लिए एक अस्थायी पासवर्ड प्रिंट करती है। इसे पढ़ने के लिए docker compose logs qbittorrent | grep -i password चलाएं, फिर Options और Web UI के अंतर्गत एक स्थायी पासवर्ड सेट करें। जब तक आप अपना पासवर्ड सेट नहीं करते, तब तक हर रीस्टार्ट पर एक नया अस्थायी पासवर्ड जेनरेट होता है।
क्या Jellyfin समान फ़ोल्डरों का उपयोग कर सकता है?
हाँ, और लेआउट का उद्देश्य यही है। /mnt/data/media को अपने मीडिया सर्वर में /media के रूप में माउंट करें, और इसकी लाइब्रेरी /media/Movies और /media/Shows पर स्थित होती हैं जबकि Sonarr और Radarr उन्हीं डायरेक्टरी में /data/media के माध्यम से लिखते हैं। मीडिया सर्वर को वही PUID और PGID दें ताकि वह उसे पढ़ सके जो arr स्टैक लिखता है।