Back to devops
devops
12/7/2025
5 min read

How to configure your server for Zero Down time like Vercel

৫ ডলারের ভিপিএস-এ Next.js হোস্ট করতে গিয়ে 502 Error বা সার্ভার ক্র্যাশে ভুগছেন? এই গাইডে শিখুন কিভাবে GitHub Actions ও Atomic Deployment ব্যবহার করে Vercel-এর মতো Zero Downtime এবং Instant Rollback সেটআপ করবেন।

How to configure your server for Zero Down time like Vercel

Vercel বা Netlify তে কোড পুশ করলেই সাইট লাইভ হয়ে যায়, কোনো প্যারা নেই। কিন্তু যখনই পকেটের দিকে তাকিয়ে ৫ ডলারের একটা VPS (যেমন DigitalOcean বা Linode) কিনে নিজেই "DevOps Engineer" সাজার চেষ্টা করলাম, তখনই বুঝলাম—জীবনটা অত সহজ না।

আমার প্রজেক্ট (BlogSpace Client) লাইভ করতে গিয়ে যে সিনারিও ফেস করতাম:

১. কোড পুশ দিতাম।
২. সার্ভারে ঢুকে git pull দিতাম।
৩. npm run build কমান্ড দিতাম।
৪. BOOM! 💥

আমার ১ জিবি র‍্যামের সার্ভার বিল্ড করতে গিয়ে হ্যাং হয়ে যেত। আর যতক্ষণ বিল্ড চলত (৩-৪ মিনিট), ততক্ষণ সাইটে ঢুকলে ইউজার দেখত "502 Bad Gateway"। মানে সাইট ডাউন। ক্লায়েন্টের ফোন, নিজের ফ্রাস্ট্রেশন—সব মিলে এক জগাখিচুড়ি অবস্থা।

তারপর ভাবলাম, Vercel যদি জিরো ডাউনটাইমে ডিপ্লয় করতে পারে, আমি কেন পারব না? একটু ঘাটাঘাটি করে সল্যুশন বের করলাম: "Atomic Deployment with GitHub Actions"

আজকে দেখাবো কিভাবে আমি আমার Next.js অ্যাপ সেটআপ করেছি, যাতে Zero Downtime, No RAM Issues, এবং Instant Rollback পাওয়া যায়।


সমস্যাটা আসলে কোথায়? (The "Why")

আমরা সাধারণত সার্ভারে লাইভ ফোল্ডারের ভেতরেই npm run build চালাই। এতে সমস্যা হলো:

  • বিল্ড চলার সময় আগের ফাইলগুলো ডিলিট হয়ে যায় বা ইনকন্সিস্টেন্ট থাকে।সার্ভারের র‍্যাম ফুল হয়ে সাইট ক্র্যাশ করে।

সমাধান: Atomic Deployment (Symlink Magic)

আইডিয়াটা সিম্পল কিন্তু পাওয়ারফুল:
১. GitHub-এ বিল্ড হবে: সার্ভারের র‍্যাম খরচ করব না। গিটহাবের ফ্রি রানার ব্যবহার করব।
২. নতুন ফোল্ডারে আপলোড: প্রতিবার ডেপ্লয় করার সময় সার্ভারে একটা নতুন ফোল্ডার (যেমন: releases/2023...) বানাব।
৩. Symlink Switch: সব রেডি হলে জাস্ট একটা "শর্টকাট লিংক" (Symlink) ঘুরিয়ে দেব।
পুরাতন ফোল্ডার ➡️ নতুন ফোল্ডার
এই সুইচটা হতে সময় লাগে ১ সেকেন্ডের কম। ইউজার টেরও পায় না ব্যাকগ্রাউন্ডে পুরো সাইট আপডেট হয়ে গেছে।


স্টেপ-বাই-স্টেপ গাইড 🛠️

নিচে আমার BlogSpace প্রজেক্টের লাইভ সেটআপ শেয়ার করলাম।

ধাপ ১: সার্ভার রেডি করা

প্রথমে সার্ভারে ঢুকে ফোল্ডার স্ট্রাকচার ঠিক করতে হবে। আমরা সরাসরি প্রোজেক্ট ফোল্ডারে কোড রাখব না, রাখব releases ফোল্ডারে। আর মেইন ফোল্ডারটা হবে একটা "Symlink"।

SSH করে সার্ভারে ঢুকে এই কমান্ডগুলো দিন:


# ১. সব রিলিজ রাখার জন্য ফোল্ডার
mkdir -p /var/www/project/blogspace/releases
# ২. আপনার বর্তমান কোড যদি থাকে, সেটাকে ভার্সন-১ হিসেবে সরিয়ে ফেলুন
mv /var/www/project/blogspace/client /var/www/project/blogspace/releases/v1
# ৩. সিমলিংক তৈরি করুন (ম্যাজিক লাইন)
ln -sfn /var/www/project/blogspace/releases/v1 /var/www/project/blogspace/client


এখন আপনার Nginx বা PM2 কনফিগারেশন চেঞ্জ করার দরকার নেই, তারা /var/www/project/blogspace/client কেই চিনবে, কিন্তু আসলে ওটা পয়েন্ট করে আছে releases/v1 এর দিকে।

ধাপ ২: SSH Key জেনারেট করা

GitHub যাতে আপনার সার্ভারে ফাইল পাঠাতে পারে, তার জন্য একটা চাবি (Key) লাগবে। সার্ভারের ভেতরে এই কমান্ড দিন:


cd ~/.ssh
ssh-keygen -t rsa -b 4096 -f github_deploy_key -N ""


