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

Docker Compose-এ PUID এবং PGID কেন ব্যবহার করবেন?

PUID এবং PGID কোনো Docker সেটিংস নয়, বরং linuxserver.io ইমেজের একটি কনভেনশন। ফাইল পারমিশন সমস্যা বা 911 আইডি কেন আসে এবং কীভাবে এটি সঠিকভাবে কনফিগার করবেন তা জানুন।

PUID এবং PGID আসলে কী

PUID এবং PGID হলো দুটি environment variable, যা নির্দিষ্ট কিছু container image startup-এর সময় পড়ে। Docker নিজে কখনো এগুলো পরীক্ষা করে না। এগুলো একটি প্রচলিত convention, যা linuxserver.io image এবং আরও কিছু image ব্যবহার করে। তাই এগুলো পড়ার জন্য তৈরি করা হয়নি এমন image এগুলো নীরবে উপেক্ষা করে।

linuxserver.io image-এর ভিতরে abc নামের একটি user থাকে। Build time-এ এই user-টি UID (user ID) 911 এবং GID (group ID) 911 দিয়ে তৈরি করা হয়। Container root হিসেবে শুরু হয় এবং init script চালায়। সেই script-গুলোর একটি application শুরু হওয়ার আগে user-টির ID পরিবর্তন করে:

groupmod -o -g "${PGID}" abc
usermod -o -u "${PUID}" abc

-o flag এমন একটি ID ব্যবহারের অনুমতি দেয়, যা অন্য কোথাও ইতিমধ্যে ব্যবহৃত হচ্ছে। এরপর init privileges কমিয়ে application-টি abc হিসেবে চালায়। তাই Docker অন্য যেকোনো environment variable-এর মতো PUID=1000 container-এর ভিতরে পাঠায় এবং নিজে এর ওপর কোনো কার্যক্রম চালায় না। Application শুরু হওয়ার আগে variable-টি container-এর ভিতরের একটি user-এর ID পরিবর্তন করে। এর ফলে user namespace remapping ছাড়া standard rootful daemon-এ নতুন তৈরি file সাধারণত আপনার disk-এ 1000-এর মালিকানায় তৈরি হয়। আগে থেকেই writable কোনো file-এ লিখলে তার owner পরিবর্তিত হয় না। Rootless Docker এই সংখ্যাটি পরিবর্তন করে, যা নিচে ব্যাখ্যা করা হয়েছে। PUID unset রাখলে abc 911-এই থাকে। তাই configuration না-করা bind mount-এ সাধারণত 911:911-এর মালিকানাধীন file জমতে থাকে।

id দিয়ে আপনার দুইটি নম্বর বের করুন

ডেটা directory-গুলোর মালিক user হিসেবে host-এ এটি চালান:

id
uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),27(sudo),988(docker)

uid হলো আপনার PUID এবং gid হলো আপনার PGID। Script-এ id -u এবং id -g শুধু সংখ্যাগুলো দেখায়। অধিকাংশ নতুন VPS image-এ প্রথম human account-এর ID 1000:1000 হয়, তবে এটি ধরে নেবেন না। বরাদ্দ নির্ভর করে উপস্থিত account এবং configuration-এর ওপর। নতুন করে তৈরি করা server আবার 1000 বরাদ্দ করতে পারে, আর পরে তৈরি account উচ্চতর available ID পেতে পারে। আপনার service-গুলো যদি নিজের login user-এর পরিবর্তে একটি dedicated service account-এর অধীনে চলে, তাহলে id thatuser চালিয়ে সেখান থেকে নম্বরগুলো নিন।

আপনার ফাইল 911:911 হিসেবে কেন দেখা যাচ্ছে

ls -l কোনো host account-এর সঙ্গে ওই ID-এর মিল না থাকলে নামের পরিবর্তে numeric ID দেখায়। কোনো host account-এর UID 911-এর সঙ্গে মিল না থাকলে দেখানোর মতো কোনো নাম থাকে না। প্রতিবার সংখ্যা দেখতে এবং এই অস্পষ্টতা দূর করতে ls -ln ব্যবহার করুন:

ls -ln /srv/appdata/sonarr
drwxr-xr-x 2 911 911 4096 Aug  7 09:12 Backups
-rw-r--r-- 1 911 911  512 Aug  7 09:12 config.xml

এই output container-এর built-in default-এর সঙ্গে মিলে যায়। তবে শুধু existing file দেখে বর্তমানে application কোন user হিসেবে চলছে তা নিশ্চিত করা যায় না। ওই listing-এর config.xml ফাইলটিই authentication settings সংরক্ষণ করে। প্রথমবার web UI খুলে যখন দেখবেন যে Sonarr এবং Radarr-এ কোনো default username বা password থাকে না, তখন এটি গুরুত্বপূর্ণ। অনুমান না করে container-এর ভেতর থেকে নিশ্চিত করুন:

docker exec sonarr id abc
docker compose logs sonarr | head -n 25

linuxserver init startup log-এ তার ফলাফল 2টি লাইনে দেখায়:

User UID:    911
User GID:    911

আপনার Compose file-এ PUID=1000 সেট করার পরে যদি ওই লাইনগুলোতে 911 দেখা যায়, তাহলে running container আপনার সেট করা value ব্যবহার করছে না। সাধারণ কারণ হলো, আপনি docker-compose.yml সম্পাদনা করে এরপর docker compose restart চালিয়েছেন। এতে existing container-টি তার আগের environment-সহ পুনরায় ব্যবহার হয়। Environment পরিবর্তনের জন্য docker compose up -d প্রয়োজন, যা container-টি পুনরায় তৈরি করে। অন্য কারণটি ইচ্ছাকৃত আচরণ: কোনো image read-only বা non-root mode-এ চললে container-এ variable উপস্থিত থাকলেও init সম্পূর্ণ renumbering এড়িয়ে যায়। read-only mode-এ banner abc-এর অপরিবর্তিত ID দেখায়। non-root mode-এ এটি /run-এর owner দেখায়।

কেন আপনি কন্টেইনারের তৈরি করা কোনো ফাইল ডিলিট করতে পারেন না

কার্নেল ফাইলের নামের পরিবর্তে সংখ্যা (UID/GID) তুলনা করে। আপনার শেল UID 1000 হিসেবে চলে, কিন্তু ফাইলটির মালিকানা UID 911-এর। ফাইলটি যে ডিরেক্টরিতে আছে সেটিও drwxr-xr-x এবং সেটির মালিকানাও 911-এর, তাই group এবং other-এর জন্য শুধু read এবং execute অনুমতি আছে, কিন্তু write অনুমতি নেই। কোনো ফাইল ডিলিট করার জন্য ফাইলটিতে নয়, বরং ফাইলটি যে ডিরেক্টরিতে আছে সেখানে write অনুমতি থাকা প্রয়োজন। তাই ফাইলটি দেখতে সাধারণ মনে হলেও আপনি এই সমস্যার সম্মুখীন হন:

rm: cannot remove '/srv/appdata/sonarr/config.xml': Permission denied

একটি write-এর কাজ করা কন্টেইনার উল্টো দিক থেকে একই বাধার সম্মুখীন হয়। যদি হোস্ট ডিরেক্টরিটি আপনার ব্যবহারকারীর মালিকানাধীন হয় এবং mode 755-এ থাকে, আর অ্যাপ্লিকেশনটি 911 হিসেবে চলে, তবে প্রথমবার write করার সময় সেটি Permission denied ত্রুটির কারণে ব্যর্থ হবে এবং অ্যাপ্লিকেশনটি তার নিজস্ব ভাষায় এটি রিপোর্ট করবে। Sonarr বা Radarr-এর মতো .NET অ্যাপ্লিকেশনের ক্ষেত্রে এটি UnauthorizedAccessException: Access to the path '/data/downloads' is denied হিসেবে দেখা দেয়। ফাইলের নামের আগে থাকা permission string আপনাকে বলে দেয় যে তিনটি permission set-এর মধ্যে কোনটি দিয়ে আপনাকে যাচাই করা হচ্ছে, এবং drwxr-xr-x সঠিকভাবে পড়া শিখলে এই রহস্যময় ত্রুটিগুলো সহজেই বোঝা যায়।

