ব্লগে ফিরে যান
আগস্ট 19, 2026গাইড

VPS-এ Docker Compose দিয়ে অ্যাপ্লিকেশন কীভাবে ডিপ্লয় করবেন

Ubuntu-তে Docker Compose v2-এর ব্যবহারিক উৎপাদন গাইড: ইঞ্জিন ইনস্টল করুন, নেটওয়ার্ক ও ভলিউমসহ Compose ফাইল লিখুন, সিক্রেট সামলান, সামনে রিভার্স প্রক্সি রাখুন, আতঙ্কহীন রোলআউটে আপডেট করুন এবং নামযুক্ত ভলিউম ব্যাকআপ করুন।

VPS-এ Docker Compose দিয়ে অ্যাপ্লিকেশন কীভাবে ডিপ্লয় করবেন

Docker Compose এক VPS-এ ছোট স্ট্যাক চালানোর সাধারণ উপায়: ওয়েব অ্যাপ, ডেটাবেস, Redis ক্যাশ এবং রিভার্স প্রক্সি, এক YAML ফাইলে। এটা Kubernetes নয়। মাল্টি-নোড ফেলওভার পাবেন না। নতুন Hiddence VPS-এ মিনিটে পুনরায় তৈরি করতে পারেন এমন পুনরাবৃত্তিযোগ্য, পর্যালোচনাযোগ্য সেটআপ পাবেন — বেশিরভাগ সাইড প্রজেক্ট ও ছোট পণ্যের ঠিক তাই দরকার।

এই নিবন্ধ ধরে নেয় শুক্রবার রাতের docker run-এর চেয়ে উৎপাদনের কাছাকাছি কিছু চান। আমরা Docker Engine ও Compose প্লাগইন ইনস্টল করব, অ-root ডিপ্লয় ব্যবহারকারী তৈরি করব, হেলথচেক ও রিস্টার্ট নীতিসহ Compose ফাইল লিখব, সিক্রেট Git-এর বাইরে রাখব, ইন্টারনেটে শুধু রিভার্স-প্রক্সি পোর্ট প্রকাশ করব, এবং আপডেট ও ব্যাকআপ রুটিন সংজ্ঞায়িত করব। উদাহরণ স্ট্যাক সাধারণ ওয়েব অ্যাপ প্লাস PostgreSQL প্লাস Caddy, কিন্তু একই প্যাটার্ন Node, PHP, Python বা একদল ওয়ার্কারের জন্য কাজ করে।

এক VPS-এ Compose এখনও কেন অর্থবহ

মানুষ ফ্যাশনের জন্য Kubernetes-এ লাফায়, তারপর এক ওয়েবসাইটের জন্য সপ্তাহান্ত YAML-এ কাটায়। Compose পঠনযোগ্য থাকে। ফাইল ভার্সন করেন, এনভায়রনমেন্ট ভেরিয়েবল নথিভুক্ত করেন, এবং প্রয়োগের আগে পরিবর্তন ডিফ করতে পারেন। আইসোলেশন যথেষ্ট: নেটওয়ার্ক ও ন্যূনতম-অধিকার ব্যবহারকারী ব্যবহার করলে আপসহীন অ্যাপ কন্টেইনার ডেটাবেস UNIX সকেট ধরে রাখবে না। রিসোর্স সীমা এক মেমরি লিক পুরো VPS জমাট বাঁধতে দেয় না।

  • এক ফাইল পুরো স্ট্যাক বর্ণনা করে
  • নামযুক্ত ভলিউম কন্টেইনার পুনর্নির্মাণ থেকে বেঁচে থাকে
  • অভ্যন্তরীণ Docker নেটওয়ার্ক Postgres-কে পাবলিক ইন্টারনেট থেকে দূরে রাখে
  • restart: unless-stopped বেশিরভাগ রিবুট কভার করে
  • প্রথমটি ছাড়িয়ে গেলে দ্বিতীয় VPS-এ কপি করা সহজ

প্রয়োজনীয়তা

অ্যাপ প্লাস Postgres-এর জন্য যথেষ্ট RAM-সহ VPS ব্যবহার করুন। অ্যাপ + ডেটাবেস + প্রক্সির জন্য বাস্তবসম্মত ন্যূনতম 2 GB প্লান। Ubuntu 24.04 ধরা হয়েছে। cgroups-এ কী করে না পড়ে এলোমেলো Snap থেকে Docker ইনস্টল করবেন না; নিচের ধাপ Docker-এর অফিসিয়াল apt রিপোজিটরি ব্যবহার করে।

  • Ubuntu 22.04/24.04, root বা sudo
  • 2 GB RAM সুপারিশকৃত (Postgres ছাড়া খুব ছোট স্ট্যাকের জন্য শুধু 1 GB)
  • স্বয়ংক্রিয় HTTPS চাইলে VPS-এ নির্দেশকারী ডোমেইন
  • সার্ভারে প্রজেক্ট কপি করার উপায়: Git বা অন্য

