SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor

একটি Docker Compose ফাইলে Prowlarr, Sonarr ও Radarr সেটআপ

একটি Docker Compose ফাইলে Prowlarr, Sonarr, Radarr ও qBittorrent সেটআপ করার সঠিক নিয়ম জানুন। হার্ডলিঙ্ক কাজ করার জন্য সঠিক PUID, PGID ও ভলিউম লেআউট কনফিগার করার উপায় এখানে দেখুন।

আপনি যা তৈরি করছেন

একটি Docker Compose arr stack হলো 4টি container-এর সমন্বয়, যা একটি media library পরিচালনা করে: indexer settings-এর জন্য Prowlarr, series-এর জন্য Sonarr, films-এর জন্য Radarr এবং download client হিসেবে qBittorrent। তারা Compose network-এর মাধ্যমে service name ব্যবহার করে একে অপরের সঙ্গে যোগাযোগ করে এবং host-এ একটি folder tree ভাগ করে ব্যবহার করে। ইনস্টলেশনটি সংক্ষিপ্ত। stack-টি বছরের পর বছর নির্ভরযোগ্যভাবে চলবে, নাকি প্রতি সপ্তাহে সমস্যায় ফেলবে, তা মূলত volume layout-এর ওপর নির্ভর করে। তাই এই guide-এর বেশির ভাগ অংশ volume layout নিয়ে।

এই stack আপনার জন্য content খুঁজে দেয় না। Prowlarr-এ আপনি যে indexer যোগ করেন, সেগুলোই সেখানে থাকে। কোন indexer ব্যবহার করবেন, তা আপনার সিদ্ধান্ত এবং আইনি দায়িত্ব। এই guide-এ plumbing বিষয়গুলো দেখানো হয়েছে: users, paths, permissions, container networking এবং কাজটি সঠিকভাবে হচ্ছে কি না তা নিশ্চিত করার checks।

আপনি যদি আগে কখনো Compose file না লিখে থাকেন, আগে VPS-এর জন্য Docker Compose-এর মৌলিক বিষয়গুলো পড়ুন। এই post ধরে নিচ্ছে যে docker compose version ইতিমধ্যে আপনার server-এ কিছু output দেখায়। Docker Engine 28.0.0 বা তার পরের version ব্যবহার করুন: পুরোনো release-গুলোতে একই local network segment-এর host-গুলো localhost-এ published port-এ পৌঁছাতে পারত।

Sonarr কোনো download শেষ করলে ফাইলটি আপনার library-তে import করে। download folder এবং library folder একই filesystem-এ থাকলে এবং hardlinking enabled থাকলে Sonarr একটি hardlink তৈরি করার চেষ্টা করে: disk-এ একই data নির্দেশ করা দ্বিতীয় একটি নাম। এতে অতিরিক্ত space বা সময় লাগে না। torrent পুরোনো নাম থেকে seeding চালিয়ে যায়, আর আপনার media server নতুন নামটি পড়ে।

দুটি folder আলাদা filesystem-এ থাকলে kernel সেই link তৈরি করতে পারে না। Sonarr তখন copy করে। ফলে 40 GB-এর একটি season-এর জন্য 80 GB disk space এবং input ও output-এর কয়েক মিনিট সময় লাগে। Sonarr cross-filesystem hardlink failure-গুলো Trace level-এ এবং অন্যান্য hardlink exception Debug level-এ log করে। তাই সাধারণ log-এ failure message না থাকলেও failure ঘটতে পারে। নির্দিষ্ট disk allowance থাকা VPS-এ এভাবেই এক সপ্তাহের মধ্যে space শেষ হয়ে যায়।

এখানেই সমস্যা তৈরি হয়। একটি container-এর ভিতরে bind mount একটি filesystem boundary। /mnt/data/torrents-কে /downloads এবং /mnt/data/media-কে /tv হিসেবে mount করলে, দুটিই একই host disk-এ থাকলেও Sonarr এগুলোকে দুটি আলাদা mount হিসেবে দেখে এবং তাদের মধ্যে hardlink তৈরি করতে পারে না। LinuxServer.io-এর official image documentation-এ এটি সরাসরি বলা আছে: আলাদা /downloads এবং /tv path ব্যবহার করলে hardlink তৈরির সুবিধা নষ্ট হয়।