এটি মূলত একটি bind mount সংক্রান্ত সমস্যা। যখন Docker একটি empty named volume তৈরি করে এবং সেটিকে ইমেজে থাকা কোনো পাথ-এর ওপর mount করে, তখন এটি সেই পাথ-এর বিষয়বস্তু ভলিউমে কপি করে নেয় (মালিকানা এবং permission bit সহ), ফলে অ্যাপ্লিকেশনটি এমন একটি ডিরেক্টরি পায় যার মালিকানা তার নিজেরই। bind mount-এর ক্ষেত্রে এমনটি ঘটে না: Docker আপনার হোস্ট ডিরেক্টরিটিকে ঠিক যেভাবে আছে সেভাবেই mount করে। এই পার্থক্যটিই হলো কখন bind mount ব্যবহার করবেন আর কখন named volume ব্যবহার করবেন তা জানার অন্যতম ব্যবহারিক কারণ।

ইতিমধ্যে ভুল থাকা একটি directory ঠিক করা

PUID এবং PGID সেট করলে এখন থেকে application-এর আচরণ পরিবর্তিত হয়। এটি disk-এ আগে থেকেই থাকা প্রতিটি file স্বয়ংক্রিয়ভাবে ঠিক করে না, যদিও নিচে বর্ণিত নির্দিষ্ট path-গুলোর ownership init ঠিক করে। stack বন্ধ করুন, নিজে ownership ঠিক করুন, তারপর আবার চালু করুন:

docker compose down
sudo chown -R 1000:1000 /srv/appdata/sonarr
docker compose up -d

সংখ্যাগুলো নিজে টাইপ করতে না চাইলে sudo chown -R "$(id -u):$(id -g)" /srv/appdata/sonarr ব্যবহার করুন। container বন্ধ থাকা অবস্থায় এটি করুন। কারণ recursive chown চলার সময় application লিখতে থাকলে directory tree আংশিকভাবে ঠিক হতে পারে এবং বিভ্রান্তিকর দ্বিতীয় দফার error তৈরি হতে পারে।

PUID এবং PGID যা ঠিক করে না

সঠিকভাবে সবকিছু করার পরও যে অংশটি অনেককে সমস্যায় ফেলে, এটি সেটিই। linuxserver base image-এর user setup script startup-এর সময় তিনটি path-এর ownership পরিবর্তন করে: /app, /config এবং /defaults। আপনার media mount-গুলো ওই তালিকায় নেই। /data, /downloads এবং /tv application-এর কাছে কোনো পরিবর্তন ছাড়াই হস্তান্তর করা হয়। তাই ওই mount-গুলোর host-side ownership এমন হলে, যাতে container user লিখতে না পারে, container স্বাভাবিকভাবে চালু হবে, banner-এ সঠিক UID দেখাবে, তারপর প্রথম import-এর সময় ব্যর্থ হবে।

এটাই সঠিক আচরণ। প্রতিবার container start হওয়ার সময় বারো terabyte-এর media library জুড়ে recursive chown চালানো বিপর্যয়কর হবে। এর মানে media directory-গুলোর দায়িত্ব আপনার, এবং permission-এর সমস্যা আসলে এই mount-গুলোতেই হয়। এ ধরনের ব্যর্থতা container সুস্থ মনে হওয়ার কয়েক ঘণ্টা পরে application log-এ নীরবে প্রকাশ পেতে পারে। তাই নিজের VPS-এ ntfy ব্যবহার করে ফোনে alert পাঠানো-র সঙ্গে একটি নিয়মিত write test যুক্ত করা সাশ্রয়ী সমাধান; এতে এক সপ্তাহের episode অনুপস্থিত থাকার পর বিষয়টি বোঝার আগেই আপনি জানতে পারবেন।

ব্যবহারকারী নিয়ন্ত্রণের তিনটি উপায় এবং কোনটি কখন প্রযোজ্য

PUID এবং PGID environment variable

এটি কেবল সেই image-এ কাজ করে, যার entrypoint এই variable পড়ে। এটি জনপ্রিয়, কারণ container প্রথমে root হিসেবে চালু হয়, নিজস্ব setup সম্পন্ন করে, /config ঠিক করে, এবং তারপর privilege কমিয়ে দেয়। Docker Mods এবং custom init script-ও কাজ করতে থাকে। এর বিনিময়ে platform feature-এর পরিবর্তে একটি প্রচলিত নিয়মের ওপর নির্ভর করতে হয়। তাছাড়া project ভেদে variable-এর নাম standard নয়।

