Ubuntu 24.04 पर Docker Compose कैसे सेटअप करें
Ubuntu 24.04 पर Docker Engine और Compose plugin इंस्टॉल करने का तरीका जानें। इस गाइड में ufw पोर्ट बायपास समस्या, डेटाबेस बैकअप और दो-सर्विस compose.yml फाइल बनाने की पूरी जानकारी है।
आप क्या बना रहे हैं
Docker Compose इस साइट पर मौजूद लगभग हर चीज़ का आधार है। Nextcloud, Vaultwarden, n8n, Immich, Rocket.Chat, इन सभी गाइड्स की शुरुआत "यह compose file लिखें" से होती है, और यह पेज बताता है कि उस फाइल का वास्तव में क्या अर्थ है। आप Ubuntu 24.04 पर Docker के आधिकारिक apt repository से Docker Engine और Compose plugin इंस्टॉल करेंगे, फिर दो-सर्विस वाला एक वास्तविक स्टैक खड़ा करेंगे: Miniflux (एक छोटा RSS reader) और PostgreSQL। यह जोड़ी उन सभी पैटर्न्स का अभ्यास कराती है जिनका उपयोग बड़े ऐप्स करते हैं: pinned images, healthcheck के साथ एक डेटाबेस, एक named volume, .env फाइल में secrets, और केवल localhost पर पब्लिश किया गया पोर्ट।
इंस्टॉलेशन में पांच मिनट लगते हैं। इस गाइड का बाकी हिस्सा उन समस्याओं को कवर करता है जो बाद में परेशानी का कारण बनती हैं: docker group का root के समान होना, पब्लिश किए गए पोर्ट्स का सीधे आपके ufw रूल्स को बायपास कर देना, और docker compose down पर मौजूद वह एक फ्लैग जो बिना किसी पुष्टि के आपके डेटाबेस को डिलीट कर देता है।
आवश्यकताएँ: एक नया Ubuntu 24.04 KVM VPS, sudo एक्सेस वाला एक यूजर, और एक गीगाबाइट या उससे अधिक RAM। यदि Docker पहले से इंस्टॉल है तो भी ठीक है, पहला सेक्शन यह बताता है कि क्या हटाना है।
Ubuntu के repo के बजाय Docker के repo से install करें
पहला command चलाने से पहले दो गलत रास्तों से बचें। Ubuntu का अपना docker.io package काम तो करता है, लेकिन यह Docker के releases से पीछे रहता है और उस plugin layout को मिस कर देता है जिसकी बाकी सब उम्मीद करते हैं। और hyphen वाला docker-compose command वह रास्ता है जिस पर पुराने tutorials आपको भेजते हैं। पुराने सर्वर पर वह command आमतौर पर Compose v1 होता है, जो Python में लिखा गया है, जिसे Docker ने end of life घोषित कर दिया है, और यही कारण है कि वे tutorials काम नहीं करते। Docker अभी भी आज के Go code से बना एक standalone docker-compose binary प्रकाशित करता है, लेकिन उसका अपना install page उस तरीके को 'not recommended' बताता है और वह केवल backward compatibility के लिए समर्थित है। आज का Compose docker compose है (बीच में space के साथ), जो एक CLI plugin है और उसी repository से install होता है जहाँ से engine होता है।
यदि इनमें से कुछ भी पहले से सर्वर पर है, तो उसे पहले हटा दें, जिसमें docker-compose-v2 और docker-buildx (plugins के Ubuntu के अपने packages) भी शामिल हैं, ताकि सब कुछ एक ही repository से आए:
sudo apt remove -y docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runcPackage 'docker.io' is not installed, so not removed एक नए VPS पर सामान्य output है। फिर Docker की repository जोड़ें और install करें:
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginतीनों layers को verify करें:
docker --version
docker compose version
sudo docker run --rm hello-worldपहले दो version strings print करते हैं, Docker Compose version v5.x.x पुष्टि करता है कि आपके पास plugin है, न कि पुराना v1 binary। यह plugin दिसंबर 2025 में v2 से सीधे v5 पर आ गया, ताकि पुराने compose file format versions के साथ भ्रम से बचा जा सके, इसलिए जो guides यहाँ v2.x.x दिखाती हैं, वे एक ही tool का वर्णन कर रही हैं। hello-world run का अंत Hello from Docker! के साथ होना चाहिए। यह package boot पर service को enable कर देता है; systemctl is-enabled docker, enabled print करता है।
docker group root है, इसे समझदारी से चुनें
अभी हर docker कमांड के लिए sudo की आवश्यकता होती है, क्योंकि /var/run/docker.sock पर स्थित डेमन का सॉकेट root और docker ग्रुप के स्वामित्व में होता है। ग्रुप की सदस्यता के बिना आपको Docker की सबसे अधिक सर्च की जाने वाली त्रुटि मिलती है:
permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sockइसका मानक समाधान:
sudo usermod -aG docker $USERग्रुप की सदस्यता लॉगिन के समय लागू होती है, इसलिए आपके वर्तमान शेल में त्रुटि बनी रहेगी। इस सत्र के लिए newgrp docker चलाएं, या लॉग आउट करके पुनः लॉग इन करें; इसके बाद id को आपके ग्रुप्स में docker दिखाना चाहिए।
अब ईमानदारी वाली बात, जिसे स्पष्ट रूप से कहा गया है: docker ग्रुप की सदस्यता होस्ट पर root के बराबर है। यह "root जैसा" या "elevated" नहीं है, यह पूर्ण root है। इस ग्रुप का कोई भी सदस्य docker run --rm -it -v /:/host alpine chroot /host चला सकता है और पूरे फाइलसिस्टम का मालिक बन सकता है, बिना किसी पासवर्ड के। यह ग्रुप सुविधा के लिए मौजूद है, सुरक्षा के लिए नहीं।
Docker का rootless मोड एक वास्तविक विकल्प है, जहाँ डेमन स्वयं आपके unprivileged यूजर के रूप में चलता है। इसकी अपनी सीमाएं हैं: 1024 से नीचे के पोर्ट्स के लिए अतिरिक्त सेटअप की आवश्यकता होती है, नेटवर्किंग एक userspace shim के माध्यम से चलती है जिसमें मापने योग्य ओवरहेड होता है, और कुछ इमेजेज वास्तविक root के बिना ठीक से काम नहीं करती हैं। एक सिंगल-एडमिन VPS पर जहाँ एकमात्र लॉगिन के पास पहले से ही sudo है, यह ग्रुप बदलाव व्यवहार में कुछ भी नहीं बदलता है, और यहाँ दिए गए सभी गाइड इसी को मानकर चलते हैं। बस इसे कभी भी sudo से कम न समझें।
Compose file की संरचना
प्रत्येक stack को अपनी एक अलग directory दें। directory का नाम ही project का नाम बन जाता है, जो containers, networks और volumes के लिए prefix का काम करता है:
sudo mkdir -p /opt/miniflux && sudo chown $USER /opt/miniflux && cd /opt/minifluxcompose.yml का उपयोग करें (यह आधुनिक नाम है; docker-compose.yml अभी भी काम करता है)। पुराने version: key को छोड़ दें, यह अब obsolete है और Compose इसे देखते ही चेतावनी देता है।
services:
miniflux:
image: miniflux/miniflux:2.2.9
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
environment:
- DATABASE_URL=postgres://miniflux:${POSTGRES_PASSWORD}@db/miniflux?sslmode=disable
- RUN_MIGRATIONS=1
- CREATE_ADMIN=1
- ADMIN_USERNAME=admin
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
- POSTGRES_USER=miniflux
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=miniflux
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "miniflux", "-d", "miniflux"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:ऊपर दी गई हर पंक्ति एक निर्णय है। इन्हें एक-एक करके समझें।
Image versions को पिन करें, :latest और pull का उपयोग करना unattended upgrade जैसा है
postgres:16-alpine का उपयोग करें, न कि postgres:latest का। एक tag स्थिर नहीं होता: :latest हर बार pull करने पर उस image को फिर से resolve करता है जिसे maintainer ने सबसे हाल ही में push किया है। इसे उस routine upgrade आदत के साथ जोड़ें जिसे आप सीखने वाले हैं, docker compose pull && docker compose up -d, तो :latest का मतलब है कि major-version के बदलाव तब लागू हो जाएंगे जब upstream उन्हें जारी करेगा, न कि तब जब आप चाहेंगे। PostgreSQL के साथ यह केवल एक संभावना नहीं है: 16 से 17 पर अचानक jump होने से container crash-loop में चला जाता है क्योंकि data directory incompatible हो जाती है। Postgres के major upgrades के लिए restart नहीं, बल्कि dump और restore की आवश्यकता होती है।
कम से कम major version को पिन करें (postgres:16-alpine, 16.x patch releases के लिए है), और applications को किसी सटीक release जैसे miniflux/miniflux:2.2.9 पर पिन करें। project के releases page को देखें और file लिखते समय जो भी current हो, उसका उपयोग करें। इसके बाद upgrade करना आपके द्वारा जानबूझकर किया गया एक-पंक्ति का बदलाव बन जाता है, जो git diff में दिखाई देता है।
127.0.0.1 पर publish करें, क्योंकि Docker ufw को दरकिनार कर देता है
"127.0.0.1:8080:8080", host address, host port, container port। अधिकांश tutorials "8080:8080" लिखते हैं, जो 0.0.0.0:8080:8080 का shorthand है: यानी हर interface पर सुनना, public interface भी शामिल है।
यही वह trap है, और यह लगभग हर किसी को एक बार फंसाता है। Docker एक port को DNAT rule लिखकर publish करता है जो packet के destination को filtering से पहले container के internal IP में बदल देता है। इसलिए packet FORWARD path लेता है और कभी भी INPUT तक नहीं पहुँचता, जहाँ आपके ufw rules मौजूद होते हैं। sudo ufw deny 8080 सफलता की रिपोर्ट देता है, ufw status दिखाता है कि port denied है, और service फिर भी पूरी internet को जवाब दे रही होती है। आपका firewall खराब नहीं है; इसे design के अनुसार ही bypass किया जा रहा है। Docker ufw को क्यों bypass करता है, और container traffic को वास्तव में कैसे filter करें इस प्रक्रिया को विस्तार से समझाता है और उन ports के लिए DOCKER-USER समाधान बताता है जिन्हें public रहना आवश्यक है।
वह आदत जो इस पूरी समस्या को खत्म कर देती है: जब तक कोई विशेष कारण न हो, published ports को 127.0.0.1 पर bind करें, और जो कुछ भी दुनिया के सामने होना चाहिए उसके लिए सामने एक reverse proxy रखें। यही वह चीज़ है जिसे Traefik reverse proxy guide इस page के बाद अगले चरण के रूप में तैयार करती है। यह एक ऐसा container है जो ports 80 और 443 को संभालता है और TLS के साथ hostname के आधार पर बाकी सब कुछ route करता है। (पुराने Traefik v2 setup से आ रहे हैं? Traefik v2 to v3 migration guide में नाम बदलने और नियमों में बदलाव की जानकारी दी गई है।)
stack शुरू करने के बाद bind को verify करें: 127.0.0.1:8080 दिखना चाहिए, न कि 0.0.0.0:8080 या *:8080, जैसा कि sudo ss -tlnp | grep 8080 में दिखाया गया है।
Named volumes बनाम bind mounts
db-data:/var/lib/postgresql/data एक named volume है: Docker /var/lib/docker/volumes/ के अंतर्गत एक directory बनाता और manage करता है और उसे container में mount करता है। इसका विकल्प bind mount है, ./data:/var/lib/postgresql/data, जो host पर आपके द्वारा चुनी गई path को map करता है।
वह विभाजन जो व्यवहार में काम आता है: केवल उन containers के data के लिए named volumes का उपयोग करें जिन्हें containers ही छूते हैं, विशेषकर databases के लिए, क्योंकि Docker volume को उस ownership के साथ initialize करता है जिसकी image को आवश्यकता होती है और file permissions अपने आप सही काम करते हैं। उन files के लिए bind mounts का उपयोग करें जिन्हें आप host से छूते हैं, जैसे कि config files जिन्हें आप text editor से edit करते हैं, या media library जिसे आप rsync करते हैं, या ऐसी कोई भी चीज़ जिसका path आप स्पष्ट रखना चाहते हैं। bind-mount की क्लासिक विफलता ownership है: image अपनी process को एक fixed UID के रूप में चलाती है (Miniflux image UID 65534 के रूप में चलती है, postgres:16-alpine UID 70 पर drop हो जाता है), आपकी host directory का owner UID 1000 है, और app startup पर logs में permission denied के साथ मर जाती है। Named volumes इस तरह की बग को काफी हद तक खत्म कर देते हैं, बस इसकी कीमत यह है कि data Docker-managed path पर रहता है, जिसे नीचे समझाया गया है।
environment और .env, secrets को git से बाहर रखें
Compose ${POSTGRES_PASSWORD} को compose.yml के बगल में स्थित .env नामक file से भरता है, लेकिन केवल तभी जब आपका shell पहले से उस variable को define न करता हो: आपके shell environment में export की गई value .env file की value पर भारी पड़ती है। इसलिए, किसी पुराने प्रयोग से बची हुई कोई भूली-बिसरी export POSTGRES_PASSWORD=... चुपचाप file को override कर देती है, और docker compose config (नीचे) दिखाता है कि कौन सी value जीती। file बनाएँ:
cat > .env <<'EOF'
POSTGRES_PASSWORD=change-me-to-something-long
ADMIN_PASSWORD=change-me-too
EOF
chmod 600 .env
echo ".env" >> .gitignoreopenssl rand -hex 24 के साथ वास्तविक values generate करें। जानबूझकर Hex का उपयोग करें, न कि base64 का: यह password DATABASE_URL connection string के अंदर जाता है, और base64 द्वारा उत्पन्न /, +, और = characters URL parsing को तोड़ देते हैं। यह एक ऐसी विफलता है जो syntax error के बजाय authentication error के रूप में सामने आती है और एक पूरी शाम बर्बाद कर देती है। .gitignore line को पहले commit से पहले डालें: compose file को publish और version करना सुरक्षित है, .env file कभी भी सुरक्षित नहीं होती, और जो secret git history में चला गया, वह secret ऐसा है जिसे आपको rotate करना ही होगा। यदि आप किसी missing variable के साथ stack शुरू करते हैं, तो Compose जोर से चेतावनी देता है और empty string के साथ जारी रहता है, जिसका Postgres password के लिए मतलब है एक broken deployment:
WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string.docker compose config पूरी तरह से interpolated file को print करता है, यह जांचने का सबसे तेज़ तरीका है कि containers को वास्तव में क्या प्राप्त होगा; याद रखें कि इसके output में आपके secrets शामिल होते हैं।
depends_on किसी चीज़ का इंतज़ार नहीं करता, जब तक आप healthcheck न जोड़ें
एक साधारण depends_on: [db] केवल start order को नियंत्रित करता है: Compose पहले Postgres को launch करता है और उसके कुछ क्षण बाद app को, जबकि Postgres को connections स्वीकार करने में अभी भी कुछ सेकंड बाकी होते हैं। app database को hit करती है, विफल हो जाती है, और crash हो जाती है या फिर retry करती है, यह इस पर निर्भर करता है कि उसे कितनी अच्छी तरह लिखा गया है।
विश्वसनीय संस्करण वही है जिसका उपयोग ऊपर दी गई file में किया गया है: db service एक healthcheck को define करती है (Postgres ठीक इसी के लिए pg_isready प्रदान करता है), और app condition: service_healthy के साथ depends_on घोषित करती है। Compose database शुरू करता है, हर 10 सेकंड में check को poll करता है, और Miniflux को तभी शुरू करता है जब check पास हो जाता है। यदि database कभी healthy नहीं होता (गलत password, corrupt volume), तो app कभी शुरू नहीं होती और Compose आपको बताता है कि कौन सी dependency विफल रही:
dependency failed to start: container miniflux-db-1 is unhealthyवह संदेश आपको docker compose logs db की ओर इशारा करता है, जहाँ वास्तविक error मौजूद होती है।
restart: unless-stopped
दोनों services पर restart: unless-stopped का मतलब है कि containers crash के बाद और VPS reboot के बाद वापस आ जाते हैं, लेकिन यदि आपने जानबूझकर docker compose stop चलाया है तो वे down ही रहते हैं। विकल्प always manual stop के बाद भी containers को पुनर्जीवित कर देता है, जिसका मतलब शायद ही कभी आपका इरादा होता है। बिना restart policy के, सुबह 4 बजे kernel-update reboot चुपचाप आपकी services को तब तक down कर देता है जब तक आप उस पर ध्यान नहीं देते।
दैनिक क्रियाएं
दैनिक कार्यों के लिए केवल पांच commands हैं, जिन्हें project directory से चलाया जाता है।
docker compose up -d # create and start; idempotent, recreates only what changed
docker compose ps # status, ports, and health of this project's containers
docker compose logs -f miniflux # follow one service's logs; --tail 100 for recent history
docker compose pull && docker compose up -d # upgrade to the pinned tags
docker compose down # stop and remove containers and the networkup -d को बार-बार चलाना सुरक्षित है। यह file की तुलना वर्तमान स्थिति से करता है और केवल उन्हीं services को प्रभावित करता है जिनकी config या image बदली है। upgrade pair उन tags को fetch करता है जिन पर आपने पिन किया है: postgres:16-alpine के तहत patch releases, और exact pin के लिए तब तक कुछ नहीं होता जब तक आप उसे edit न करें, जो कि इसका मुख्य उद्देश्य है। upgrades के बाद पुरानी images जमा हो जाती हैं; डिस्क स्पेस खाली करने के लिए docker image prune -f का उपयोग करें।
अब विनाशकारी command की बात, जिसे ध्यान से समझें: docker compose down चलाना सुरक्षित है, containers और network को कभी भी हटाया जा सकता है, और आपका डेटा volume में सुरक्षित रहता है। docker compose down -v named volumes को भी हटा देता है। इसका मतलब है कि आपका database तुरंत नष्ट हो जाएगा, बिना किसी पुष्टि या undo के। -v flag का अस्तित्व प्रयोगों को मिटाने के लिए है; वास्तविक डेटा वाले stack पर, इसे वैसे ही समझें जैसे आप rm -rf को समझते हैं। /var/lib/docker/volumes/ में कोई trash can नहीं होता है।
चल रहे container के अंदर एक बार shell access पाने के लिए: docker compose exec db psql -U miniflux आपको database में ले जाता है, और docker compose exec miniflux sh आपको app में shell प्रदान करता है।
आपका डेटा वास्तव में कहाँ रहता है
Named volumes को project prefix मिलता है, इसलिए db-data जो miniflux नामक directory में है, वह miniflux_db-data बन जाता है:
docker volume ls
docker volume inspect miniflux_db-datainspect के output में वह line शामिल होती है जो महत्वपूर्ण है:
"Mountpoint": "/var/lib/docker/volumes/miniflux_db-data/_data"वह directory database है, जो host filesystem पर root-owned है, और यह down, upgrades, और container rebuilds के बाद भी सुरक्षित रहती है। यही वह डेटा है जिसे आपके backups में अनिवार्य रूप से शामिल किया जाना चाहिए।
Named volume का बैकअप लेना
इसका मानक तरीका एक अस्थायी container का उपयोग करना है, जो volume को read-only मोड में host directory के साथ mount करता है और tar का उपयोग करके डेटा कॉपी करता है:
docker run --rm \
-v miniflux_db-data:/data:ro \
-v "$PWD":/backup \
alpine:3.22 tar czf /backup/miniflux-db-$(date +%F).tar.gz -C /data .इसमें किसी इंस्टॉलेशन की आवश्यकता नहीं होती, कुछ भी बैकग्राउंड में नहीं चलता, और restore की प्रक्रिया इसका बिल्कुल उल्टा है, जहाँ tar xzf का उपयोग करके एक नए खाली volume में mounts को उलट दिया जाता है।
डेटाबेस के लिए एक सावधानी: एक चलते हुए Postgres डेटा डायरेक्टरी का tar लेने से वह स्थिति कैप्चर हो सकती है जो लिखते समय बीच में हो, जिससे डेटाबेस बाद में सही ढंग से start नहीं होगा। या तो tar के दौरान कुछ सेकंड के लिए docker compose stop का उपयोग करें, या बेहतर होगा कि एक logical dump लें, जो अपनी संरचना के कारण हमेशा consistent रहता है:
docker compose exec -T db pg_dump -U miniflux miniflux | gzip > miniflux-$(date +%F).sql.gz-T उस pseudo-terminal को अक्षम कर देता है जिसे Compose डिफ़ॉल्ट रूप से allocate करता है, क्योंकि dump आउटपुट को TTY के माध्यम से पाइप करने से वह corrupt हो सकता है। इनमें से किसी एक कमांड को cron में डालें और परिणाम को VPS से बाहर कॉपी करें; जिस डिस्क पर डेटा है उसी पर बैकअप रखना केवल एक कॉपी है, वास्तविक बैकअप नहीं। Nextcloud guide ठीक इन्हीं दो पैटर्न्स के आधार पर एक पूर्ण निर्धारित रूटीन तैयार करता है।
विफलता के प्रकार और उनसे संबंधित संदेश
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock, आप अभी तक docker group में शामिल नहीं हैं, या आप शामिल तो हैं लेकिन आपका वर्तमान session उससे पुराना है। id आपके प्रभावी groups को दिखाता है; newgrp docker वर्तमान shell को ठीक कर देता है, जबकि logout करके फिर से login करने से सभी sessions ठीक हो जाते हैं।
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?, यह एक अलग समस्या है: daemon ही बंद है। sudo systemctl status docker और sudo journalctl -u docker -n 50 इसका कारण बताते हैं। VPS पर इसका सबसे आम कारण disk का भर जाना है, इसलिए पहले df -h /var/lib/docker चलाएं।
Bind for 127.0.0.1:8080 failed: port is already allocated, किसी अन्य container ने पहले ही उस host port को publish कर दिया है। docker ps दिखाता है कि वह कौन सा है; आमतौर पर इसका कारण कुछ docker run सप्ताह पहले का कोई पुराना container होता है। यदि docker ps खाली है, तो कोई non-Docker process उस port का उपयोग कर रही है: sudo ss -tlnp | grep 8080 उसका नाम बता देगा।
yaml: line 14: did not find expected key, यह निर्दिष्ट line या उसके ठीक ऊपर एक indentation त्रुटि है। Compose files YAML होती हैं: इसमें दो-space का indentation अनिवार्य है, केवल spaces का उपयोग करें, और tab character का कहीं भी होना घातक है। docker compose config बिना कुछ शुरू किए file को validate करता है, और हर बदलाव के बाद इसे चलाना एक अच्छी आदत है।
ufw surprise कोई त्रुटि नहीं दिखाता है, जो इसे खतरनाक बनाता है: deployment सफल हो जाता है, ufw status सही दिखता है, और बाहर से port scan करने पर भी आपका database मिल जाता है। ऊपर दिए गए ports section को फिर से पढ़ें, हर ports: entry में missing 127.0.0.1: prefix की जाँच करें, और किसी दूसरे machine से curl http://your-vps-ip:8080 के साथ पुष्टि करें; connection refused ही वह उत्तर है जो आप चाहते हैं।
यहाँ से, Traefik guide इस single stack को एक HTTPS entry point के पीछे कई apps में बदल देता है, और what's worth self-hosting in 2026 वह सूची है जिसे आप चला सकते हैं। जब ऐसे कई stacks चल रहे हों और प्रत्येक का अपना login form हो, तो a self-hosted SSO server like Authentik उन्हें उसी proxy के पीछे एक ही account में समेट देता है।
VPS पर Minecraft server जैसा game server अभ्यास के लिए एक अच्छा पहला Compose project है। यदि आप ऐसी चीज़ से सीखना चाहते हैं जिसे रोज़ खोलते हैं, तो openGym, self-hosted workout tracker एक छोटा stack है, जो image tag के बजाय git tag पर pinned है। पहला passkey register करने से पहले इसके सामने TLS होना चाहिए। Photos आम तौर पर पहली ऐसी चीज़ होती हैं जिसे लोग किसी और के cloud से वापस लाना चाहते हैं। PhotoPrism और Immich की तुलना करने से यह तय करने में मदद मिलती है कि न्यूनतम कितनी RAM चाहिए और किस backup routine के लिए आप सहमत हो रहे हैं, इससे पहले कि आप इनमें से किसी के लिए volume निर्धारित करें। जब दो services पर्याप्त नहीं लगतीं, तो AFFiNE को Notion-style workspace के रूप में स्थापित करना चार containers में उन्हीं patterns को लागू करता है। यह जाँचने का अच्छा तरीका भी है कि ऊपर बताए गए pinned tags, healthchecks और named volumes अब आपकी आदत बन चुके हैं या नहीं।
FAQ
मुझे "permission denied while trying to connect to the Docker daemon socket" क्यों मिलता है?
आपका user docker group में नहीं है, या उसे वर्तमान session शुरू होने के बाद जोड़ा गया था; membership केवल login के समय लागू होती है। sudo usermod -aG docker $USER चलाएँ, फिर newgrp docker करें या log out करके वापस log in करें, और id के साथ पुष्टि करें। यह group host का root-equivalent access देता है, इसलिए केवल उन्हीं users को जोड़ें जिन्हें आप sudo देना चाहेंगे।
क्या docker compose down मेरा data delete कर देता है?
साधारण docker compose down ऐसा नहीं करता है, यह केवल containers और project network को हटाता है; named volumes सुरक्षित रहते हैं और अगला up -d उन्हें फिर से attach कर देता है। docker compose down -v विनाशकारी तरीका है: यह named volumes को delete कर देता है, जिसका अर्थ है कि आपका database बिना किसी पुष्टि या undo के हट जाएगा। कभी भी real data वाले stack पर -v न चलाएँ जब तक कि आपके पास verified backup न हो।
docker-compose और docker compose में क्या अंतर है?
docker-compose (hyphen) Compose को call करने का पुराना तरीका है। पुराने सर्वर पर यह आमतौर पर Compose v1 होता है, जो मूल Python version है जिसे Docker ने end of life घोषित कर दिया है। Docker अभी भी वर्तमान Go code से बना एक standalone docker-compose binary प्रकाशित करता है, लेकिन उस install को 'not recommended' बताता है और वह केवल backward compatibility के लिए समर्थित है, इसलिए नए सर्वर पर इसे न चुनें। docker compose (space) वर्तमान Compose है, जो v2 के बाद का है और दिसंबर 2025 से v5 के रूप में numbered है। यह Docker CLI के लिए एक Go plugin है, जिसे Docker के apt repository से docker-compose-plugin के रूप में install किया जाता है। Commands और YAML लगभग पूरी तरह से compatible हैं, इसलिए जब कोई पुराना tutorial docker-compose up कहे, तो docker compose up टाइप करें।
ufw द्वारा port block होने के बावजूद मैं internet से अपने Docker container तक क्यों पहुँच सकता हूँ?
क्योंकि Docker, iptables की PREROUTING chain में DNAT rules के साथ ports publish करता है, और rewrite किए गए packets Docker की अपनी chains के माध्यम से FORWARD path पर चलते हैं, वे कभी भी INPUT chain तक नहीं पहुँचते जहाँ ufw के rules लागू होते हैं। इसलिए ufw deny 8080 का published container port पर कोई असर नहीं पड़ता। इसे source पर ठीक करें: 127.0.0.1: पर publish करें और reverse proxy के माध्यम से services को expose करें।
क्या मुझे named volume का उपयोग करना चाहिए या bind mount का?
Named volumes का उपयोग केवल उन data के लिए करें जिन्हें केवल container ही access करता है, विशेष रूप से databases के लिए, क्योंकि Docker वही ownership set करता है जिसकी image को उम्मीद होती है और permissions अपने आप काम करती हैं। Bind mounts का उपयोग उन files के लिए करें जिन्हें आप host से भी manage करते हैं: जैसे configs जिन्हें आप edit करते हैं, media जिसे आप upload करते हैं, या कोई भी ऐसी चीज़ जिसका path आप स्पष्ट रखना चाहते हैं। यदि कोई container bind mount पर permission denied के साथ start होने में विफल रहता है, तो host-vs-container UID mismatch सबसे पहली चीज़ है जिसे जाँचें।