সমাধান হলো একটি mount ব্যবহার করা। Media নিয়ে কাজ করা প্রতিটি container একই single volume, /mnt/data:/data, পাবে এবং তারা যে path ব্যবহার করবে সেগুলো এই volume-এর ভেতরের folder হবে। একটি mount point, একটি filesystem, এবং কার্যকর hardlink।

ইউজার, গ্রুপ এবং ফোল্ডার তৈরি করুন

কন্টেইনারগুলো PUID এবং PGID দ্বারা নির্ধারিত একটি সংখ্যাসূচক ইউজার আইডি (numeric user id) হিসেবে ফাইল লেখে। আপনার নিজের অ্যাকাউন্ট ব্যবহার করুন যাতে আপনি sudo ছাড়াই SSH-এর মাধ্যমে সেই ফাইলগুলো পড়তে এবং এডিট করতে পারেন।

id -u
id -g

সাধারণত একটি নতুন Ubuntu VPS-এ উভয় কমান্ডই 1000 আউটপুট দেয়। এখন ডিরেক্টরি ট্রি তৈরি করুন। এটি আপনার মিডিয়া ধারণকারী যেকোনো ডিস্কে রাখুন এবং পুরো ট্রি-টি সেই একটি ডিস্কেই বজায় রাখুন।

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/data

TZ-কে আপনার নিজস্ব জোনে সেট করুন, যেমন 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

এই ফাইলের চারটি বিষয় বাস্তবে গুরুত্বপূর্ণ কাজ করে।

মিডিয়ার সঙ্গে কাজ করা তিনটি container-এই ${DATA_ROOT}:/data অভিন্ন। Prowlarr-এ এটি দেওয়া হয়নি, কারণ Prowlarr কখনো কোনো media file খোলে না।

প্রতিটি web port 127.0.0.1-এ bind করা হয়েছে, তাই Docker এটি শুধু loopback address-এ publish করে। সাধারণ 8989:8989 ব্যবহার করলে port-টি প্রতিটি interface-এ publish হতো, এবং Docker-এর নিজস্ব firewall rule সেই traffic-কে ufw-এর deny rule অতিক্রম করিয়ে দিত। এই আচরণে মানুষ প্রায়ই অবাক হয়। Docker কীভাবে ufw অতিক্রম করে সরাসরি port publish করে-এ বিষয়টি ব্যাখ্যা করা হয়েছে।

Port 6881 ইচ্ছাকৃতভাবে সব interface-এ publish করা হয়েছে। এটি torrent listening port, তাই incoming peer connection-এর জন্য এটি reachable থাকতে হয়। এখানেও Docker-এর একই আচরণ প্রযোজ্য। তাই এর জন্য ufw rule প্রয়োজন নেই, এবং এমন rule যোগ করলেও কিছু পরিবর্তন হবে না। November 8, 2026 তারিখে পরীক্ষা করা Docker-এর documentation অনুযায়ী, published port-এর traffic ufw ব্যবহৃত chain-এ পৌঁছানোর আগেই route হয়ে যায়। তাই এই port-এর ক্ষেত্রে sudo ufw allow 6881 কোনো প্রভাব ফেলে না। Container চালু হওয়ার সঙ্গে সঙ্গে Docker এটিকে host-এর সব interface-এ publish করে, এবং ufw-এর deny দিয়েও এটি বন্ধ হবে না। কখনো কারা এতে connect করতে পারবে তা সীমিত করতে হলে, Docker-এর documentation default iptables backend-এ তার DOCKER-USER chain-এ rule ব্যবহারের নির্দেশ দেয়। এর nftables backend-এর জন্য পরিবর্তে আলাদা nftables table-এ rule প্রয়োজন। Docker-এ না চলা service, যেমন SSH, এর জন্য ufw ব্যবহার করুন। এই tool নতুন হলে VPS-এর ufw firewall-এর প্রাথমিক বিষয়গুলো পড়ুন।

প্রতিটি application-এর config directory আলাদা, এবং শুধু media volume-টি shared। প্রথমবার start করার আগে এগুলো তৈরি করুন, যাতে এগুলোর owner root-এর পরিবর্তে আপনার user হয়:

mkdir -p ~/arr/config/prowlarr ~/arr/config/sonarr ~/arr/config/radarr ~/arr/config/qbittorrent
docker compose up -d
docker compose ps

চারটি service-এরই running পড়া উচিত। November 8, 2026 অনুযায়ী, এই image-গুলো lscr.io-এ published এবং latest tag-টি বর্তমান stable release অনুসরণ করে। তাই upgrade যেন হঠাৎ না হয়ে আপনার সিদ্ধান্ত অনুযায়ী হয়, চাইলে এর পরিবর্তে নির্দিষ্ট version tag pin করুন।

ওয়েব ইন্টারফেসে নিরাপদে পৌঁছান

ওয়েব ইন্টারফেসগুলো loopback-এ bind করা আছে। নিজের মেশিন থেকে SSH-এর মাধ্যমে এগুলো forward করুন:

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

এখন আপনার browser-এ http://127.0.0.1:8989 server-এর Sonarr-এ পৌঁছাবে। স্থায়ী access-এর জন্য stack-টিকে বেশ কয়েকটি অ্যাপের জন্য TLS certificate-সহ Traefik-এর পিছনে রাখুন, অথবা নিজে host করা WireGuard VPN-এর মাধ্যমে server-এ পৌঁছান। তবে VPN নিজে থেকে এই port-গুলোতে পৌঁছাতে পারে না। November 8, 2026-এ পরীক্ষা করা Docker-এর documentation অনুযায়ী, Docker Engine 28.0.0 বা নতুন version এবং default bridge configuration ব্যবহার করলে localhost address-এ published কোনো port-এ শুধু Docker host-ই access করতে পারে। VPN ব্যবহার করতে হলে VPN-এর মাধ্যমে SSH tunnel চালু রাখুন, অথবা Compose file-এ binding 127.0.0.1 থেকে VPN interface-এ server-এর নিজস্ব address-এ পরিবর্তন করুন। কোনো application-ই শুধু নিজের login page-এর ওপর নির্ভর করে public internet-এ রাখা উচিত নয়। Reverse proxy ব্যবহার করলে এবং চারটি আলাদা application login পরিচালনার বদলে সব interface-এর জন্য একটি account চাইলে, Authentik self-hosted single sign-on দেয়। Traefik forward auth ব্যবহার করে প্রতিটি request-এ এটি প্রয়োগ করতে পারে। Proxy-এর পিছনে Sonarr এবং Radarr-এর নিজস্ব দুটি বিশেষ বিষয় আছে। তাই Traefik-এর মাধ্যমে এগুলো route করার আগে reverse proxy-এর পিছনে Sonarr ও Radarr চালানোর পদ্ধতি পড়ুন। সেখানে Invalid Hostname error প্রতিরোধের জন্য Allowed Hosts entry এবং কেন /api-কে login এড়িয়ে যেতে হবে, তা ব্যাখ্যা করা হয়েছে।

qBittorrent প্রথমবার start হলে একটি random administrator password তৈরি করে এবং container log-এ তা print করে। Password-টি পড়ে web interface-এ পরিবর্তন করুন:

docker compose logs qbittorrent | grep -i password

পরিবর্তনটি না করলে প্রতিবার restart-এর সময় নতুন random password তৈরি হবে এবং প্রতিবার আপনাকে আবার log পরীক্ষা করতে হবে।

প্রতিটি অ্যাপ্লিকেশনের ভেতরে path নির্ধারণ করুন

qBittorrent-এ Options খুলুন। এরপর Downloads খুলে default save path হিসেবে /data/torrents নির্ধারণ করুন। অসম্পূর্ণ download-এর folder একই tree-এর মধ্যে রাখুন, যেমন /data/torrents/incomplete। /data-এর বাইরে কোনো download সম্পূর্ণ হলে এই Compose file দিয়ে সেটিকে hardlink করে library-তে যোগ করা যাবে না।

Sonarr-এ Settings খুলুন। এরপর Media Management খুলে root folder হিসেবে /data/media/Shows যোগ করুন। Radarr-এ root folder হলো /data/media/Movies। এগুলো container-এর ভেতরের path। host path /mnt/data/media/Shows প্রত্যাখ্যাত হবে, কারণ container-এর দৃষ্টিকোণ থেকে ওই directory অস্তিত্বশীল নয়।