Compose-এর user: key

এটি প্রকৃত Docker feature এবং সব image-এ কাজ করে, কারণ image-এর নিজস্ব code চলার আগেই container runtime এটি প্রয়োগ করে:

services:
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    user: "1000:1000"

Process কখনোই root হিসেবে চলে না, এক মুহূর্তের জন্যও নয়। এটি প্রকৃত security gain। তবে entrypoint-এ root privilege প্রয়োজন এমন সবকিছু এতে নষ্ট হয়। linuxserver image-এ project এটি reasonable endeavours basis-এ সমর্থন করে, এবং কেবল যেসব image তারা পরীক্ষা করেছে সেগুলোর জন্যই। সতর্কতাগুলো নির্দিষ্ট: PUID এবং PGID-এর আর কোনো প্রভাব থাকে না, Docker Mods চলবে না, custom service চলবে না, এবং প্রতিটি mounted volume-এর permission-এর দায়িত্ব আপনার। তাদের documented pattern-এ এই flag-এর সঙ্গে একটি writable /run ব্যবহার করা হয়:

user: 1000:1000
tmpfs:
  - /run:uid=1000,gid=1000,exec
security_opt:
  - no-new-privileges=true

একটি বাহ্যিকভাবে সামান্য প্রভাব অনেককে অবাক করে। Container-এর /etc/passwd-এ matching entry না থাকা numeric user: থাকলে ভেতরের tool-গুলো whoami: cannot find name for user ID 1000 দেখায়। ID বৈধ থাকে এবং file access স্বাভাবিকভাবে কাজ করে। শুধু name lookup ব্যর্থ হয়।

Rootless Docker

Rootless Docker daemon-টিকেই আপনার unprivileged user হিসেবে চালায়। ফলে daemon এবং container host-এর root privilege ছাড়াই চলে। এতে ownership-এর হিসাব সম্পূর্ণ বদলে যায়। Container UID 0 rootless Docker চালানো user-এর host UID-তে map হয়। আর container UID n-এর ক্ষেত্রে, যেকোনো n 1 বা তার বেশি হলে, এটি subuid + (n - 1)-এ map হয়; এখানে subuid হলো /etc/subuid-এ আপনার জন্য বরাদ্দ range-এর base। একই নিয়মে group ID-ও /etc/subgid ব্যবহার করে map হয়। Docker সেখানে অন্তত 65,536 subordinate ID প্রত্যাশা করে।

এই mapping আবার পড়ুন, কারণ এটি প্রচলিত পরামর্শের বিপরীত ফল দেয়। Rootless Docker-এ container root হিসেবে file তৈরি করলে সাধারণত file-টির মালিক আপনি হন। Container UID 1000 হিসেবে file তৈরি করলে সাধারণত file-টির মালিক একটি subordinate ID হয়, যেমন range 100000 থেকে শুরু হলে 100999। আপনার shell থেকে access permission এবং ACL-এর ওপর নির্ভর করে। File মুছতে সাধারণত containing directory-এর permission প্রয়োজন হয়, তাই আপনার নিয়ন্ত্রণাধীন directory থেকে সেই file মুছতে পারবেন। সুতরাং rootful daemon-এ সঠিক PUID এখানে ভুল হতে পারে। দুটি mechanism ভিন্ন layer-এ ownership পরিবর্তন করে। যাচাই না করে দুটিকে একসঙ্গে ব্যবহার করলে mounted data-তে লেখার ক্ষমতা হারাতে পারেন। Rootless ব্যবহারে library migrate করার আগে নিজের server-এ একটি লিখিত file-এর ownership পরীক্ষা করুন।