এখন পাবলিক কি-টা সার্ভারে অথোরাইজ করুন:


cat github_deploy_key.pub >> authorized_keys


আর প্রাইভেট কি-টা কপি করুন (এটা গিটহাবে লাগবে):


cat github_deploy_key


(শুরু -----BEGIN... থেকে শেষ পর্যন্ত কপি করবেন)

ধাপ ৩: GitHub Secrets সেটআপ

গিটহাব রিপোজিটরিতে গিয়ে Settings > Secrets and variables > Actions-এ যান। নিচের সিক্রেটগুলো অ্যাড করুন:

  • VPS_HOST: আপনার সার্ভারের আইপি।

  • USERNAME: সার্ভারের ইউজারনেম (যেমন root)।

  • SSH_PRIVATE_KEY: কপি করা প্রাইভেট কি।

  • NEXT_PUBLIC_...: আপনার অ্যাপের এনভায়রনমেন্ট ভেরিয়েবলগুলো (যেমন API URL)।

ধাপ ৪: The Workflow File (আসল খেলা) 

রিপোজিটরির .github/workflows/deploy-blogspace.yml ফাইলে নিচের কোডটি দিন।

এই স্ক্রিপ্ট যা করে:
১. গিটহাবে কোড বিল্ড করে।
২. এনভায়রনমেন্ট ভেরিয়েবলগুলো বিল্ডের ভেতর ঢুকিয়ে দেয় (Bake in)।
৩. ফাইল জিপ করে সার্ভারে পাঠায়।
৪. সার্ভারে আনজিপ করে এবং Symlink Switch করে দেয়।

name: Atomic Deploy Blogspace Client
on:
  push:
    branches:
      - main
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      # ১. কোড চেকআউট
      - name: Checkout code
        uses: actions/checkout@v3
      # ২. নোড সেটআপ
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: 'npm'
      # ৩. গিটহাবে বিল্ড (সার্ভারের র‍্যাম বাঁচলো!)
      - name: Install and Build
        run: |
          npm ci --legacy-peer-deps
          npm run build
        env:
          # এখানে আপনার অ্যাপের পাবলিক ভেরিয়েবলগুলো দিতে হবে
          NEXT_PUBLIC_BACKEND_API: ${{ secrets.NEXT_PUBLIC_BACKEND_API }}
          NEXT_PUBLIC_API_VERSION: ${{ secrets.NEXT_PUBLIC_API_VERSION }}
          NEXT_PUBLIC_SPACE_URL: ${{ secrets.NEXT_PUBLIC_SPACE_URL }}
          CACHE_REVALIDATE_TIME: ${{ secrets.CACHE_REVALIDATE_TIME }}
      # ৪. বিল্ড ফাইল কম্প্রেস করা
      - name: Tar build files
        run: tar -czf blog_build.tar.gz .next public package.json package-lock.json next.config.js
      # ৫. সার্ভারে পাঠানো (Temp ফোল্ডারে)
      - name: Copy files to VPS Temp
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          source: "blog_build.tar.gz"
          target: "/tmp"
      # ৬. এক্সট্রাক্ট এবং এটমিক সুইচ (আসল ম্যাজিক)
      - name: Extract and Switch on VPS
        uses: appleboy/ssh-action@v0.1.8
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            TIMESTAMP=$(date +%Y%m%d%H%M%S)
            RELEASE_DIR="/var/www/project/blogspace/releases/$TIMESTAMP"
            LIVE_DIR="/var/www/project/blogspace/client"
            PM2_NAME="blog-space-client"
            
            # নতুন ফোল্ডার বানিয়ে ফাইল আনজিপ
            mkdir -p "$RELEASE_DIR"
            tar -xzf /tmp/blog_build.tar.gz -C "$RELEASE_DIR"
            rm /tmp/blog_build.tar.gz
            # প্রোডাকশন ডিপেন্ডেন্সি ইনস্টল
            cd "$RELEASE_DIR"
            npm ci --production --legacy-peer-deps
            # --- ATOMIC SWITCH ---
            # সিমলিংক ঘুরিয়ে দেওয়া হচ্ছে নতুন ফোল্ডারে
            ln -sfn "$RELEASE_DIR" "$LIVE_DIR"
            # PM2 রিলোড (জিরো ডাউনটাইম)
            pm2 reload $PM2_NAME --update-env || pm2 start npm --name "$PM2_NAME" -- run start
            # ক্লিনআপ (পুরানো ভার্সন ডিলিট করে জায়গা বাচানো)
            cd /var/www/project/blogspace/releases
            ls -dt * | tail -n +6 | xargs -d '\n' rm -rf || true


ফলাফল? 😌

এখন আমি যখনই git push করি:
১. গিটহাব একশন রান হয়।
২. ২-৩ মিনিট পর সার্ভারে অটোমেটিক নতুন ভার্সন লাইভ হয়ে যায়।

৩. কোনো ডাউনটাইম নেই, কোনো 502 Error নেই।

সবচেয়ে বড় শান্তি হলো, যদি নতুন কোডে কোনো বাগ থাকে, আমি সার্ভারে ঢুকে জাস্ট একটা কমান্ড দিয়ে আগের ভার্সনে ফিরে যেতে পারি (Rollback)।

যাদের ভিপিএস এ Next.js হোস্ট করতে গিয়ে রাতের ঘুম হারাম হচ্ছে, তারা এই মেথডটা ট্রাই করে দেখতে পারেন। জীবন সুন্দর! ☕

হ্যাপি কোডিং! 💻

Tags

["tech","devops","cloud","ssh","server","vps"]