ধাপ ১: Docker Engine ও Compose v2 ইনস্টল করুন

Compose v2 প্লাগইন যা docker compose (স্পেসসহ) হিসেবে ডাকা হয়, পুরনো docker-compose Python বাইনারি নয়। বর্তমান নিরাপত্তা প্যাচ পেতে দুটোই Docker-এর রিপোজিটরি থেকে ইনস্টল করুন।

bash
ssh root@YOUR_VPS_IP
apt update && apt -y install ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
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" | tee /etc/apt/sources.list.d/docker.list > /dev/null

apt update
apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

docker version
docker compose version

ধাপ ২: ডিপ্লয় ব্যবহারকারী ও ডিরেক্টরি লেআউট

Compose root হিসেবে চালানো কাজ করে, কিন্তু docker গ্রুপের সদস্যপদসহ নিবেদিত ব্যবহারকারী পরিষ্কার। প্রজেক্ট /root-এ নয় /opt বা /srv-এ রাখুন যাতে ব্যাকআপ ও অনুমতি স্পষ্ট হয়। .env থাকা ডিরেক্টরি কখনো বিশ্ব-লেখযোগ্য করবেন না।

bash
adduser --disabled-password --gecos '' deploy
usermod -aG docker deploy
mkdir -p /srv/app
chown deploy:deploy /srv/app
chmod 750 /srv/app

# Log in as deploy for the rest of the file editing:
# su - deploy
# cd /srv/app

ধাপ ৩: উৎপাদন-মনস্ক Compose ফাইল লিখুন

নিচের ফাইল টেমপ্লেট। অ্যাপ ইমেজ নিজের দিয়ে বদলান। Postgres 0.0.0.0:5432-এ প্রকাশিত হয় না — শুধু Caddy 80 ও 443-এ প্রকাশিত। হেলথচেক রিভার্স প্রক্সিকে এখনও ডেটাবেস মাইগ্রেট করা অ্যাপে ট্রাফিক পাঠাতে বাধা দেয়। ইমেজ ট্যাগ পিন করুন; latest চমক ভাঙার উপায়।

bash
# /srv/app/compose.yaml
services:
  caddy:
    image: caddy:2.8-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      app:
        condition: service_healthy

  app:
    image: ghcr.io/example/webapp:1.4.2
    restart: unless-stopped
    env_file: .env
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8000/health"]
      interval: 10s
      timeout: 3s
      retries: 10
    networks:
      - frontend
      - backend

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    env_file: .env
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 10
    networks:
      - backend

networks:
  frontend: {}
  backend: {}

volumes:
  pgdata:
  caddy_data:
  caddy_config:

ধাপ ৪: সিক্রেট, .env ও Caddyfile

পাসওয়ার্ড সার্ভারের .env-এ রাখুন, chmod 600 করুন, এবং সেই ফাইল কখনো কমিট করবেন না। পাসওয়ার্ড openssl rand -base64 32 দিয়ে জেনারেট করুন। Caddyfile-কে শুধু Docker নেটওয়ার্কে অ্যাপ সার্ভিস নামে রিভার্স প্রক্সি করতে হয়।

bash
# /srv/app/.env (permissions 600)
POSTGRES_USER=app
POSTGRES_PASSWORD=change-me-long-random
POSTGRES_DB=app
# plus any APP_SECRET / NEXTAUTH_SECRET your image needs

# /srv/app/Caddyfile
app.example.com {
    encode gzip
    reverse_proxy app:8000
}

chmod 600 /srv/app/.env
cd /srv/app
docker compose up -d
docker compose ps
docker compose logs -f --tail=100

ধাপ ৫: ফায়ারওয়াল, লগ ও রিসোর্স সীমা

UFW শুধু 22, 80 ও 443 অনুমতি দেবে। Docker কখনো প্রকাশিত পোর্টের জন্য UFW বাইপাস করে; কঠোর হোস্ট ফায়ারওয়াল লাগলে আপনার Ubuntu সংস্করণের বর্তমান Docker + UFW মিথস্ক্রিয়া দেখুন বা পোর্ট শুধু 127.0.0.1-এ প্রকাশ করে সামনে হোস্ট Caddy রাখুন। Postgres VPS না খেয়ে ফেলুক বলে Compose-এ মেমরি সীমা সেট করুন।

bash
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

# Optional in compose.yaml under app or db:
#    deploy:
#      resources:
#        limits:
#          memory: 512M

# Logs (do not let json-file grow forever):
# { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }
# in /etc/docker/daemon.json then: systemctl restart docker

ধাপ ৬: আপডেট ও রোলব্যাক

যে বিরক্তিকর আপডেট কাজ করে: নতুন ইমেজ পুল করুন, up -d, হেলথচেক দেখুন, ফিরে পিন করতে আগের ট্যাগ git-এ রাখুন। ট্রাফিক থামানোর ইচ্ছা না থাকলে উৎপাদন ডেটাবেসে docker compose down করবেন না। down -v ভলিউম মুছে দেয় — এটা ওয়াইপ, রিস্টার্ট নয়।