একটি single VPS-এ অধিকাংশ self-hosted stack-এর জন্য rootful daemon-এ PUID এবং PGID ব্যবহার করাই বাস্তবসম্মত পছন্দ, কারণ image-গুলো এটির জন্য তৈরি এবং documented। Image README-তে ওই image-এর জন্য পরীক্ষা করা হয়েছে বলা থাকলে, অথবা এমন official upstream image ব্যবহার করলে যার কোনো PUID support নেই, তখন user: ব্যবহার করুন। একটি VPS-এ self-hosted AFFiNE instance-এর মতো document workspace এই শেষ ক্ষেত্রের অন্তর্ভুক্ত। কারণ এর কোনো container PUID পড়ে না, এবং database directory ও uploaded file-এর ownership environment block-এর কোনো কিছু নয়, runtime নির্ধারণ করে। একটি self-hosted Chatwoot support desk-এর ক্ষেত্রেও একই কথা প্রযোজ্য। Rails container এবং তার Sidekiq worker উভয়ই একটি uploads directory-তে লেখে, কিন্তু কোনোটি PUID পড়ে না। তাই directory-টির ownership image ইতিমধ্যে যে user হিসেবে চলে, তার সঙ্গে মিলতে হবে। নতুন stack হলেও এই নিয়ম বদলায় না। তাই দলের প্রত্যেক ব্যক্তিকে নিজস্ব sandboxed OneCLI agent দেওয়া হলে per-person workspace directory এবং Postgres data directory প্রতিটি image যে user হিসেবে চলে, তার মালিকানায় থাকবে। এটি user: এবং chown-এর সমস্যা, PUID-এর নয়। Codex, Claude Code এবং Hermes-এর সামনে একটি self-hosted API রাখা হলে তার entrypoint একাধিক identity পরিচালনা করে। Container-কে root হিসেবে শুরু করতে হয়, console এবং gateway unprivileged user হিসেবে চলে, এবং প্রতিটি agent session নিজস্ব user হিসেবে চলে। ওই deployment-এ user: যোগ করবেন না। এর entrypoint data volume-এর ownership নিজেই পরিচালনা করে।

মিডিয়া স্ট্যাকের উদাহরণ: কনটেইনারগুলোর মধ্যে একটি shared group

Sonarr, Radarr এবং একটি download client-সহ arr media stack-এ এসে বিষয়টি আর শুধু তত্ত্ব থাকে না। Download client সম্পূর্ণ হওয়া ফাইলটি /data/downloads-এ লেখে। এরপর Sonarr সেই ফাইলটি /data/media-এ hardlink করে অথবা সরিয়ে নেয়। Hardlink কাজ করার জন্য দুইটি কনটেইনারের একই tree-তে write access থাকতে হবে। Download client যদি 1000 হিসেবে চলে এবং Sonarr shared group write permission ছাড়া 1001 হিসেবে চলে, তাহলে তাদের একটি এমন ফাইলের owner হয় যা অন্যটি শুধু পড়তে পারে।

সমাধান হলো একটি shared group তৈরি করা, যা stack-এর প্রতিটি কনটেইনার PGID হিসেবে ব্যবহার করবে:

sudo groupadd -g 13000 media
sudo usermod -aG media deploy
sudo chown -R deploy:media /srv/media
sudo find /srv/media -type d -exec chmod 2775 {} +
sudo find /srv/media -type f -exec chmod 0664 {} +

2775-এর শুরুতে থাকা 2 হলো setgid bit। কোনো directory-তে এটি থাকলে ভেতরে তৈরি প্রতিটি নতুন file ও subdirectory creator-এর নিজস্ব primary group-এর পরিবর্তে media group উত্তরাধিকারসূত্রে পায়। তাই প্রতিটি নতুন download-এর পরে আপনাকে chown আবার চালাতে হয় না। নিজের access পরীক্ষা করার আগে log out করে আবার log in করুন, অথবা newgrp media চালান। usermod -aG দিয়ে যোগ করা group ইতিমধ্যে খোলা shell session-এ দেখা যায় না।