Sonarr এবং Radarr উভয়টিতেই Settings খুলুন। এরপর Download Clients খুলে qBittorrent যোগ করুন। host হিসেবে qbittorrent এবং port হিসেবে 8080 দিন। service name hostname হিসেবে কাজ করে, কারণ Compose internal DNS (domain name system) service-সহ চারটি container-কে একই network-এ রাখে। এখানে localhost ব্যবহার করবেন না: Sonarr container-এর ভেতরে localhost হলো Sonarr।

Remote Path Mappings খালি রাখুন। download client যে path জানায়, সেটিকে arr application দেখতে পারে এমন path-এ রূপান্তর করার জন্য এই feature ব্যবহৃত হয়। একটি shared /data mount থাকায় উভয় container ইতিমধ্যেই প্রতিটি path সম্পর্কে একই তথ্য ব্যবহার করে। এই layout তৈরি করার চেষ্টা সার্থক হওয়ার এটিই দ্বিতীয় কারণ।

Sonarr এবং Radarr-এর সঙ্গে Prowlarr সংযুক্ত করুন

Prowlarr অন্যান্য অ্যাপ্লিকেশনে indexer-এর সংজ্ঞা পাঠায়। তাই একই indexer দুইবার configure করতে হয় না। এর জন্য প্রতিটি অ্যাপ্লিকেশন থেকে একটি API (application programming interface) key প্রয়োজন।

Sonarr-এ Settings খুলুন, তারপর General খুলে API key কপি করুন। Prowlarr-এ Settings খুলুন, তারপর Apps খুলে একটি Sonarr application যোগ করুন এবং 3টি field পূরণ করুন। Prowlarr Server হলো http://prowlarr:9696। Sonarr Server হলো http://sonarr:8989। API Key হলো কপি করা মানটি। Test চাপুন। সবুজ ফলাফল দেখালে বোঝায়, Prowlarr Compose network-এর মাধ্যমে Sonarr-এ পৌঁছাতে পেরেছে। Radarr-এর ক্ষেত্রেও একই কাজ করুন, তবে ঠিকানা হবে http://radarr:7878।

লাল ফলাফলে connection refused দেখালে বোঝায়, নির্ধারিত address ও port-এ কোনো listening service-এ সংযোগ পৌঁছায়নি। container-এর ভেতর থেকে name resolve হচ্ছে কি না যাচাই করুন:

docker compose exec prowlarr curl -sS -o /dev/null -w '%{http_code}\n' http://sonarr:8989

HTTP status code পাওয়া গেলে বোঝায় network path ঠিক আছে। name resolution error দেখালে বোঝায় service name resolve হয়নি। বানান এবং উভয় container একই Compose network-এ চলছে কি না যাচাই করুন।

হার্ডলিংক সত্যিই তৈরি হচ্ছে কি না প্রমাণ করুন

লিংক কাউন্ট না দেখা পর্যন্ত সেটআপকে নির্ভরযোগ্য ধরে নেবেন না। একটি আইটেম import হওয়ার পরে downloaded file এবং library file তুলনা করুন:

stat -c '%i %h %n' /mnt/data/torrents/tv/*/*.mkv
stat -c '%i %h %n' /mnt/data/media/Shows/*/*/*.mkv

প্রথম সংখ্যাটি inode এবং দ্বিতীয় সংখ্যাটি link count। একই filesystem-এ পরস্পরের hardlink হওয়া দুটি file একই inode দেখায় এবং link count কমপক্ষে 2 থাকে; অতিরিক্ত hardlink তৈরি হলে এই count বাড়ে। ভিন্ন inode হলে file দুটি পরস্পরের hardlink নয়। তবে এতে hardlink তৈরির চেষ্টা ব্যর্থ হয়েছে—এমন প্রমাণ হয় না। Sonarr-এর hardlink setting নিষ্ক্রিয় থাকলেও এটি hardlink তৈরির চেষ্টা না করে file copy করে। Cross-filesystem hardlink ব্যর্থতা Trace level-এ এবং অন্যান্য hardlink exception Debug level-এ log হয়। তাই সাধারণ import log থেকে ব্যর্থতার কারণ নিশ্চিতভাবে জানা যায় না।

Disk usage-ও monitor করুন। Import চলার সময় df -h /mnt/data-এ সামান্যই পরিবর্তন হওয়ার কথা, কারণ hardlink শুধু একটি নাম যোগ করে, কোনো data নয়।

আসলে কী নষ্ট হয়

Import-এর সময় permission error হলে বোঝায়, container-এর user id library folder-এ লিখতে পারছে না। বার্তাটি হলো Access to the path ... is denied। ls -ln /mnt/data/media দিয়ে পরীক্ষা করুন যে owner id আপনার PUID-এর সঙ্গে মেলে কি না। মনে রাখবেন, container কোনো directory-তে প্রবেশ করার আগে সেই directory-তে execute bit থাকতে হয়।

Host directory তৈরি হওয়ার আগে container চালু করলে root-owned directory তৈরি হতে পারে, কারণ Docker অনুপস্থিত bind-mount directory নিজে তৈরি করে। Stack বন্ধ করুন, directory-টি chown করুন, তারপর আবার চালু করুন।

qBittorrent থেকে কোনো torrent মুছে ফেলার পর library file-ও অনুপস্থিত দেখা গেলে কোন কোন path মুছে গেছে তা পরীক্ষা করুন। শুধু download মুছে ফেললে আলাদা library copy বা hardlink মুছে যায় না। প্রকৃত hardlink থাকলে একটি নাম মুছে ফেললেও অন্যটি অক্ষত থাকে, কারণ link count শূন্যে না নামা পর্যন্ত data মুক্ত হয় না।

আপনি যে media যোগ করেছেন তার তুলনায় disk দ্রুত পূর্ণ হলে সেটি copy সমস্যার সবচেয়ে ব্যয়বহুল রূপ। আরও storage কেনার আগে উপরের stat check চালান।

VPS থেকে এই স্ট্যাকের যা প্রয়োজন

তিনটি arr অ্যাপ্লিকেশনই হালকা। এগুলো indexer-এ poll করে, একটি ছোট SQLite database-এ লিখে এবং file-এর নাম পরিবর্তন করে। আসল load অন্য জায়গা থেকে আসে। বড় torrent চলার সময় download client disk input এবং output সম্পৃক্ত করে ফেলে। একই box-এ media server video transcode করলে CPU-তে চাপ পড়ে। প্রকৃত throughput-সম্পন্ন volume-এ media রাখুন। সার্ভারে আপনার গুরুত্বপূর্ণ অন্য কাজ চললে download client-এ bandwidth limit নির্ধারণ করুন। এসব কাজের জন্য আলাদা করে resource budget রাখুন। পর্যাপ্ত অতিরিক্ত capacity আছে ধরে নেবেন না। self-hosted AFFiNE workspace-এ database-সহ আরও চারটি container থাকে। AFFiNE-এর basic usage-এর জন্য 2 GB RAM এবং 10,000 শব্দের বেশি document-এর জন্য 4 GB RAM সুপারিশ করা হয়। self-hosted openGym workout tracker-এর মতো single-purpose অ্যাপের জন্য নিজস্ব TLS নির্ধারণ করুন। এক বছরের training history-এর দায়িত্ব দেওয়ার আগে এর data folder কোথায় আছে তা নিশ্চিত করুন। যে কোনো ব্যবস্থায় web application, একটি Postgres database এবং background worker queue থাকলে তা এই range-এর AFFiNE প্রান্তের কাছাকাছি resource ব্যবহার করে। তাই import চলার মাঝপথে সীমায় পৌঁছানোর আগে সিদ্ধান্ত নিন, self-hosted Chatwoot support desk এই সার্ভারে থাকবে, নাকি নিজস্ব সার্ভারে যাবে। Bursty workload-এর ক্ষেত্রে আরও সতর্ক থাকুন। কারণ import-এর সঙ্গে সংঘাত তৈরি করে average নয়, peak load। আপনি যদি প্রত্যেক ব্যক্তির জন্য নিজস্ব sandboxed agent চালানো self-hosted OneCLI বিবেচনা করেন, qBittorrent পুরো গতিতে চলার সময় বাস্তবে কত resource অব্যবহৃত থাকে তার সঙ্গে প্রকাশিত sizing number মিলিয়ে দেখুন। idle box-এ free -h যে মান দেখায়, তার সঙ্গে মিলিয়ে দেখবেন না।

FAQ

কারণ hardlinking নিষ্ক্রিয় করা আছে, অথবা hardlink তৈরির চেষ্টা ব্যর্থ হয়েছে। এর মধ্যে এমন অবস্থাও রয়েছে যখন container-এর দৃষ্টিতে source ও destination ভিন্ন filesystem-এ থাকে। /downloads ও /tv-এর মতো দুটি পৃথক bind mount পৃথক mount point, যদিও দুটিই একই host disk থেকে আসতে পারে। hardlink এই mount point অতিক্রম করতে পারে না। প্রতিটি container-এ একটি একক parent directory /data হিসেবে mount করুন এবং তার ভেতরে downloads ও library রাখুন। তাহলে link তৈরি করা সম্ভব হবে। উভয় ফাইলের ক্ষেত্রে stat -c '%i %h %n' চালিয়ে ফলাফল নিশ্চিত করুন। একই filesystem-এ থাকলে দুটিতে একই inode এবং অন্তত 2 link count দেখা যাবে।

কোন PUID এবং PGID ব্যবহার করব?

media tree-এর মালিক host account-এর numeric id ব্যবহার করুন। এই id id -u এবং id -g থেকে পাওয়া যাবে। নতুন Ubuntu VPS-এ সাধারণত উভয়ের জন্য 1000 থাকে। stack-এর প্রতিটি container-এ একই pair ব্যবহার করতে হবে। অন্যথায় একটি application এমন ফাইল লিখবে, যা অন্য application পরিবর্তন করতে পারবে না। মান পরিবর্তন করার পরে docker compose up -d --force-recreate দিয়ে container পুনরায় তৈরি করুন এবং chown -R দিয়ে বিদ্যমান ফাইলগুলোর ownership ঠিক করুন।

এই web interface-গুলো কি Internet-এ প্রকাশ করতে হবে?

না, এবং তা করা উচিত নয়। Compose file-এ প্রতিটি published port 127.0.0.1-এ bind করুন। এরপর SSH tunnel-এর মাধ্যমে, অথবা server-এ এমন একটি reverse proxy-এর মাধ্যমে interface-এ প্রবেশ করুন, যা TLS (transport layer security) termination করে এবং নিজস্ব authentication যোগ করে। Docker Engine 28.0.0 বা নতুন সংস্করণ এবং default bridge configuration ব্যবহার করলে শুধু VPN দিয়ে 127.0.0.1-এ published port-এ পৌঁছানো যায় না। কারণ Docker ওই published port-কে কেবল host থেকেই reachable করে। পুরোনো Docker release-গুলোতে একই local network segment-এর host-গুলো localhost-এ published port-এ পৌঁছাতে পারত। VPN-এর মাধ্যমে সরাসরি access চাইলে server-এর VPN address-এ port publish করুন। Public interface-এ সরাসরি publish করা যতটা নিরাপদ মনে হয়, বাস্তবে তার চেয়ে বেশি ঝুঁকিপূর্ণ। কারণ Docker নিজস্ব firewall rule যোগ করে, এবং একটি ufw deny rule ওই traffic আটকাতে পারবে না।

qBittorrent-এর password কোথায় পাব?

LinuxServer.io image startup log-এ admin user-এর জন্য একটি temporary password দেখায়। এটি পড়তে docker compose logs qbittorrent | grep -i password চালান। এরপর Options এবং Web UI-এর অধীনে একটি permanent password সেট করুন। আপনি নিজস্ব password সেট না করা পর্যন্ত প্রতিবার restart-এর সময় নতুন temporary password তৈরি হবে।

Jellyfin কি একই folder ব্যবহার করতে পারে?

হ্যাঁ, layout-এর উদ্দেশ্যই এটি। media server-এ /mnt/data/media-কে /media হিসেবে mount করুন। তাহলে এর library /media/Movies এবং /media/Shows-এ থাকবে, আর Sonarr ও Radarr /data/media-এর মাধ্যমে ওই একই directory-তে লিখবে। media server-এ একই PUID এবং PGID দিন, যাতে arr stack যে ফাইলগুলো লেখে সেগুলো পড়তে পারে।

এই লেখাটি কি কাজে লেগেছে?

#sonarr#radarr#prowlarr#docker-compose#self-hosting