bash
cd /srv/app
git pull   # if the Compose file lives in git

# Change the image tag in compose.yaml, then:
docker compose pull
docker compose up -d
docker compose ps

# Rollback: set the old tag, pull, up -d again
# NEVER: docker compose down -v   # this deletes named volumes

নামযুক্ত ভলিউম ব্যাকআপ করুন

VPS স্ন্যাপশট ভালো। অন্য মেশিনে পুনরুদ্ধার লাগলে লজিক্যাল Postgres ডাম্প ভালো। cron দিয়ে শিডিউল করুন। একবার পুনরুদ্ধার পরীক্ষা করুন, নাহলে ব্যাকআপ নেই — ফাইল আছে যা ব্যাকআপ বলে আশা করেন।

bash
# Postgres dump while the db container is running:
docker compose exec -T db pg_dump -U app app | gzip > /var/backups/app-$(date +%F).sql.gz

# Copy off-box
# scp /var/backups/app-*.sql.gz backup-host:~

# Restore sketch (maintenance window):
# gunzip -c app-2026-08-19.sql.gz | docker compose exec -T db psql -U app app

সমস্যা সমাধান

docker compose ps ও docker compose logs service পড়ুন। ইমেজ পুল ব্যর্থতা সাধারণত ghcr/docker hub রেট লিমিট বা লগইন ছাড়া প্রাইভেট ইমেজ। Caddy থেকে 502 মানে অ্যাপ সুস্থ নয় বা প্রক্সি হোস্টনেম ভুল (Caddy কন্টেইনারের ভিতর থেকে localhost নয় Compose সার্ভিস নাম ব্যবহার করুন)। ভলিউমে অনুমতি ত্রুটি প্রায়ই মানে ইমেজ uid 1000 হিসেবে চলে আর হোস্ট ডিরেক্টরি root।

  • compose: command not found — পুরনো বাইনারি নাম ইনস্টল করেছেন; docker compose ব্যবহার করুন
  • port is already allocated — অন্য কিছু 80/443 ধরে (Apache, Nginx, অন্য Caddy)
  • database connection refused — Postgres প্রস্তুত হওয়ার আগে অ্যাপ শুরু; healthcheck + depends_on শর্ত ব্যবহার করুন
  • disk full — docker system df, তারপর অব্যবহৃত ইমেজ সাবধানে ছাঁটুন
  • permission denied on docker.sock — ব্যবহারকারী docker গ্রুপে নেই, বা নতুন লগইন সেশন লাগে

নিরাপত্তা

ডেটাবেস পোর্ট প্রকাশ করবেন না। privileged: true চালাবেন না। ইচ্ছাকৃতভাবে কন্টেইনার ম্যানেজার না লিখলে /var/run/docker.sock অ্যাপ কন্টেইনারে মাউন্ট করবেন না। ইঞ্জিন আপডেট রাখুন। নিজের ইমেজ বানালে স্ক্যান করুন। ডিস্কে .env এখনও সিক্রেট ফাইল — বক্সে কে ssh করতে পারে সীমাবদ্ধ করুন।

  • কোনো পাবলিক 5432 / 3306 / 6379 নয়
  • ইমেজ ডাইজেস্ট বা অন্তত অপরিবর্তনীয় ট্যাগ পিন করুন
  • chmod 600 .env
  • হোস্ট OS-এর জন্য Unattended-upgrades এখনও গুরুত্বপূর্ণ
  • অ্যাপ প্রতি এক Compose প্রজেক্ট বিস্ফোরণ ব্যাসার্ধ ছোট রাখে

টিপস

  • compose.yaml git-এ রাখুন; আসল সিক্রেট ছাড়া .env.example রাখুন
  • ঐচ্ছিক ওয়ার্কারের জন্য প্রোফাইল ব্যবহার করুন (docker compose --profile workers up -d)
  • VPS সাইজ করতে docker stats দেখুন
  • সোর্স কোডের বাইন্ড মাউন্ট উৎপাদন প্যাটার্ন নয় — ইমেজ বেক করুন
  • স্ট্যাক কয়েকটি VPS-এ বাড়লে তখন অর্কেস্ট্রেশন দেখুন — তার আগে নয়

এক VPS-এ উৎপাদন-সদৃশ Compose সেটআপ: অফিসিয়াল Docker প্যাকেজ, লক করা .env, ডেটাবেস প্রকাশ করে না এমন YAML ফাইল, হেলথচেক, 80/443-এ রিভার্স প্রক্সি, UFW, রোল ব্যাক করা যায় এমন ইমেজ ট্যাগ, এবং একবার সত্যি পুনরুদ্ধার করা Postgres ডাম্প। এই নিবন্ধের টেমপ্লেট থেকে শুরু করুন, অ্যাপ ইমেজ বদলান, এবং docker compose down -v-কে rm -rf-এর মতো ধ্বংসাত্মক কমান্ডের সম্মান দিন।