কনটেইনারের ভেতরে groupmod -o -g 13000 abc কমান্ডটি abc group-কে 13000-এ renumber করে। ফলে abc আপনার host-এর media group-এর মতো একই GID দিয়ে লেখে। এই tree-তে access করা প্রতিটি linuxserver container নিজের PUID ধরে রাখে এবং একই PGID share করে। Finished library শুধু পড়ে এমন chain-এর পরের কনটেইনারগুলোর ক্ষেত্রেও এটি প্রযোজ্য, যেমন Jellyfin নিজে। Halcyon-এর মতো একটি front end, যা সেই library-কে হাঁটাচলা করা যায় এমন 90s video store হিসেবে পরিবেশন করে, HALCYON_JELLYFIN_URL ব্যবহার করে HTTP-এর মাধ্যমে Jellyfin-এর সঙ্গে সংযোগ করে। এর standard deployment-এর জন্য shared media PGID বা media-directory mount—কোনোটিই প্রয়োজন হয় না।

এরপর stack-এর প্রতিটি linuxserver container-এ UMASK=002 সেট করুন। এই ধাপটিই অনেকে বাদ দেন। এটি unset থাকলে, অন্য কোনো পরিবর্তন না হলে application তার inherited umask ব্যবহার করে। Image README-গুলোতে দেখানো example value হলো UMASK=022। Effective umask 022 হলে, নতুন file-এর জন্য application 0666 চাইলে default ACL না থাকায় 0644 পায়। ফলে group-এর অন্য সদস্যরা file পড়তে পারে, কিন্তু পরিবর্তন করতে পারে না। এতে আপনি সদ্য কনফিগার করা sharing-এর বেশিরভাগ সুবিধা নষ্ট হয়। 002 এবং কোনো default ACL না থাকলে, file-এর জন্য প্রচলিত 0666 এবং directory-এর জন্য 0777 চাইলে application 0664 file এবং setgid tree-এর ভেতরে 2775 directory তৈরি করে, যেখানে group লিখতে পারে। Umask কেবল permission bit সরাতে পারে। তাই application 0600 চাইলে এখনও 0600 পায়। Default ACL থাকা directory-তে umask সম্পূর্ণ উপেক্ষা করা হয়। PUID এবং PGID-এর পাশে variable-টি যোগ করুন:

services:
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - UMASK=002
      - TZ=Etc/UTC
    volumes:
      - /srv/appdata/sonarr:/config
      - /srv/media:/data
    restart: unless-stopped

এই দুইটি value Compose file-এর পাশে থাকা .env file-এ রাখুন, যাতে পুরো stack একটি definition পড়ে:

PUID=1000
PGID=13000

Compose স্বয়ংক্রিয়ভাবে ওই file পড়ে ${PUID}-ধরনের substitution-এর জন্য। Credentials-এর ক্ষেত্রেও একই mechanism ব্যবহার করা হয়। docker-compose.yml থেকে value সরিয়ে .env file-এ রাখার নিয়ম এখানেও প্রযোজ্য। পার্থক্য হলো, এই দুইটি সংখ্যা secret নয়।

Configuration-এর ওপর নির্ভর না করে শুরু থেকে শেষ পর্যন্ত যাচাই করুন। Application-এর user হিসেবে configured umask প্রয়োগ করে একটি নতুন file লিখুন, তারপর host থেকে সেটি পড়ুন। এমন একটি test filename ব্যবহার করুন, যা আগে থেকে নেই:

docker exec --user abc sonarr sh -c 'umask "$UMASK" && touch /data/downloads/permtest'
ls -ln /srv/media/downloads/permtest

সঠিক ফলাফলে owner হিসেবে আপনার PUID, group হিসেবে 13000 এবং mode হিসেবে -rw-rw-r-- দেখা যাবে। Group যদি 1000 দেখায়, ls -ldn /srv/media/downloads চালান। এর অর্থ হলো directory-তে setgid bit অনুপস্থিত—অর্থাৎ drwxrwsr-x-এর s নেই—অথবা directory-টি এখনও 1000 group-এর মালিকানাধীন, media-এর নয়। উপরের chown এবং chmod 2775 command দুইটি সমস্যাই ঠিক করে। Mode যদি -rw-r--r-- দেখায়, কনটেইনারের UMASK value এবং directory-এর default ACL পরীক্ষা করুন। Environment পুরোনো থাকলে কনটেইনারটি recreate করুন। এই test configured mask ব্যবহার করে abc হিসেবে file তৈরি করার বিষয়টি যাচাই করে। Application-এর নিজস্ব creation mode এবং effective umask এখনও তার file-এর permission নির্ধারণ করে। কাজ শেষ হলে rm /srv/media/downloads/permtest দিয়ে test file মুছে ফেলুন।

কোন image কোন variable ব্যবহার করে

linuxserver.io-এর image-গুলো PUID, PGID এবং UMASK ব্যবহার করে। Paperless-ngx একই ধারণার জন্য ভিন্ন নাম ব্যবহার করে: USERMAP_UID এবং USERMAP_GID; দুটির default মান 1000। তাদের documentation-এ এগুলো id -u এবং id -g থেকে পড়তে বলা হয়েছে। Photo server-গুলোতেও একই ভিন্নতা দেখা যায়: PhotoPrism-এর নিজস্ব PHOTOPRISM_UID এবং PHOTOPRISM_GID জোড়া আছে, কিন্তু Immich-এ এর সমতুল্য কোনো variable নেই। এটি Docker-এর user: key-এর ওপর container user নির্ধারণের দায়িত্ব ছেড়ে দেয়। তাই PhotoPrism ও Immich-এর মধ্যে বেছে নেওয়া মানে box-এর সবচেয়ে বড় library-এর জন্য কোন user-management পদ্ধতি বজায় রাখবেন, সেটিও নির্ধারণ করা। সাধারণ database ও web server image-সহ অনেক official upstream image-এ একটি নির্দিষ্ট built-in user থাকে। এগুলোতে user: ব্যবহার করার প্রত্যাশা থাকে, অথবা কোনো পরিবর্তন না করাই উচিত। ছোট single-app deployment-এও একই প্রশ্ন আসে। তাই self-hosted openGym workout tracker চালু করার আগে তার container আসলে কোন user হিসেবে চলে তা যাচাই করুন। এর database থাকা directory-র ownership সেই user অনুযায়ী নির্ধারিত হবে, আপনি PUID set করুন বা না করুন। Remote access relay-ও একই শ্রেণির। তাই নিজের RustDesk relay server চালানোর সময় hbbs প্রথমবার চালু হলে যে Ed25519 key pair লেখে, তা আপনার bind mount-এ ওই image শেষ পর্যন্ত যে user হিসেবে চলেছিল তার ownership-এ তৈরি হবে। পরে host side chown দিয়ে ownership ঠিক করতে পারেন। অথবা user: key দিয়ে শুরুতেই identity নির্ধারণ করতে পারেন। কারণ ওই image নিজে কোনো user set করে না। তবে আপনি যে ID বেছে নেবেন, mounted directory-টি সেই ID-এর জন্য writable হতে হবে। পরে যোগ করা infrastructure-এর ক্ষেত্রেও একই নিয়ম প্রযোজ্য। তাই একটি login-এর জন্য আপনার app-গুলোর সামনে Authentik বসালে official authentik এবং Postgres image চালানো হবে। এগুলো PUID পড়ে না। তাদের volume ownership নির্ধারিত হয় process যে user হিসেবে চলে এবং entrypoint যে setup সম্পন্ন করে, তার ভিত্তিতে। Authentik release 2025.10-এ Redis dependency সরিয়ে দিয়েছে।

তাই project-গুলোর মধ্যে কোনো environment block কপি করার আগে প্রতিটি image-এর README পরীক্ষা করুন। আপনি যে environment variable set করেন, Docker সেটি যেকোনো container-এ পাঠায়, ভেতরের কোনো process সেটি পড়ুক বা না পড়ুক। কোনো কিছু ব্যবহার না করা PUID-এর কারণে কোনো error, warning বা কার্যকর পরিবর্তন হয় না। Docker-এর user: setting অথবা Dockerfile নির্ধারিত user হিসেবে container শুরু হয়। এরপর application শুরু করার আগে তার entrypoint privileges কমিয়ে দিতে পারে। Box-এ নতুন কিছু যোগ করার আগে এই বিষয়টি পড়ে নিন। এর মধ্যে self-hosted open-kritt security scanning stack-ও অন্তর্ভুক্ত। Compose file দেখে বুঝুন image-গুলো PUID সমর্থন করে কি না, অথবা আপনি যে directory mount করেন তার ownership image-গুলো নিজেরাই নির্দিষ্ট করে কি না।

FAQ

আমার Docker ফাইলের মালিকানা 911:911 কেন?

911 হলো linuxserver.io image-এ অন্তর্ভুক্ত abc user-এর UID এবং GID। এটি image-এর built-in default-এর সঙ্গে মিলে যাওয়াই স্বাভাবিক। তবে container-এর PUID এবং PGID পরিবর্তন করার পরও ফাইলের মালিকানা আগের মতো থাকতে পারে। আপনার host-এ ওই ID-র কোনো account না থাকলে ls -l কাঁচা সংখ্যা দেখায়, কারণ প্রদর্শনের জন্য কোনো নাম থাকে না। id-এর output অনুযায়ী PUID এবং PGID সেট করুন। এরপর docker compose up -d দিয়ে container পুনরায় তৈরি করুন। শেষে প্রভাবিত directory-তে sudo chown -R 1000:1000 চালিয়ে বিদ্যমান ফাইলগুলোর মালিকানা ঠিক করুন।

প্রতিটি Docker image-এ কি PUID এবং PGID কাজ করে?

না। এগুলো Docker-এর feature নয় এবং Docker এগুলো পড়ে না। শুধু সেই image-গুলোতেই এগুলো কাজ করে, যাদের নিজস্ব entrypoint এগুলো পড়ে এবং application চালু করার আগে usermod ও groupmod চালায়। linuxserver.io family এবং এই pattern অনুসরণ করা কয়েকটি project-এ এটি থাকে। অন্য project-এ অন্য নাম ব্যবহৃত হয়। যেমন paperless-ngx-এ USERMAP_UID এবং USERMAP_GID ব্যবহৃত হয়। কোনো image যদি এগুলোর কোনোটিই না পড়ে, তাহলে variables গ্রহণ করা হলেও কোনো warning ছাড়াই উপেক্ষা করা হয়।

Docker Compose-এ কি PUID এবং PGID ব্যবহার করব, নাকি user: key ব্যবহার করব?

Image এগুলো সমর্থন করলে PUID এবং PGID ব্যবহার করুন। এতে entrypoint যথেষ্ট সময় root হিসেবে চলে /config ঠিক করতে এবং নিজস্ব service সঠিকভাবে চালু করতে পারে। Image নির্বাচিত user-এর জন্য support নথিভুক্ত করলে user: ব্যবহার করুন। শুধু PUID support না থাকলেই entrypoint root ছাড়া কাজ করবে—এমন নয়। linuxserver image-এ user: সেট করলে PUID এবং PGID নিষ্ক্রিয় হয়, Docker Mods ও custom service চালানো বন্ধ হয়, এবং প্রতিটি mounted volume-এর permission পরিচালনার দায়িত্ব আপনার ওপর পড়ে।

Sonarr-এর সঠিক PUID থাকা সত্ত্বেও ফাইল সরাতে পারছে না। সমস্যা কী?

ক্রম অনুযায়ী 3টি বিষয় পরীক্ষা করুন। প্রথমে media mount নিজে পরীক্ষা করুন। Base image-এর user setup script /app, /config এবং /defaults-এ chown চালায়। তাই /data বা /downloads থাকলে host-এ directory-টির যে ownership আছে, সেটিই বজায় থাকে। দ্বিতীয়ত shared group পরীক্ষা করুন। Media tree-তে access থাকা container-গুলোকে একই PGID দিন এবং group write permission দিন। তৃতীয়ত umask পরীক্ষা করুন। Application 0666 চাইলেও কোনো default ACL প্রযোজ্য না হলে কার্যকর mask 022, 0644 permission-সহ ফাইল তৈরি করে। ফলে group-এর অন্য container-গুলো ফাইল পড়তে পারে, কিন্তু পরিবর্তন করতে পারে না। UMASK unset রাখলে নির্দিষ্ট কোনো mask বা file mode নিশ্চিত হয় না। UMASK=002 সেট করুন এবং chmod 2775 দিয়ে directory-গুলোতে setgid bit সেট করুন, যাতে নতুন ফাইলগুলো group উত্তরাধিকার সূত্রে পায়। কোনো application 0600 চাইলে private file তৈরি করবে। Default ACL থাকলে creation permission নির্ধারণের পদ্ধতি পরিবর্তিত হয়।

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