সরাসরি পর্বে যান
পর্ব ৮২ · ৯৩-এর মধ্যে · মডিউল ১২

কোথায় চালাবেন — VPS, shared hosting, PaaS আর serverless

Where to Run It — VPS, Shared Hosting, PaaS and Serverless

Taught in Bangla, this lesson asks where each part of an app should run, not which company to pick: shared hosting and cPanel and their limits, running Next.js on a VPS with a standalone build and pm2, Caddy as a reverse proxy with compression and cache headers, a measured zero-downtime reload, managed versus self-hosted databases and backups, PaaS and serverless trade-offs and cold starts, cost, domains and distance from Bangladesh, and a decision chart.

এই পর্বে যা শিখবেন

  • চার ধরনের জায়গায় বাজারঘরের কোন অংশ চলে, কোনটি ভাঙে, আর কেন
  • cPanel shared hosting-এ static export বা PHP অ্যাপ তোলার বাস্তবতা
  • নিজের যন্ত্রে VPS-এর মহড়া: standalone build, pm2 cluster, crash-এর পর restart, log, Caddy, compression আর cache header
  • Zero-downtime reload সত্যিই মাপা, managed বনাম নিজের PostgreSQL আর backup
  • PaaS ও serverless-এর সীমা, cold start, lock-in, খরচের ছক আর একটি সিদ্ধান্তের গাইড

১ · চার জায়গা, একটি দোকান

বাজারঘর এখন প্রায় তৈরি। Next.js 16-এর দোকানের পাতা, Express বা route handler-এর API (পর্ব ৫৭), Prisma আর PostgreSQL, Redis-এর cache (পর্ব ৪৪), background worker আর cron (পর্ব ৬২), আর অর্ডারের live আপডেটের জন্য WebSocket (পর্ব ৬০)। এবার প্রশ্ন: এসব চলবে কোথায়?

দোকান খোলার চারটি উপায় ভাবুন। Shared hosting হলো মার্কেটের ভেতরে ভাগের একটি তাক: ভাড়া কম, কিন্তু বিদ্যুৎ, তালা আর সময় মার্কেট কমিটির নিয়মে। VPS হলো নিজের ভাড়া করা দোকানঘর: যা খুশি সাজাতে পারেন, কিন্তু শাটার, তালা আর পাহারা আপনার দায়িত্ব। PaaS হলো সাজানো-গোছানো শোরুম ভাড়া: শুধু মাল তোলেন, বাকিটা মালিক দেখেন, দাম বেশি। Serverless হলো মেলার স্টল, যা ক্রেতা এলে খোলে আর ফাঁকা হলে গুটিয়ে যায়: যত বিক্রি তত ভাড়া, কিন্তু প্রথম ক্রেতাকে স্টল খোলা পর্যন্ত একটু দাঁড়াতে হয়।

তত্ত্বের দিক, অর্থাৎ IaaS, PaaS আর FaaS কী, public আর private cloud কী, Cloud & DevOps কোর্সের deployment model আর কোন compute কখন পর্বে আছে। এখানে আমরা একজন ফুল-স্ট্যাক ডেভেলপারের চোখে দেখব: আমার অ্যাপের কোন টুকরো কোথায় বসবে, আর কোথায় বসালে কী ভাঙবে।

  • Shared hosting: একটি server-এ অনেক গ্রাহক, প্রত্যেকে একটি ফোল্ডার আর একটি cPanel পান। সাধারণত Apache বা LiteSpeed, PHP আর MySQL থাকে।
  • VPS: একটি virtual যন্ত্র, পূর্ণ root অধিকারসহ। OS থেকে firewall পর্যন্ত সব আপনার।
  • PaaS: আপনি কোড বা container দেন, platform build করে, চালায়, পড়ে গেলে তোলে। ডেটাবেস প্রায়ই পাশের একটি managed সেবা।
  • Serverless: কোড ছোট function হিসেবে অনুরোধ এলে চলে, ভিড়ে অনেক কপি হয়, অলস হলে শূন্যে নামে।

কোন অংশ কোথায় চলে

নিচের টেবিলটি এই পর্বের মেরুদণ্ড। “হ্যাঁ” মানে সাধারণভাবে স্বাভাবিক পথে চলে; “শর্তে” মানে কোনো বিশেষ সুবিধা বা কৌশল লাগে, আর সেটি সেবাদাতা ভেদে আলাদা। নির্দিষ্ট কোনো সেবার জন্য তাদের বর্তমান নথি দেখে মিলিয়ে নিন।

অংশShared hostingVPSPaaSServerless
Static ফাইল (HTML, JS, ছবি)হ্যাঁহ্যাঁ, proxy দেয়হ্যাঁহ্যাঁ, সাধারণত CDN থেকে
Next.js server (SSR, Server Action)শর্তে: Node অ্যাপ সুবিধা থাকলেহ্যাঁহ্যাঁহ্যাঁ, adapter দিয়ে
API (Express বা route handler)শর্তে; PHP হলে হ্যাঁহ্যাঁহ্যাঁহ্যাঁ, ছোট অনুরোধে
Background worker (queue)সাধারণত নাহ্যাঁহ্যাঁ, আলাদা worker সেবাশর্তে: queue trigger, সময়সীমা
Cronহ্যাঁ, cPanel cron (PHP বা script)হ্যাঁশর্তেশর্তে: scheduled trigger
WebSocketপ্রায় নাহ্যাঁসাধারণত হ্যাঁকঠিন: আলাদা realtime সেবা লাগে
PostgreSQLপ্রায়ই নেই, MySQL থাকেহ্যাঁ, নিজে চালানmanaged add-onবাইরের managed, pooler-সহ
Redisসাধারণত নাহ্যাঁmanaged add-onHTTP-ভিত্তিক managed Redis

টেবিল থেকেই একটি নিয়ম বেরিয়ে আসে: যে কাজ দীর্ঘক্ষণ বেঁচে থাকা process চায় (WebSocket-এর খোলা সংযোগ, পাঁচ মিনিটের PDF job, queue-র worker), সেটি VPS বা PaaS-এ স্বাভাবিক, serverless-এ কষ্টের, shared hosting-এ প্রায় অসম্ভব। আর যে কাজ শুধু ফাইল দেয়, সেটি যেকোনো জায়গায় চলে, সবচেয়ে ভালো চলে CDN থেকে।

VPS-এ বাজারঘর: কোন অংশ কোথায় বসে

A single-VPS topology: CDN in front, firewall, Caddy, a pm2 cluster, a worker, Redis and PostgreSQL on localhost

এক VPS-এ বাজারঘরের বিন্যাস ব্রাউজার (ঢাকা) DNS → CDN edge /_next/static cache থেকেই ফেরত VPS (Linux) firewall: শুধু 80, 443, 22 Caddy :443 TLS, gzip/zstd, reverse proxy pm2 cluster · 127.0.0.1:47382 worker 0 Next.js server.js worker 1 Next.js server.js job worker + cron Redis 127.0.0.1:6379 PostgreSQL 127.0.0.1:5432 বিকল্প: PostgreSQL আর Redis managed সেবায় তখন VPS-এ শুধু proxy, Node আর worker
ছবি ৮২.১ — বাইরে থেকে শুধু তিনটি port খোলা: 80 (certificate আর redirect), 443 (দোকান), 22 (SSH). Node, Redis আর PostgreSQL সবাই 127.0.0.1-এ শোনে, তাই ইন্টারনেট থেকে সরাসরি পৌঁছানো যায় না।

ধারণাগুলো নতুন নয়। cPanel-এর যাত্রা ১৯৯০-এর দশকের মাঝামাঝি থেকে শেষ দিকে (১৯৯৬ সালের দিকে বলে জানা যায়); বহু বছর ধরে এটি shared hosting-এর পরিচিত মুখ। PaaS জনপ্রিয় করে Heroku (২০০৭ সালের দিকে শুরু), যেখানে git push করলেই অ্যাপ চলত। AWS Lambda ঘোষণা হয় ২০১৪ সালে, আর “serverless” শব্দটি আগেও কিছুটা ব্যবহৃত হলেও মূলত এর পর থেকেই ব্যাপকভাবে ছড়ায়। Nginx-এর প্রথম প্রকাশ ২০০৪ সালে (Igor Sysoev); Caddy আসে ২০১৫ সালে, ডিফল্টভাবে স্বয়ংক্রিয় HTTPS-এর জন্য পরিচিত। একই বছর Let's Encrypt বিনা খরচে certificate দেওয়া শুরু করে, যা ছোট সাইটের জন্য HTTPS-কে সাধারণ ব্যাপার বানিয়ে দেয়।

২ · Shared hosting আর cPanel — বাংলাদেশের পরিচিত পথ

বাংলাদেশে বহু ছোট ব্যবসা, স্কুল আর ফ্রিল্যান্সার স্থানীয় বা বিদেশি hosting কোম্পানির cPanel-ওয়ালা প্যাকেজ ব্যবহার করেন। কারণগুলো বাস্তব: টাকায় বিল দেওয়া যায়, বাংলায় support মেলে, আর বছরে একবার নবায়ন করলেই চলে। কোন প্যাকেজে ঠিক কী আছে, তা প্রতিষ্ঠান আর প্যাকেজ ভেদে অনেক আলাদা। তাই এখানে যা বলছি, তা সাধারণ চিত্র; কেনার আগে নিজের hosting-এর বিবরণ মিলিয়ে নিন।

যা সাধারণত পাবেন, আর যা পাবেন না

  • পাবেন: public_html ফোল্ডার, File Manager, FTP, MySQL বা MariaDB, PHP, email, cron job, আর প্রায়ই বিনা খরচের TLS certificate.
  • পাবেন না: root অধিকার, নিজের মতো package install, যেকোনো port-এ শোনা, আর চিরকাল চলা process. প্রতিটি অ্যাকাউন্টের CPU, মেমরি আর process-এর সংখ্যায় সীমা থাকে; অনেক hosting-এ এই সীমা CloudLinux-এর মতো ব্যবস্থায় বাঁধা।
  • কখনো কখনো পাবেন: Node.js বা Python অ্যাপ চালানোর একটি অংশ। cPanel-এর নিজস্ব Application Manager, বা CloudLinux-এর “Setup Node.js App” জাতীয় সুবিধা, যেখানে hosting এটি চালু রেখেছে। সাধারণত এগুলো Phusion Passenger-এর মতো একটি app server দিয়ে আপনার অ্যাপ চালায়, আর অলস থাকলে process থামিয়ে দিতে পারে। আপনার প্যাকেজে এটি আছে কি না, আর থাকলে কোন Node version, তা hosting-কেই জিজ্ঞেস করুন।

বাজারঘরের তিনটি পথ shared hosting-এ

১. Static export

output: 'export' দিলে পুরো দোকান HTML, CSS আর JS ফাইল। পর্ব ৫৫-এর build-এ পুরো ক্যাটালগ ছিল ৪৪টি ফাইল, 766 KB. Server Action, ISR বা cookie নেই, কিন্তু চলবে যেকোনো Apache-এ।

শুধু দেখার দোকান, ক্যাটালগ

২. Vite SPA + বাইরের API

React Router-এর SPA (পর্ব ২০) public_html-এ, আর .htaccess-এর SPA fallback, যাতে /products/3 সরাসরি খুললে 404 না হয়। API অন্য কোথাও চলে।

frontend এখানে, backend অন্যখানে

৩. PHP অ্যাপ

Laravel (পর্ব ৭০) shared hosting-এর স্বাভাবিক বাসিন্দা। নিয়ম একটাই: ওয়েব থেকে দেখা ফোল্ডার হবে public/, পুরো প্রজেক্ট নয়, যাতে .env কখনো ওয়েবে না যায়।

পুরো ফুল-স্ট্যাক, MySQL-সহ

নিচের stepper-এ static export কীভাবে cPanel-এ ওঠে, ধাপে ধাপে দেখুন। ফাইলের সংখ্যা আর আকার পর্ব ৫৫-এর সত্যিকারের build থেকে; cPanel-এর ধাপগুলো সাধারণ বিবরণ, কারণ আমরা কোনো আসল hosting-এ তুলিনি।

  1. buildout/নিজের যন্ত্রে
  2. zipsite.zipএকটি ফাইল
  3. cPanelpublic_htmlupload, extract
  4. .htaccess404, cacheApache-এর নিয়ম
  5. যাচাইcurl -Iব্রাউজারে দেখা
~/bazarghar-exportপর্ব ৫৫-এর সত্যিকারের build
next.config.mjs: output: 'export', trailingSlash: true
$ npx next build
out/index.html
out/products/1/index.html
out/_next/static/…
৪৪টি ফাইল, 766 KB
zipভেতরের সবকিছু, ফোল্ডার নয়
cd out
zip -r ../site.zip .
# out/ ফোল্ডারটি নয়, তার ভেতরের জিনিস
public_htmlFile Manager → Upload → Extract
public_html/
  index.html
  404.html
  products/1/index.html
  _next/static/…
  .htaccess   ← আগে থেকে থাকলে মুছবেন না
.htaccessউদাহরণ, আসল Apache-এ চালানো হয়নি
ErrorDocument 404 /404.html
<IfModule mod_headers.c>
  <FilesMatch "\.html$">
    Header set Cache-Control "no-cache"
  </FilesMatch>
</IfModule>
Terminalযা দেখার কথা (নমুনা)
$ curl -I https://bazarghar.example/products/1/
HTTP/2 200
content-type: text/html
cache-control: no-cache
নমুনা আউটপুট: আসল hosting-এ চালানো নয়
  1. নিজের যন্ত্রে build. output: 'export' আর trailingSlash: true দিয়ে next build. প্রতিটি পাতা নিজের ফোল্ডারে index.html, যা Apache কোনো বাড়তি নিয়ম ছাড়াই দেয়। পর্ব ৫৫-এর run-এ পুরো দোকান ৪৪টি ফাইল, 766 KB.
  2. একটি zip. শত শত ছোট ফাইল FTP-তে আলাদা তুললে ধীর আর ভুলের সুযোগ বেশি। out-এর ভেতরের সবকিছু একটি zip-এ ভরুন, যাতে extract করলে ফাইলগুলো সরাসরি public_html-এ বসে, public_html/out/-এ নয়।
  3. Upload আর extract. File Manager-এ “Show Hidden Files” চালু রাখুন, নইলে .htaccess দেখা যাবে না। পুরোনো build-এর _next/static ফাইল থেকে গেলে ক্ষতি নেই, কারণ নতুন build-এর নাম নতুন hash-এ।
  4. .htaccess. নিজের 404 পাতা, আর HTML-এ no-cache, যাতে নতুন upload সঙ্গে সঙ্গে দেখা যায়। mod_headers চালু আছে কি না hosting ভেদে আলাদা, তাই নিয়মটি IfModule-এর ভেতরে। Vite SPA হলে এখানে পর্ব ২০-এর SPA fallback-ও বসবে।
  5. যাচাই. curl -I দিয়ে status আর header দেখুন, তারপর ব্রাউজারে একটি গভীর URL সরাসরি খুলুন। পাশের আউটপুটটি নমুনা, কারণ এই পর্বের জন্য আমরা কোনো আসল hosting-এ তুলিনি।

cPanel-এর Node অ্যাপ সুবিধা থাকলেও কয়েকটি জিনিস আশা করবেন না। Process সংখ্যার সীমার কারণে pm2-এর cluster প্রায়ই চলে না, অলস হলে process থামতে পারে বলে in-memory cache আর WebSocket-এর ভরসা কম, আর build-এর মতো ভারী কাজ (next build) সেখানে মেমরির সীমায় আটকে যেতে পারে। নিরাপদ পথ হলো build নিজের যন্ত্রে বা CI-তে করা, আর hosting-এ শুধু তৈরি ফাইল তোলা।

৩ · VPS ঠিকভাবে — standalone build আর pm2

VPS-এ স্বাধীনতা পুরো, দায়িত্বও পুরো। আমরা কোনো আসল VPS ভাড়া করিনি; একই কাজ নিজের যন্ত্রে 127.0.0.1-এ মহড়া দিয়েছি। নিচের প্রতিটি আউটপুট সেই সত্যিকারের run থেকে, লেখার সময়ের version-এ: Next.js 16.4.4, React 19.3.1, pm2 7.1.1, Caddy 2.11.7, Node 24. যন্ত্রটি Windows ছিল, যা পার্থক্য তৈরি করেছে এক জায়গায়, সেটি নিচে বলা আছে। Linux server-এর ভিত্তি, যেমন user, permission আর package, Cloud & DevOps-এর Server-এর Linux পর্বে।

ধাপ ১: standalone build

সাধারণ next start চালাতে server-এ পুরো node_modules লাগে। output: 'standalone' দিলে Next.js build-এর সময় খুঁজে বের করে কোন ফাইল সত্যিই লাগবে, আর শুধু সেগুলো নিয়ে .next/standalone ফোল্ডার আর একটি ছোট server.js বানায়। এটাই standalone output.

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
};
export default nextConfig;
~/bazarghar$ npx next build
▲ Next.js 16.4.4 (Turbopack)
…
Route (app)
┌ ○ /
├ ○ /_not-found
├ ƒ /api/health
├ ƒ /api/lab-crash
└ ƒ /products

○  (Static)   prerendered as static content
ƒ  (Dynamic)  server-rendered on demand

~/bazarghar$ cp -r public .next/standalone/ && cp -r .next/static .next/standalone/.next/
~/bazarghar$ du -sh .next/standalone node_modules
32M	.next/standalone
351M	node_modules

সত্যিকারের run. একটি local run-এ ছোট বাজারঘরের standalone ফোল্ডার 32 MB, যেখানে পুরো node_modules 351 MB; আপনার প্রজেক্টে সংখ্যা আলাদা হবে। মাঝের cp লাইনটি জরুরি: নথি অনুযায়ী server.js নিজে থেকে public আর .next/static কপি করে না, কারণ ধারণা হলো এগুলো CDN দেবে। কপি করলে server.js নিজেই এগুলো দেয়। /api/lab-crash শুধু এই ল্যাবের জন্য একটি route, যা ইচ্ছে করে process বন্ধ করে, যাতে আমরা crash-এর পর কী হয় দেখতে পারি।

ধাপ ২: pm2 দিয়ে চালু রাখা

node server.js হাতে চালালে terminal বন্ধ হলেই দোকান বন্ধ, crash হলে কেউ আবার চালাবে না। দরকার একটি process supervisor. Linux-এ systemd নিজেই এ কাজ পারে (systemd-এর পর্ব); Node-এর জগতে জনপ্রিয় বিকল্প pm2, যা একসাথে cluster, log আর reload দেয়। আমাদের ecosystem ফাইল:

module.exports = {
  apps: [{
    name: 'bazarghar-web',
    script: '.next/standalone/server.js',
    exec_mode: 'cluster',
    instances: 2,               // CPU core অনুযায়ী; 'max' দিলে সব core
    env: { NODE_ENV: 'production', PORT: 47382, HOSTNAME: '127.0.0.1' },
    out_file: 'logs/web-out.log',
    error_file: 'logs/web-error.log',
    time: true,                 // log-এর প্রতিটি লাইনে সময়
    max_memory_restart: '300M', // মেমরি ফাঁস হলে আবার চালু
    kill_timeout: 10000,        // বন্ধের আগে চলমান অনুরোধ শেষ করার সময়
  }],
};

HOSTNAME: '127.0.0.1' খেয়াল করুন: Node শুধু যন্ত্রের ভেতর থেকে পৌঁছানো যায় এমন ঠিকানায় শোনে, বাইরের দুনিয়া কথা বলবে শুধু proxy-র সাথে। এবার চালানো, আর সমানভাবে ভাগ হচ্ছে কি না দেখা:

~/bazarghar$ pm2 start ecosystem.config.js
[PM2][WARN] Applications bazarghar-web not running, starting...
[PM2] App [bazarghar-web] launched (2 instances)

~/bazarghar$ node count-pids.js      # ছোট script: ২০টি অনুরোধ, প্রতিটির pid গোনা
{ '29580': 20 }                      # Windows, ডিফল্ট নিয়ম

~/bazarghar$ pm2 kill && NODE_CLUSTER_SCHED_POLICY=rr pm2 start ecosystem.config.js
~/bazarghar$ node count-pids.js
{ '12432': 10, '23920': 10 }         # round-robin

সত্যিকারের run, কিন্তু একটি শিক্ষণীয় চমকসহ। প্রথমবার ২০টি অনুরোধের সবকটি একই worker-এ গেল। কারণ Node-এর cluster module-এর নথি অনুযায়ী ভাগের ডিফল্ট নিয়ম Windows ছাড়া সব OS-এ round-robin; Windows-এ OS নিজে ঠিক করে কোন process সংযোগ নেবে। NODE_CLUSTER_SCHED_POLICY=rr দিয়ে pm2-এর daemon চালু করার পর ১০ আর ১০, ঠিক পালা করে। Linux VPS-এ এই পরিবর্তন লাগে না। শিক্ষা: “চলছে” দেখে থামবেন না, ভাগটা মেপে দেখুন।

ধাপ ৩: crash, আবার চালু, আর log

এবার ইচ্ছে করে একটি worker মেরে ফেলি। ল্যাবের route process-কে process.exit(1) করে:

~/bazarghar$ curl -s -X POST http://127.0.0.1:47382/api/lab-crash
{"bye":23920}
~/bazarghar$ pm2 ls
┌────┬──────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name             │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼──────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0  │ bazarghar-web    │ default     │ 1.0.0   │ cluster │ 6592     │ 3s     │ 1    │ online    │ 0%       │ 90.3mb   │ deploy   │ disabled │
│ 1  │ bazarghar-web    │ default     │ 1.0.0   │ cluster │ 12432    │ 13s    │ 0    │ online    │ 0%       │ 95.0mb   │ deploy   │ disabled │
└────┴──────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
~/bazarghar$ for i in 1 2 3 4; do curl -s http://127.0.0.1:47382/api/health; echo; done
{"ok":true,"pid":12432}
{"ok":true,"pid":6592}
{"ok":true,"pid":12432}
{"ok":true,"pid":6592}
~/bazarghar$ tail -n 1 logs/web-error-0.log
2026-11-03T17:16:27: lab: worker exiting on purpose

সত্যিকারের run (user কলামের নাম বদলে deploy লেখা হয়েছে, আর host-এর তথ্যের লাইন বাদ)। pid 23920 মারা গেল, pm2 তিন সেকেন্ডের মধ্যে id 0-এর জায়গায় নতুন process 6592 তুলল, আর ↺ (restart-এর সংখ্যা) হলো 1. দোকান চালু থাকল, কারণ ততক্ষণ worker 1 একাই সব সামলেছে। log ফাইল প্রতিটি worker-এর আলাদা (-0, -1 যোগ হয়েছে), আর time: true-এর জন্য প্রতিটি লাইনে সময়। আসল server-এ এই log ফাইল দিনে দিনে বড় হয়, তাই pm2-logrotate বা OS-এর logrotate লাগে; structured log-এর কথা পর্ব ৩১-এ, আর error ট্র্যাকিং আসছে পর্ব ৮৩-এ।

pm2 নিজে কী করছে, তার একটি খেলনা মডেল নিচে। দুটি worker, পালা করে অনুরোধ, একটি অনুরোধ চলার মাঝেই worker 1 মারা যায়, আর supervisor দুই tick পরে নতুন pid নিয়ে তাকে ফেরায়। চালিয়ে দেখুন, তারপর t === 4 বদলে অন্য সময়ে crash ঘটান।

// pm2 cluster-এর খেলনা মডেল: round-robin, একটি worker crash, supervisor আবার চালায়
const workers = [{ id: 0, pid: 101, up: true, restarts: 0 },
                 { id: 1, pid: 102, up: true, restarts: 0 }];
let nextPid = 103, rr = 0, ok = 0, failed = 0, restartAt = null;
const RESTART_DELAY = 2;              // ধরে নেওয়া: নতুন process তৈরি হতে ২ tick

function pick() {                     // পরের জীবিত worker, পালা করে
  for (let i = 0; i < workers.length; i++) {
    const w = workers[(rr + i) % workers.length];
    if (w.up) { rr = (rr + i + 1) % workers.length; return w; }
  }
  return null;
}

for (let t = 1; t <= 9; t++) {
  if (t === restartAt) {
    const w = workers[1];
    Object.assign(w, { up: true, pid: nextPid++, restarts: w.restarts + 1 });
    console.log(`t=${t} supervisor: worker 1 back as pid ${w.pid} (restarts ${w.restarts})`);
  }
  const w = pick();
  if (t === 4) {                      // এই অনুরোধ চলার সময়েই process মারা গেল
    w.up = false; failed++; restartAt = t + RESTART_DELAY;
    console.log(`t=${t} GET -> worker ${w.id} pid ${w.pid}  CRASH, proxy answers 502`);
    continue;
  }
  ok++;
  console.log(`t=${t} GET -> worker ${w.id} pid ${w.pid}  200`);
}
console.log(`ok ${ok}, failed ${failed}`);

আউটপুট: t=1 থেকে t=3 পালা করে worker 0, 1, 0. t=4 GET -> worker 1 pid 102 CRASH, proxy answers 502. t=5-এ worker 1 নেই, তাই pick() তাকে বাদ দিয়ে worker 0-কে দেয়। t=6 supervisor: worker 1 back as pid 103 (restarts 1), তারপর আবার পালা করে, শেষে ok 8, failed 1. দুটি শিক্ষা। এক, একাধিক worker থাকায় crash-এর সময়েও দোকান বন্ধ হয়নি; একটি worker থাকলে t=5-ও ব্যর্থ হতো। দুই, যে অনুরোধ চলার সময় process মরে, সেটি বাঁচানো যায় না; proxy তখন 502 Bad Gateway দেয়। তাই crash-এর মূল কারণ খোঁজা জরুরি, restart শুধু ব্যান্ডেজ।

৪ · সামনে reverse proxy — Caddy, compression আর cache header

Next.js-এর self-hosting নথি সরাসরি বলে: Next.js server-কে সরাসরি ইন্টারনেটে না রেখে সামনে একটি reverse proxy রাখুন, যা ভাঙা অনুরোধ, ধীরে ধীরে পাঠানো সংযোগের আক্রমণ, payload-এর সীমা আর rate limit সামলাবে। হোটেলের রিসেপশনের মতো: অতিথি সরাসরি রান্নাঘরে ঢোকেন না, রিসেপশন যাচাই করে ঠিক জায়গায় পাঠায়। Nginx-এর virtual host, TLS আর proxy-র বিস্তারিত Cloud & DevOps-এর Nginx আর reverse proxy পর্বে; এখানে আমরা Caddy ব্যবহার করেছি, কারণ এর config ছোট আর আসল domain-এ এটি নিজেই certificate নেয়। Caddy-র Windows binary তাদের release-এর checksum ফাইলের সাথে মিলিয়ে তবেই চালানো হয়েছে।

{
	admin 127.0.0.1:47389
	auto_https off
}

http://127.0.0.1:47380 {
	bind 127.0.0.1
	encode zstd gzip

	# hash-ওয়ালা JS/CSS: disk থেকে সরাসরি, এক বছরের cache
	handle_path /_next/static/* {
		root * .next/static
		header Cache-Control "public, max-age=31536000, immutable"
		file_server
	}

	# বাকি সব: Node (pm2 cluster)
	handle {
		reverse_proxy 127.0.0.1:47382
	}

	header -Server
	log {
		output file logs/caddy-access.log
		format json
	}
}

ল্যাবে auto_https off আর http://, কারণ 127.0.0.1-এর জন্য কোনো public certificate হয় না। প্রথমবার bind ছাড়া চালিয়ে দেখা গেল Caddy 0.0.0.0:47380-এ শুনছে, অর্থাৎ সব network-এ; site-এর ঠিকানায় 127.0.0.1 লেখা থাকলেও। bind 127.0.0.1 যোগ করে তবেই শুধু ভেতরে সীমিত হলো। আসল server-এ এ ধরনের ভুল ধরতে ss -tlnp বা netstat দিয়ে কে কোথায় শুনছে তা দেখার অভ্যাস রাখুন। এবার তিনটি অনুরোধ:

~/bazarghar$ curl -sS -D - -o /dev/null -H 'Accept-Encoding: gzip, zstd' http://127.0.0.1:47380/
HTTP/1.1 200 OK
Cache-Control: s-maxage=31536000
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Etag: "pr41o7sdnu3l2"
Vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept-Encoding
Via: 1.1 Caddy
X-Nextjs-Cache: HIT
X-Nextjs-Prerender: 1
X-Powered-By: Next.js
…
~/bazarghar$ curl -sS -D - -o /dev/null -H 'Accept-Encoding: gzip' http://127.0.0.1:47380/products
HTTP/1.1 200 OK
Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate
Content-Encoding: gzip
Via: 1.1 Caddy
…
~/bazarghar$ curl -sS -D - -o /dev/null -H 'Accept-Encoding: gzip' http://127.0.0.1:47380/_next/static/chunks/0cz1d0mv5g_q7.js
HTTP/1.1 200 OK
Cache-Control: public, max-age=31536000, immutable
Content-Encoding: gzip
Content-Type: text/javascript; charset=utf-8
…
~/bazarghar$ for e in identity gzip zstd; do curl -s -o /dev/null -H "Accept-Encoding: $e" \
    -w "$e: %{size_download} bytes\n" http://127.0.0.1:47380/_next/static/chunks/0cz1d0mv5g_q7.js; done
identity: 112594 bytes
gzip: 41106 bytes
zstd: 41881 bytes

সত্যিকারের run, কয়েকটি লাইন বাদ দিয়ে। হোম পাতা build-এর সময় তৈরি (X-Nextjs-Prerender: 1), তাই Next.js s-maxage দিয়েছে, যা CDN-কে cache করার অনুমতি দেয়। /products প্রতি অনুরোধে তৈরি, তাই private, no-store: কোনো CDN বা proxy এটি জমিয়ে রাখবে না, যা ক্রেতার নিজস্ব তথ্যের পাতার জন্য ঠিক। JS chunk Caddy সরাসরি disk থেকে দিয়েছে, Node পর্যন্ত যায়নি, আর immutable মানে ব্রাউজার এক বছর আর জিজ্ঞেসও করবে না; ফাইলের নামে hash থাকায় এটি নিরাপদ। Compression-এ এই ফাইলটি 112,594 থেকে gzip-এ 41,106 bytes, প্রায় ৬৩% কম; এই একটি ফাইলে zstd সামান্য বড় এসেছে। এটি একটি ফাইলের একটি run, সাধারণ সিদ্ধান্ত নয়। X-Powered-By: Next.js header বন্ধ করতে চাইলে config-এ poweredByHeader: false; নিরাপত্তা header-এর বাকি তালিকা পর্ব ৫০-এ।

একটি অনুরোধের পুরো পথ

আসল production-এ সামনে আরও দুটি স্তর যোগ হয়: DNS আর CDN. নিচের stepper-এ একটি ক্রেতার দুটি অনুরোধ দেখুন: একটি JS ফাইল আর একটি /products পাতা। Header-এর মান ওপরের সত্যিকারের run থেকে; DNS আর CDN-এর অংশ বর্ণনা, কারণ কোনো আসল domain বা CDN ব্যবহার করা হয়নি। IP ঠিকানাগুলো নথিতে উদাহরণের জন্য সংরক্ষিত পরিসর থেকে।

  1. DNSA recordনাম থেকে IP
  2. CDN edgecacheকাছের server
  3. Caddy:443VPS-এর দরজা
  4. Node:47382pm2 worker
এই ধাপে
অনুরোধ
কে উত্তর দিল
মূল তথ্য
VPS ছুঁয়েছে?
  1. DNS. ব্রাউজার জিজ্ঞেস করে bazarghar.example-এর ঠিকানা কী। CDN ব্যবহার করলে DNS record দেখায় CDN-এর edge-এর দিকে, VPS-এর দিকে নয়। TTL 300 মানে উত্তরটি পাঁচ মিনিট মনে রাখা চলে। Record, TTL আর routing-এর তত্ত্ব Cloud DNS পর্বে।
  2. TLS, কাছের edge-এ। HTTPS-এর handshake হয় CDN-এর edge-এর সাথে, যা সাধারণত ব্যবহারকারীর কাছাকাছি। তাই দূরের server-এ handshake-এর কয়েকটি round trip বাঁচে।
  3. JS ফাইল: cache থেকেই। public, max-age=31536000, immutable দেখে CDN আগের কপি দেয়। VPS কিছুই জানে না, কোনো খরচ বা চাপ নেই। এজন্যই নথি বলে static ফাইল ভালোভাবে CDN-এ রাখা যায়।
  4. /products: origin-এ যেতে হবে। উত্তরে private, no-store থাকবে, তাই CDN এটি জমায় না; অনুরোধ যায় origin-এ, অর্থাৎ VPS-এর Caddy-তে। Firewall বাইরে থেকে শুধু 22, 80 আর 443 খোলা রেখেছে; দোকানের অনুরোধ আসে 443-এ, Node-এর port বাইরে বন্ধ।
  5. Caddy থেকে Node. Caddy TLS খোলে, অনুরোধটি 127.0.0.1:47382-এ দেয়; pm2-এর cluster একটি worker-কে দেয়। Worker পাতা তৈরি করে; ফেরার পথে Caddy gzip করে আর Via: 1.1 Caddy যোগ করে।
  6. ফেরার পথ। উত্তর Caddy থেকে CDN হয়ে ব্রাউজারে। দুটি অনুরোধের মধ্যে VPS ছুঁয়েছে মাত্র একটি। দোকান যত বড় হয়, এই অনুপাতই ঠিক করে একটি ছোট VPS কতটা ভিড় সামলাতে পারবে। CDN, WAF আর DDoS-এর বিস্তারিত CDN, WAF আর edge পর্বে।

আসল domain-এ TLS, firewall আর SSH

এই অংশ আমরা চালাইনি, কারণ এর জন্য আসল domain আর public server লাগে। সাধারণ পথটি এমন:

  • TLS: domain-এর A record VPS-এর IP-তে দিন। Caddy-তে site-এর ঠিকানা হিসেবে শুধু bazarghar.example লিখলে Caddy নিজেই Let's Encrypt বা অন্য ACME সেবা থেকে certificate নেয় আর নবায়ন করে। Nginx-এ এ কাজ সাধারণত certbot করে। Let's Encrypt-এর certificate স্বল্পমেয়াদি (লেখার সময়ে ৯০ দিন, আর মেয়াদ আরও কমানোর পরিকল্পনা তাঁরা ঘোষণা করেছেন), তাই নবায়ন স্বয়ংক্রিয় না হলে একদিন দোকান হঠাৎ “Not secure” দেখাবে। ACME-র HTTP challenge-এর জন্য port 80 খোলা থাকা লাগে। TLS-এর ভেতরের কাজ Computer Networks-এর TLS আর HTTPS পর্বে।
  • Firewall: বাইরে থেকে শুধু 22, 80, 443. PostgreSQL-এর 5432 বা Redis-এর 6379 কখনো ইন্টারনেটে খোলা নয়। cloud-এর security group আর OS-এর firewall দুই স্তরেই নিয়ম রাখা ভালো; তত্ত্ব security group পর্বে।
  • SSH: password দিয়ে login বন্ধ, শুধু key; root দিয়ে সরাসরি login বন্ধ, আলাদা একটি user; বারবার ভুল login ঠেকাতে fail2ban-এর মতো টুল। বিস্তারিত SSH আর দূরের server পর্বে।
  • Reboot-এর পর: pm2 startup OS-এর জন্য একটি startup script তৈরির কমান্ড দেখায়, আর pm2 save বর্তমান process-এর তালিকা মনে রাখে। দুটি না করলে server restart-এর পর দোকান বন্ধ থাকবে। এগুলো আমরা Windows-এ চালাইনি।

৫ · Zero-downtime reload — মেপে দেখা

নতুন কোড এলে পুরোনো process থামিয়ে নতুনটি চালাতে হয়। মাঝের কয়েক সেকেন্ডে যাঁরা অর্ডার দিচ্ছেন, তাঁদের কী হয়? Zero-downtime reload-এর দাবি: কিছুই হবে না। দাবিটি আমরা মেপে দেখেছি। একটি ছোট script চারটি সমান্তরাল loop-এ ১২ সেকেন্ড ধরে Caddy-র মাধ্যমে /api/health-এ অনুরোধ পাঠায়, প্রতিটি নতুন সংযোগে, আর ফল গোনে। তিন সেকেন্ড পর চালানো হয় reload.

~/bazarghar$ node load.js http://127.0.0.1:47380/api/health 12 &  sleep 3;  pm2 reload bazarghar-web
[PM2] Applying action reloadProcessId on app [bazarghar-web](ids: [ 0, 1 ])
[PM2] [bazarghar-web](0) ✓
[PM2] [bazarghar-web](1) ✓
requests: 23745
ok: 23745  failed: 0
status codes: {"200":23745}
network errors: {}
worker pids seen: 12432, 6592, 33336, 33360

~/bazarghar$ node load.js http://127.0.0.1:47380/api/health 12 &  sleep 3;  pm2 restart bazarghar-web
[PM2] Applying action restartProcessId on app [bazarghar-web](ids: [ 0, 1 ])
[PM2] [bazarghar-web](0) ✓
[PM2] [bazarghar-web](1) ✓
requests: 16384
ok: 16001  failed: 383
status codes: {"200":16001,"502":383}
network errors: {}
worker pids seen: 33336, 33360, 29784

সত্যিকারের run, একটি local যন্ত্রে একবার মাপা; সংখ্যাগুলো সাধারণ নিয়ম নয়, শুধু এই run-এর। pm2 reload: ২৩,৭৪৫টি অনুরোধ, ব্যর্থ ০. আগের দুটি pid (12432, 6592) আর নতুন দুটি (33336, 33360) চারটিই উত্তর দিয়েছে, অর্থাৎ পুরোনো আর নতুন কিছুক্ষণ পাশাপাশি ছিল। pm2 restart: ১৬,৩৮৪টির মধ্যে ৩৮৩টি পেয়েছে 502, কারণ restart দুটি worker-কে প্রায় একসাথে থামায়, আর সেই ফাঁকে Caddy পেছনে কাউকে পায়নি। মোট অনুরোধ কম, কারণ ব্যর্থ সময়টুকুতে loop আটকে ছিল। Reload-এর আরেকটি দাম: কিছুক্ষণের জন্য মেমরিতে চারটি process, তাই ছোট VPS-এ মেমরির হিসাব রাখুন।

Reload-এর সময় ভেতরে কী ঘটে, নিচের stepper-এ দেখুন। ক্রমটি pm2-এর নথির বর্ণনা অনুযায়ী (cluster mode-এ একটি একটি করে বদলানো); pid আর শেষ সংখ্যা ওপরের run থেকে।

pm2 cluster-এর অবস্থা
id 0
id 1
অনুরোধ যায়
ব্যর্থ
  1. আগে। দুটি worker, pid 12432 আর 6592, পালা করে অনুরোধ নিচ্ছে। Load script ইতিমধ্যে চলছে।
  2. id 0-এর নতুন কপি। pm2 id 0-এর জন্য নতুন process 33336 চালু করে। সে port-এ শোনা শুরু না করা পর্যন্ত পুরোনো 12432 কাজ চালিয়ে যায়, তাই কেউ খালি হাতে ফেরে না।
  3. পুরোনোকে বিদায়। নতুনটি প্রস্তুত হলে pm2 পুরোনো 12432-কে বন্ধের সংকেত দেয়। Next.js-এর নথি অনুযায়ী সংকেত পেলে server চলমান অনুরোধ শেষ করে তবে বেরোয় (graceful shutdown, পর্ব ৩১); না বেরোলে kill_timeout-এর পর জোর করে থামানো হয়।
  4. এবার id 1. একই নাচ: 33360 ওঠে, তারপর 6592 বিদায় নেয়। এক মুহূর্তের জন্যও শোনার মতো কেউ নেই এমন অবস্থা আসেনি; এটাই restart-এর সাথে পার্থক্য।
  5. ফল। ২৩,৭৪৫টি অনুরোধ, একটিও ব্যর্থ নয়; এটি একটি local run-এর ফল। মনে রাখুন: database-এর migration পুরোনো আর নতুন দুই কোডের সাথেই চলার মতো না হলে reload নিখুঁত হলেও অ্যাপ ভাঙতে পারে। Expand-contract কৌশল পর্ব ৪০-এ; বড় পরিসরের rolling, blue-green আর canary Cloud & DevOps-এর deployment strategy পর্বে।

একটি সতর্কতা Next.js-এর জন্য। একাধিক instance চালালে নথি অনুযায়ী ISR আর data cache ডিফল্টভাবে প্রতিটি instance-এর নিজের disk বা মেমরিতে থাকে, আর revalidateTag শুধু নিজের instance-এ কাজ করে; ভাগ করা cache handler (যেমন Redis) লাগে। Server Action-এর encryption key-ও সব instance-এ এক হতে হয়, যার জন্য আছে NEXT_SERVER_ACTIONS_ENCRYPTION_KEY. একই build সব instance-এ চালালে key এক থাকে, কিন্তু আলাদা আলাদা build করলে মিলবে না। Rolling deploy-এর সময় পুরোনো পাতার সাথে নতুন server-এর অমিল (version skew) ঠেকাতে deploymentId. Environment আর secret-এর বাকি কথা পর্ব ৭৮-এ।

৬ · ডেটাবেস — managed না নিজের, আর backup

অ্যাপ server ভাঙলে আবার চালানো যায়; ডেটাবেস ভাঙলে ক্রেতার অর্ডার আর টাকার হিসাব চলে যায়। তাই কোথায় চালাবেন প্রশ্নে ডেটাবেসের সিদ্ধান্তই সবচেয়ে ভারী।

বিষয়একই VPS-এ নিজের PostgreSQLManaged database
মাসিক খরচপ্রায় শূন্য বাড়তি (VPS-এর ভেতরেই)আলাদা বিল, সাধারণত VPS-এর সমান বা বেশি
Backupআপনি লিখবেন, আপনি পরীক্ষা করবেনস্বয়ংক্রিয়, প্রায়ই point-in-time recovery-সহ
Update আর security patchআপনার দায়িত্বসেবাদাতার
Failover, replicaনিজে বানাতে হয়, কঠিনপ্রায়ই এক ক্লিকে, বাড়তি দামে
সংযোগের সীমাmax_connections নিজে ঠিক করেনপ্ল্যানের আকারে বাঁধা; pooler থাকতে পারে
Latencyএকই যন্ত্র, প্রায় শূন্যএকই region-এ রাখলে কম; ভিন্ন region-এ প্রতি query-তে বাড়তি
Extension, superuserসব পারবেনসেবাদাতা যা অনুমতি দেয়

বিস্তারিত (replica, failover, connection) Cloud & DevOps-এর Managed database পর্বে। ছোট দোকানের জন্য একটি বাস্তব মাঝামাঝি পথ: অ্যাপ VPS-এ, ডেটাবেস managed. তাতে খরচ বাড়ে, কিন্তু সবচেয়ে ঝুঁকির কাজটি, backup আর restore, অভিজ্ঞ কারও হাতে যায়।

নিজে চালালে backup-এর ন্যূনতম নিয়ম

  • প্রতিদিন dump, অন্য জায়গায়: pg_dump দিয়ে dump নিয়ে VPS-এর বাইরে, যেমন object storage-এ (পর্ব ৬৪)। একই disk-এ রাখা backup disk নষ্ট হলে সাথেই যায়।
  • কতটা হারানো চলবে, আগে ঠিক করুন: দিনে একবার dump মানে খারাপ দিনে প্রায় ২৪ ঘণ্টার অর্ডার হারাতে পারেন। এর চেয়ে কম চাইলে WAL archiving আর PITR লাগে, যা managed সেবায় সহজ। RPO আর RTO-র তত্ত্ব Backup আর disaster recovery পর্বে।
  • Restore মহড়া: মাসে অন্তত একবার নতুন একটি খালি ডেটাবেসে backup ফিরিয়ে দেখুন, আর গুনে দেখুন অর্ডারের সংখ্যা মেলে কি না। পরীক্ষা না করা backup আসলে একটি আশা মাত্র।

সংযোগের হিসাব

VPS-এ হিসাব সহজ: ২টি pm2 worker, প্রতিটিতে pool-এর আকার ১০ হলে সর্বোচ্চ ২০টি সংযোগ, সাথে worker process-এর কয়েকটি। PostgreSQL-এর ডিফল্ট max_connections ১০০, তাই অনেক জায়গা বাকি। Serverless-এ ছবিটি উল্টো: ভিড়ে platform ৫০টি কপি চালালে, প্রতিটিতে pool ৫ হলে, ২৫০টি সংযোগের চাওয়া, যা ১০০-র সীমা আড়াই গুণ ছাড়ায়। পর্ব ৩৮-এ এই সমস্যা সত্যিকারের PostgreSQL-এ ঘটিয়ে দেখানো হয়েছে, আর সমাধান: প্রতিটি কপিতে ছোট pool, আর মাঝে একটি connection pooler.

৭ · PaaS আর serverless — সুবিধা, সীমা আর cold start

PaaS: শোরুম ভাড়া

PaaS-এ আপনি repository যুক্ত করেন বা container image দেন; platform build করে, process চালায়, health check দেখে, crash হলে তোলে, TLS দেয়, আর অনেক সময় নতুন version চালু করার আগে পুরোনোটিকে রেখে দেয়। Render, Railway, Fly.io, Heroku বা DigitalOcean App Platform এমন সেবার উদাহরণ; প্রত্যেকের নিয়ম, region আর দাম আলাদা আর সময়ের সাথে বদলায়, তাই তাদের বর্তমান নথিই চূড়ান্ত। বাজারঘরের জন্য সাধারণ রূপ হলো তিনটি আলাদা জিনিস: একটি web সেবা (Next.js), একটি worker সেবা (queue-র job আর cron), আর পাশে managed PostgreSQL ও Redis. দীর্ঘজীবী process হওয়ায় WebSocket আর লম্বা job এখানে স্বাভাবিকভাবে চলে, যদি না platform নির্দিষ্ট কোনো সময়সীমা বা idle-এ ঘুম পাড়ানোর নিয়ম রাখে (কিছু সস্তা বা বিনা খরচের প্ল্যানে এমন নিয়ম থাকে)।

Serverless: মেলার স্টল

Serverless platform-এ, যেমন Vercel, Netlify, Cloudflare Workers বা AWS Lambda-ভিত্তিক সেবায়, Next.js-এর প্রতিটি dynamic route এক বা একাধিক function হয়ে যায়, আর static অংশ যায় CDN-এ। Trigger, concurrency আর সীমার তত্ত্ব Cloud & DevOps-এর Serverless function পর্বে। ফুল-স্ট্যাক ডেভেলপারের কাছে তিনটি জিনিস ভাঙে:

  • WebSocket: function একটি অনুরোধ নিয়ে একটি উত্তর দিয়ে শেষ হয়; ঘণ্টার পর ঘণ্টা খোলা সংযোগ রাখার জায়গা নেই। পর্ব ৬০-এ দেখেছেন, তখন আলাদা একটি দীর্ঘজীবী realtime সার্ভিস বা managed realtime সেবা লাগে; অনেক ক্ষেত্রে SSE (পর্ব ৬১) সহজ বিকল্প।
  • লম্বা job: প্রতিটি function-এর চলার সময়ের একটি সর্বোচ্চ সীমা থাকে, যা platform আর প্ল্যান ভেদে সেকেন্ড থেকে মিনিটের ঘরে। আট মিনিটের PDF রিপোর্ট সেখানে মাঝপথে কেটে যেতে পারে। সমাধান: কাজটি queue-তে দিন আর আলাদা worker-এ চালান (পর্ব ৬২), অথবা কাজটি ছোট টুকরোয় ভাঙুন।
  • PostgreSQL-এর সংযোগ: ওপরের হিসাব। Pooler ছাড়া serverless আর সাধারণ PostgreSQL একসাথে ভিড়ের দিনে ভাঙে।

Cold start: প্রথম ক্রেতার অপেক্ষা

অনেকক্ষণ অনুরোধ না এলে platform instance বন্ধ করে দেয়, যাতে খরচ শূন্যে নামে। পরের অনুরোধে নতুন instance চালু, runtime আর কোড load, তারপর কাজ: এই বাড়তি সময়ের নাম cold start. কতটা বাড়তি, তা platform, runtime, bundle-এর আকার আর ডেটাবেসে প্রথম সংযোগের ওপর নির্ভর করে; কিছু platform আগে থেকে গরম রাখা বা প্রস্তুত instance-এর সুবিধা দেয়। আমরা কোনো আসল platform মাপিনি, তাই নিচের মডেলের সংখ্যাগুলো ধরে নেওয়া। ধারণাটি দেখার জন্য: কম ভিড়ের API-তে cold start কত ঘন ঘন পড়ে।

// নকল ঘড়ি; সব সংখ্যা ধরে নেওয়া, মাপা নয়
const COLD_MS = 900;            // নতুন instance চালু + code load
const WARM_MS = 60;             // গরম instance-এ স্বাভাবিক কাজ
const IDLE_LIMIT_MIN = 10;      // এত মিনিট অলস থাকলে platform instance বন্ধ করে
// এক দুপুরে বাজারঘরের admin API-তে অনুরোধ আসার সময় (মিনিট)
const arrivals = [0, 1, 2, 3, 20, 21, 45, 46, 47, 48, 49, 90];

let lastSeen = -Infinity;
const lat = [];
for (const m of arrivals) {
  const cold = m - lastSeen > IDLE_LIMIT_MIN;
  const ms = cold ? COLD_MS + WARM_MS : WARM_MS;
  lat.push(ms);
  console.log(`t=${String(m).padStart(2)} min  ${cold ? 'COLD' : 'warm'}  ${ms} ms`);
  lastSeen = m;
}
const sorted = [...lat].sort((a, b) => a - b);
const pct = (q) => sorted[Math.ceil(q * sorted.length) - 1];
const mean = lat.reduce((a, b) => a + b, 0) / lat.length;
const colds = lat.filter((x) => x > WARM_MS).length;
console.log(`cold: ${colds}/${lat.length}  mean: ${mean.toFixed(0)} ms  p50: ${pct(0.5)} ms  p95: ${pct(0.95)} ms`);
console.log(`always-on server (VPS/PaaS): every request ${WARM_MS} ms`);

আউটপুটে ১২টি অনুরোধের ৪টি COLD: মিনিট 0, 20, 45 আর 90, কারণ প্রতিটির আগে ১০ মিনিটের বেশি ফাঁকা ছিল: 20 − 3 = 17, 45 − 21 = 24, 90 − 49 = 41 মিনিট। শেষ লাইন: cold: 4/12 mean: 360 ms p50: 60 ms p95: 960 ms. হিসাব: (4 × 960 + 8 × 60) / 12 = 4320 / 12 = 360. মাঝের মান (p50) ঠিকঠাক, কিন্তু ধীরতম ৫% (p95) সব cold start; সব সময় চালু server-এ প্রতিটি 60 ms. কম ভিড়ের অ্যাপে তাই cold start বেশি চোখে পড়ে, আর বেশি ভিড়ে কম, কারণ instance গরম থাকে। IDLE_LIMIT_MIN বা arrivals বদলে দেখুন। Latency-র percentile আর budget-এর হিসাব পর্ব ৮৪-এ আরও আসবে।

Lock-in আর OpenNext

Next.js আর Vercel একই প্রতিষ্ঠানের, তাই প্রশ্ন ওঠে: অন্য কোথাও কি সব সুবিধা পুরোপুরি চলে? Next.js-এর deploy নথি অনুযায়ী Node.js server বা Docker-এ চালালে সব feature সমর্থিত, static export-এ সীমিত, আর অন্য platform-এ চলে adapter দিয়ে। Next.js একটি public Deployment Adapter API দিয়েছে, যাতে platform-গুলোকে build-এর ভেতরের গঠন অনুমান করে চলতে না হয়। OpenNext হলো একটি open-source উদ্যোগ, যার নিজের বর্ণনা অনুযায়ী এর AWS, Cloudflare আর Netlify-র adapter আছে, ভিন্ন ভিন্ন দলের রক্ষণাবেক্ষণে। কোন feature কোন platform-এ কতটা চলে, তা সময়ের সাথে বদলাচ্ছে; তাই নির্দিষ্ট platform বাছার আগে সেখানে নিজের অ্যাপের ISR, Server Action, image আর proxy চালিয়ে দেখুন। Lock-in-এর আসল খরচ সাধারণত কোডে নয়, platform-এর নিজস্ব সেবায়: তাদের KV store, queue, cron বা image সেবায় যত বেশি নির্ভর করবেন, সরে যাওয়া তত কঠিন।

৮ · খরচ, domain আর বাংলাদেশ থেকে দূরত্ব

মাসিক খরচ: ধরে নেওয়া সংখ্যায়

এই কোর্স কোনো দাম ঘটনা হিসেবে বলে না, কারণ দাম বদলায়, মুদ্রার হার বদলায়, আর সেবাদাতারা প্রায়ই প্ল্যান সাজান নতুনভাবে। নিচের ক্যালকুলেটরের প্রতিটি সংখ্যা ধরে নেওয়া, কোনো vendor-এর আসল দাম নয়: 1 USD = 122 টাকা, বছরে ৬,০০০ টাকার cPanel প্ল্যান, মাসে 12 ডলারের 2 vCPU/4 GB VPS, ইত্যাদি। কাজ হলো তুলনার কাঠামো শেখা; নিজের পাওয়া দাম বসিয়ে আবার চালান। Cloud বিলের তত্ত্ব, যেমন on-demand, reserved আর data transfer, Cloud-এর বিল পর্বে।

// সব দাম ধরে নেওয়া উদাহরণ (assumption), কোনো vendor-এর আসল দাম নয়
const RATE = 122;                         // ধরে নেওয়া: 1 USD = 122 টাকা
const domain = ['domain .com', 1800 / 12, 'BDT'];   // বছরে 1800 টাকা
const plans = {
  'Shared hosting':   [['cPanel plan', 6000 / 12, 'BDT'], domain],
  'VPS, all on it':   [['VPS 2 vCPU 4 GB', 12, 'USD'], ['VPS backup', 2.4, 'USD'],
                       ['offsite DB dumps', 1, 'USD'], domain],
  'VPS + managed DB': [['VPS 2 vCPU 4 GB', 12, 'USD'], ['managed Postgres', 15, 'USD'],
                       domain],
  'PaaS':             [['web service', 7, 'USD'], ['worker service', 7, 'USD'],
                       ['managed Postgres', 15, 'USD'], ['managed Redis', 10, 'USD'], domain],
  'Serverless':       [['platform plan', 20, 'USD'], ['serverless Postgres', 19, 'USD'],
                       ['Redis per request', 5, 'USD'], domain],
};
const usdOf = ([, amount, cur]) => (cur === 'USD' ? amount : amount / RATE);

console.log('plan'.padEnd(18), 'USD/mo'.padStart(8), 'BDT/mo'.padStart(8), 'BDT/yr'.padStart(9));
for (const [name, items] of Object.entries(plans)) {
  const usd = items.reduce((sum, it) => sum + usdOf(it), 0);
  console.log(name.padEnd(18), usd.toFixed(2).padStart(8),
    String(Math.round(usd * RATE)).padStart(8), String(Math.round(usd * RATE * 12)).padStart(9));
}

আউটপুটের ছক (ধরে নেওয়া সংখ্যায়): Shared hosting 5.33 ডলার বা ৬৫০ টাকা মাসে; VPS-এ সব নিজে 16.63 ডলার বা ২,০২৯ টাকা; VPS + managed DB 28.23 ডলার বা ৩,৪৪৪ টাকা; PaaS 40.23 ডলার বা ৪,৯০৮ টাকা; Serverless 45.23 ডলার বা ৫,৫১৮ টাকা। একটি হিসাব মিলিয়ে দেখি: VPS-এ সব নিজে = 12 + 2.4 + 1 + (150 ÷ 122 = 1.23) = 16.63 ডলার, × 122 ≈ ২,০২৯ টাকা। ছকটি পড়ার তিনটি সতর্কতা। এক, সস্তার সারিগুলোতে আপনার নিজের সময়ের দাম ধরা নেই: VPS-এ update, backup-এর মহড়া আর রাত দুটোর crash আপনার। দুই, serverless-এর সারি ট্রাফিকের সাথে বদলায়; কম ভিড়ে সস্তা হতে পারে, ঈদের সেলে হঠাৎ বেশি। তিন, ডলারে বিল হলে বাংলাদেশি কার্ডে আন্তর্জাতিক লেনদেনের সীমা আর ব্যাংকের খরচ যোগ হয়, যা ব্যাংক ভেদে আলাদা।

Domain, DNS আর CDN

যেখানেই চালান, domain-এর DNS-এ কয়েকটি record লাগে: A (বা IPv6-এর AAAA) record server বা CDN-এর ঠিকানায়, www-এর জন্য CNAME, আর email-এর জন্য MX, SPF ও DKIM (পর্ব ৬৩)। PaaS বা serverless সাধারণত একটি CNAME বা নির্দিষ্ট A record দিতে বলে, আর certificate নিজেরাই নেয়। Server বদলানোর আগের দিন TTL কমিয়ে রাখলে নতুন ঠিকানা দ্রুত ছড়ায়। CDN সামনে রাখলে static ফাইল কাছের edge থেকে যায় আর VPS-এর IP লুকানো থাকে; বিস্তারিত CDN, WAF আর edge পর্বে।

বাংলাদেশ থেকে কোন region

অনেক সেবাদাতার বাংলাদেশের ভেতরে region নেই; কাছের সাধারণ পছন্দ Singapore আর Mumbai. আমরা কোনো latency মাপিনি, তাই নিচের সংখ্যা শুধু পদার্থবিদ্যার নিচের সীমা। Fiber-এ আলো মোটামুটি সেকেন্ডে ২ লাখ কিলোমিটার চলে, অর্থাৎ প্রতি মিলিসেকেন্ডে প্রায় ২০০ কিলোমিটার। Round trip-এ দূরত্ব দুবার।

ঢাকা থেকেসরলরেখায় দূরত্ব (হিসাব)সর্বনিম্ন RTT = 2 × দূরত্ব ÷ 200নতুন HTTPS সংযোগে প্রথম byte-এর আগে, ৩ RTT
Mumbai≈ ১,৮৮৭ km≈ 18.9 ms≥ 57 ms
Singapore≈ ২,৮৮৫ km≈ 28.9 ms≥ 87 ms
Frankfurt≈ ৭,৪২৬ km≈ 74.3 ms≥ 223 ms
উত্তর Virginia (US)≈ ১২,৯২৭ km≈ 129.3 ms≥ 388 ms

দূরত্ব শহরের স্থানাঙ্ক থেকে great-circle সূত্রে হিসাব করা। ৩ RTT-এর যুক্তি: TCP handshake ১, TLS 1.3 handshake ১, আর অনুরোধ-উত্তর ১. বাস্তবে cable সোজা পথে যায় না, মাঝে routing আর server-এর নিজের সময় যোগ হয়, তাই আসল সংখ্যা এর চেয়ে বেশিই হবে; কতটা বেশি, তা নিজের ISP থেকে ping বা curl -w দিয়ে মাপুন। সিদ্ধান্তের নিয়মটি অবশ্য পরিষ্কার: অ্যাপ server আর ডেটাবেস একই region-এ রাখুন, কারণ একটি পাতায় পাঁচটি query হলে সেই দূরত্ব পাঁচবার গোনা হয়।

৯ · সিদ্ধান্তের ছক

সব মিলিয়ে চারটি প্রশ্ন বেশিরভাগ সিদ্ধান্ত ঠিক করে দেয়: Node server আদৌ লাগে কি না; দীর্ঘজীবী process (WebSocket, লম্বা job) লাগে কি না; Linux চালানোর মতো কেউ আছেন কি না; আর ট্রাফিক কি স্থির, নাকি হঠাৎ লাফায়। নিচের function এই প্রশ্নগুলো একটি সরল নিয়মে বাঁধে। এটি একটি শেখার মডেল, কোনো সর্বজনীন উত্তর নয়: platform-এর সর্বোচ্চ চলার সময় আর বাজেটের সীমা এখানে ধরে নেওয়া।

// নিয়মগুলো এই পর্বের সরল সারাংশ; বাস্তবে আরও প্রশ্ন আছে
const FN_MAX_MIN = 5;   // ধরে নেওয়া: platform-এ একটি function সর্বোচ্চ কত মিনিট চলতে পারে
function choose(app) {
  if (!app.nodeServer) return ['shared hosting', 'static export or PHP is enough'];
  const longLived = app.websockets || app.longestJobMin > FN_MAX_MIN;
  if (longLived && app.linuxSkills && app.budgetUsd >= 15)
    return ['VPS + pm2 + proxy', 'long-lived process; you can run Linux'];
  if (longLived && app.budgetUsd >= 40)
    return ['PaaS (web + worker)', 'long-lived process; managed for you'];
  if (longLived) return ['rethink', 'budget too low for long-lived process'];
  if (app.spiky) return ['serverless + pooler', 'bursty traffic; watch DB connections'];
  return app.linuxSkills ? ['VPS + pm2 + proxy', 'steady traffic, cheapest per month']
                         : ['PaaS', 'steady traffic, no server to manage'];
}
const apps = [
  { name: 'catalog only', nodeServer: false },
  { name: 'shop + live chat', nodeServer: true, websockets: true, longestJobMin: 8,
    linuxSkills: true, budgetUsd: 20 },
  { name: 'shop, no ops person', nodeServer: true, websockets: true, longestJobMin: 8,
    linuxSkills: false, budgetUsd: 50 },
  { name: 'Eid flash sale API', nodeServer: true, websockets: false, longestJobMin: 1,
    linuxSkills: false, budgetUsd: 30, spiky: true },
];
for (const a of apps) {
  const [where, why] = choose(a);
  console.log(`${a.name.padEnd(20)} -> ${where.padEnd(20)} (${why})`);
}

আউটপুটের চার লাইন: শুধু ক্যাটালগ → shared hosting; দোকান + live chat, Linux জানা মানুষ, বাজেট 20 → VPS + pm2 + proxy; একই দোকান কিন্তু server দেখার কেউ নেই, বাজেট 50 → PaaS (web + worker); ঈদের flash sale-এর API, হঠাৎ ভিড়, WebSocket নেই → serverless + pooler. নিয়মের ক্রম খেয়াল করুন: দীর্ঘজীবী process-এর প্রশ্ন আগে আসে, কারণ সেটিই serverless-কে বাদ দেয়। একটি শর্ত যোগ করে দেখুন: dataMustStayInBD: true হলে কী হবে? তখন বিদেশি region-এর সব বিকল্প বাদ, আর দেশের ভেতরের data center-এর VPS বা hosting-ই পথ।

আপনার অবস্থাশুরু করার জায়গাযা খেয়াল রাখবেন
শুধু তথ্য বা ক্যাটালগ, বাজেট খুব কমShared hosting-এ static exportForm বা অর্ডার লাগলে বাইরের API
PHP দল, MySQL, প্রচলিত অ্যাপShared hosting-এ Laravelweb root শুধু public/; queue-র জন্য cron-ভিত্তিক worker
ফুল-স্ট্যাক Next.js, WebSocket, Linux জানেনএকটি VPS: Caddy বা Nginx + pm2 + PostgreSQLbackup-এর মহড়া, update, firewall
একই অ্যাপ, ops-এর মানুষ নেইPaaS-এ web + worker + managed DBমাসিক খরচ, region, idle-এ ঘুমের নিয়ম
হঠাৎ ভিড়, ছোট ছোট অনুরোধServerless + managed DB-এর poolercold start, function-এর সময়সীমা, বিলের সীমা
অনেক সেবা, দল বড়, container দরকারContainer platform বা Kubernetesপর্ব ৮০ আর Cloud & DevOps কোর্স

আরও গভীরে: Node-এর cluster module-এ primary process সংযোগ গ্রহণ করে worker-দের মধ্যে ভাগ করে (round-robin), আর Windows-এ ডিফল্টভাবে এই ভাগ OS-এর হাতে; পর্বের run-এ ঠিক সেই পার্থক্য দেখা গেছে। pm2-এর reload cluster mode-এ এই কাঠামো ব্যবহার করে নতুন worker শোনা শুরু করার পরই পুরোনোকে থামায়; fork mode-এ, অর্থাৎ একটি process হলে, এমন নিখুঁত হস্তান্তর সম্ভব নয়। Serverless-এর cold start কমাতে platform-গুলো snapshot থেকে runtime ফেরানো বা আগে থেকে প্রস্তুত instance রাখার মতো কৌশল নিয়েছে, যার খরচ আর সীমা তাদের নথিতে। আর Next.js-এর Deployment Adapter API একটি বড় পরিবর্তন: আগে প্রতিটি platform build-এর ভেতরের ফাইল পড়ে নিজের মতো বুঝত, এখন একটি ঘোষিত চুক্তি আছে।

পরীক্ষা ও ইন্টারভিউতে:

  • pm2 restart আর pm2 reload-এর পার্থক্য? restart সব process থামিয়ে আবার চালায়, মাঝে ফাঁক থাকে; cluster mode-এ reload একটি একটি করে বদলায়, নতুনটি প্রস্তুত হলে তবেই পুরোনো থামে।
  • Next.js-এর output: 'standalone' কী দেয়? শুধু দরকারি ফাইল আর একটি server.js; public আর .next/static হাতে কপি করতে হয় বা CDN-এ দিতে হয়।
  • Serverless-এ WebSocket কেন কঠিন? Function অনুরোধ-উত্তরের জন্য, স্বল্পায়ু; দীর্ঘ খোলা সংযোগ রাখার মতো process থাকে না।
  • ৫০টি function কপি, pool ৫, max_connections ১০০: সমস্যা? ২৫০টি সংযোগের চাওয়া; pool ছোট করুন আর pooler বসান।
  • Node-কে কেন 127.0.0.1-এ বাঁধবেন? যাতে শুধু reverse proxy পৌঁছাতে পারে; TLS, সীমা আর সুরক্ষা এক জায়গায় থাকে।

১০ · AI-এর যুগে deployment

“আমার Next.js অ্যাপ deploy করার ধাপ লিখে দাও” বললে AI খুব আত্মবিশ্বাসী একটি তালিকা দেয়। সমস্যা হলো, deployment-এর ভুল test-এ ধরা পড়ে না; ধরা পড়ে production-এ, ক্রেতার সামনে। AI-এর সাধারণ ভুলগুলো এই পর্বের বিষয়ের সাথে মিলিয়ে দেখুন:

AI যা প্রায়ই করেফলকীভাবে ধরবেন
পুরোনো Pages Router বা next export কমান্ডবর্তমান version-এ কমান্ডটি নেই বা অন্যভাবে চলেনিজের version-এর নথি; next build-এর আসল আউটপুট
Standalone-এ .next/static কপির কথা বাদপাতা আসে, কিন্তু CSS আর JS-এ 404ব্রাউজারের Network tab; curl -I
Node-কে 0.0.0.0-এ, firewall-এ 3000 খোলাproxy এড়িয়ে সরাসরি ঢোকার পথss -tlnp, বাইরে থেকে port যাচাই
Serverless route-এর ভেতরে Socket.IO server বা setInterval-এর cronলোকালে চলে, platform-এ নীরবে থামেplatform-এর সীমার নথি; staging-এ চালানো
config-এ আসল password, বা NEXT_PUBLIC_-এ secretsecret browser-এর bundle-এ বা repository-তেbuild-এর ফাইলে খোঁজা; পর্ব ৭৮
অচেনা pm2 option বা Caddy directive বানিয়ে লেখাচালু হয় না, বা নীরবে উপেক্ষিতcaddy validate, pm2-এর নথি

AI-কে কাজে লাগানোর ভালো উপায় হলো তাকে পরিকল্পনা লিখতে বলা নয়, আপনার পরিকল্পনার ঝুঁকি খুঁজতে বলা, আর প্রতিটি দাবির জন্য যাচাইয়ের কমান্ড চাওয়া:

আমার অ্যাপ: Next.js 16 (App Router), Prisma 7, PostgreSQL, Redis, একটি queue worker যার একটি job প্রায় ৮ মিনিট চলে, আর অর্ডারের live আপডেটের জন্য WebSocket. পরিকল্পনা: একটি VPS-এ output: 'standalone', pm2 cluster mode-এ ২টি instance, সামনে Caddy, একই VPS-এ PostgreSQL. ১. এই পরিকল্পনায় কোন কোন জায়গা ভাঙতে পারে, তালিকা দাও; প্রতিটির জন্য বলো কীভাবে আমি নিজে যাচাই করব (কমান্ড বা পরীক্ষা)। ২. কোনো option বা কমান্ড বললে, সেটি কোন version-এর নথিতে আছে বলো। নিশ্চিত না হলে "নিশ্চিত নই" লেখো। ৩. কোনো password, key বা আসল domain উদাহরণে দিও না; example-secret আর bazarghar.example ব্যবহার করো।

AI-এর deployment পরামর্শ হাতে পেলে

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।

প্র ০১“Serverless” মানে কি সত্যিই server নেই? তাহলে এর লাভ কোথায়, আর কখন এটি উল্টো ফল দেয়?

Server অবশ্যই আছে; শুধু সেটি আপনার দেখতে হয় না। নামটি ভুল বোঝার জন্যই যেন তৈরি। ২০১৪ সালে AWS যখন Lambda ঘোষণা করে, তখন নতুন ছিল দুটি জিনিস: হিসাবের একক হলো একটি অনুরোধ বা একটি function-এর চলার সময়, যন্ত্রের ঘণ্টা নয়; আর কোনো অনুরোধ না থাকলে খরচ শূন্যে নামতে পারে।

লাভ তিনটি। প্রথমত, ভিড় সামলানো platform-এর দায়িত্ব: হঠাৎ এক হাজার অনুরোধ এলে অনেক কপি চালু হয়, আপনাকে আগে থেকে যন্ত্র কিনে রাখতে হয় না। দ্বিতীয়ত, কম ব্যবহারের কাজে খরচ কম, যেমন দিনে কয়েকশো বার চলা একটি webhook. তৃতীয়ত, OS-এর patch, firewall বা process চালু রাখার ঝামেলা নেই।

উল্টো ফল আসে কয়েকটি জায়গায়। স্থির ও বেশি ট্রাফিকে প্রতি অনুরোধের দাম যোগ হতে হতে সারাক্ষণ চলা একটি যন্ত্রের চেয়ে বেশি হতে পারে; কোথায় সেই সমান-বিন্দু, তা নিজের সংখ্যায় হিসাব করতে হয়। Cold start কম ভিড়ের অ্যাপে ধীরতম অনুরোধগুলোকে আরও ধীর করে। দীর্ঘজীবী সংযোগ, যেমন WebSocket, আর লম্বা job কাঠামোর সাথেই মেলে না। আর অনেক কপি একসাথে প্রচলিত ডেটাবেসে সংযোগ খুললে সীমা ফুরিয়ে যায়; এজন্য serverless-বান্ধব ডেটাবেস আর pooler-এর আলাদা একটি বাজার তৈরি হয়েছে।

আরেকটি সূক্ষ্ম খরচ হলো স্থাপত্যের: function-এর মেমরি অনুরোধের মাঝে টিকে থাকবে, এমন ভরসা করা যায় না, তাই in-memory cache, session বা rate limit-এর গণনা বাইরের store-এ রাখতে হয়। একটি VPS-এ যা একটি Map, serverless-এ তা Redis.

মূল উপলব্ধি: serverless হলো server-এর দায়িত্ব কেনা, server বাদ দেওয়া নয়। যে কাজ ছোট, অনিয়মিত আর state ছাড়া, সেখানে এটি চমৎকার; যে কাজ দীর্ঘ, স্থির আর state-ভরা, সেখানে হিসাব করে তবে বাছুন।

প্র ০২Next.js কি শুধু তার নির্মাতার platform-এ পুরোপুরি চলে? Lock-in-এর ভয় কতটা যৌক্তিক?

প্রশ্নটি কয়েক বছর ধরে সম্প্রদায়ে বিতর্কের বিষয়। একদিকে Next.js নিজে open-source, আর এর নথি পরিষ্কার বলে Node.js server বা Docker-এ চালালে সব feature সমর্থিত। এই পর্বের ল্যাবে আমরা ঠিক সেটাই করেছি: standalone build, pm2, Caddy, আর কোনো বিশেষ platform ছাড়া পুরো অ্যাপ চলেছে।

অন্যদিকে সমস্যা আসে অন্য জায়গায়। ISR, image optimization, middleware বা proxy, আর streaming-এর মতো feature-কে serverless বা edge platform-এ চালাতে build-এর ফল ভেঙে নানা ধরনের function আর cache-এ সাজাতে হয়। বহুদিন এ কাজ প্রতিটি platform নিজে করত, Next.js-এর ভেতরের ফাইল পড়ে বুঝে, আর Next.js-এর নতুন version এলে সেই বোঝাপড়া ভেঙে যেত। এ কারণেই ২০২৩ সালের দিকে OpenNext নামের উদ্যোগ শুরু হয়, যাতে AWS-এর মতো জায়গায় Next.js চালানো যায়; এখন এর Cloudflare আর Netlify-র adapter-ও আছে বলে তাদের সাইট জানায়।

পরে Next.js একটি public Deployment Adapter API এনেছে, আর deploy নথিতে কিছু adapter-কে “verified” বলে তালিকাভুক্ত করেছে, যারা পূর্ণ compatibility test suite চালায়। দিকটি ইতিবাচক: চুক্তি লিখিত হলে platform-গুলোকে অনুমান করতে হয় না। তবে কোন feature কোথায় কতটা চলে, তা এখনো platform ভেদে আলাদা।

Lock-in-এর আসল ঝুঁকি প্রায়ই framework-এ নয়, চারপাশের সেবায়: platform-এর নিজস্ব KV store, queue, cron, analytics, বা environment ব্যবস্থাপনা। এগুলোতে যত বেশি কোড লেখা হয়, সরে যাওয়া তত কঠিন। প্রতিরোধের সহজ কৌশল: এমন সেবা একটি পাতলা নিজের interface-এর পেছনে রাখুন, আর বছরে একবার স্বাভাবিক Node server-এ চালিয়ে দেখুন অ্যাপটি এখনো চলে কি না।

মূল উপলব্ধি: lock-in পুরোপুরি এড়ানো যায় না, কিন্তু মাপা যায়। “অন্য জায়গায় সরাতে কত দিন লাগবে?” প্রশ্নের উত্তর জানা থাকলেই সিদ্ধান্তটি সচেতন।

প্র ০৩Backup থাকার পরও ডেটা হারায় কীভাবে? একটি পরিচিত ঘটনা থেকে কী শেখার আছে?

সবচেয়ে বেশি উদ্ধৃত ঘটনাগুলোর একটি GitLab-এর, ২০১৭ সালের জানুয়ারিতে। তাদের প্রকাশ্য postmortem অনুযায়ী, একজন প্রকৌশলী replication-এর একটি সমস্যা সারাতে গিয়ে ভুল server-এ ডেটাবেসের ডেটা ফোল্ডার মুছে ফেলেন। এরপর দেখা গেল, যে কয়েকটি backup ব্যবস্থার ওপর তারা ভরসা করছিলেন, তার বেশিরভাগ হয় কাজ করছিল না, নয়তো ঠিকভাবে সাজানো ছিল না; যেমন একটি backup-এর কাজ version-এর অমিলে নীরবে ব্যর্থ হচ্ছিল, আর ব্যর্থতার খবরের email পৌঁছাচ্ছিল না। শেষে একটি পুরোনো snapshot থেকে ফেরানো হয়, আর কয়েক ঘণ্টার ডেটা হারায় বলে তাঁরা জানান।

শিক্ষাগুলো বাজারঘরের মতো ছোট দোকানেও সরাসরি খাটে। প্রথমত, backup-এর কাজ চলছে মানে backup আছে নয়; ফাইলের আকার শূন্য কি না, তারিখ নতুন কি না, নিয়মিত দেখতে হয়। দ্বিতীয়ত, ব্যর্থতার খবর এমন জায়গায় যাওয়া চাই যা কেউ সত্যিই দেখেন; পর্ব ৮৩-এর monitoring এখানে লাগে। তৃতীয়ত, restore-এর মহড়া ছাড়া কেউ জানে না ফেরাতে কত সময় লাগবে।

আরেকটি শিক্ষা মানুষের ভুল নিয়ে: production আর অন্য server-এর terminal দেখতে একই হলে ভুল server-এ কমান্ড চালানো খুব সহজ। প্রম্পটে server-এর নাম রঙিন করে রাখা, ধ্বংসাত্মক কমান্ডের আগে দ্বিতীয় জনের চোখ, আর আলাদা user-এর অধিকার এমন ভুলের সম্ভাবনা কমায়।

Managed ডেটাবেস এই ঝুঁকির একটি বড় অংশ কেনার উপায়: স্বয়ংক্রিয় backup, point-in-time recovery, আর অভিজ্ঞ দলের নজর। কিন্তু সেখানেও ভুল করে টেবিল মুছে ফেললে কীভাবে ফেরাবেন, কতক্ষণ আগের পর্যন্ত ফেরানো যায়, আর সেই সুবিধা আপনার প্ল্যানে আছে কি না, তা আগে থেকে জেনে রাখতে হয়।

মূল উপলব্ধি: backup একটি ফাইল নয়, একটি অভ্যাস: নিয়মিত নেওয়া, অন্য জায়গায় রাখা, ব্যর্থ হলে জানা, আর মাঝে মাঝে ফিরিয়ে দেখা। চারটির একটি বাদ পড়লে বাকি তিনটির মূল্য কমে যায়।

প্র ০৪বাংলাদেশের একটি ছোট দোকানের জন্য দেশের ভেতরের hosting নাকি বিদেশি cloud? কোন বিষয়গুলো ওজন করবেন?

এখানে কোনো একটি সঠিক উত্তর নেই; কয়েকটি ভিন্ন দিকের ওজন আছে।

Latency: ক্রেতা বাংলাদেশে হলে server যত কাছে, round trip তত কম। পর্বের হিসাবে ঢাকা থেকে Singapore-এর সরলরেখার দূরত্বে আলোর round trip-ই প্রায় ২৯ মিলিসেকেন্ড, Virginia-তে প্রায় ১২৯; বাস্তবে দুটিই বেশি। দেশের ভেতরের data center-এ এই সংখ্যা আরও কম হওয়ার কথা, যদিও দেশের ভেতরের network-এর পথও সবসময় সোজা নয়, তাই মেপে দেখাই ভালো। CDN থাকলে static ফাইলের ক্ষেত্রে পার্থক্য অনেকটা কমে, কিন্তু dynamic পাতা আর API-তে নয়।

বিল আর টাকা: স্থানীয় hosting-এ টাকায় বিল, bKash বা ব্যাংকে পরিশোধ, ভ্যাট-সহ চালান পাওয়া সহজ হতে পারে। বিদেশি cloud-এ ডলারে বিল, আন্তর্জাতিক কার্ডের সীমা আর বিনিময় হারের ঝুঁকি।

সেবার পরিধি: বড় cloud-এ managed PostgreSQL, Redis, object storage, queue, একাধিক region সবই এক জায়গায়। স্থানীয় hosting-এর অনেকের ক্ষেত্রে মূল পণ্য shared hosting আর VPS; managed সেবার পরিসর সাধারণত ছোট। প্রতিষ্ঠান ভেদে এটি অনেক আলাদা, তাই সাধারণীকরণ না করে জিজ্ঞেস করুন।

আইন আর ডেটা: কিছু ক্ষেত্রে, যেমন সরকারি বা আর্থিক কাজে, ডেটা কোথায় রাখা যাবে তা নিয়ে নিয়ম বা চুক্তির শর্ত থাকতে পারে। এ বিষয়ে প্রতিষ্ঠানের আইনি পরামর্শ আর সংশ্লিষ্ট কর্তৃপক্ষের বর্তমান নির্দেশনাই মানদণ্ড; অনুমান করবেন না।

Support আর নির্ভরযোগ্যতা: বাংলায় ফোনে সাহায্য পাওয়ার মূল্য অনেক। অন্যদিকে বিদ্যুৎ, cooling আর একাধিক network সংযোগের ব্যবস্থা কেমন, uptime-এর কী প্রতিশ্রুতি, তা যেকোনো সেবাদাতার কাছেই লিখিতভাবে জানা দরকার।

মূল উপলব্ধি: region বাছাই মানে latency, টাকা, সেবা, আইন আর support-এর মধ্যে ভারসাম্য। নিজের ক্রেতা কোথায়, আর কোন ঝুঁকি আপনি সহ্য করতে পারবেন না, এ দুটি প্রশ্ন আগে লিখে নিলে সিদ্ধান্ত সহজ হয়।

প্র ০৫একটি VPS-এ সব কিছু চালানো কি “অপেশাদার”? কখন একটি যন্ত্র যথেষ্ট, আর কখন ভাগ করা দরকার?

সম্প্রদায়ে দুটি মত শোনা যায়। একদল বলেন, আধুনিক অ্যাপ মানেই managed সেবা, একাধিক instance আর container orchestration; আরেকদল মনে করিয়ে দেন, অনেক সফল পণ্য বহু বছর এক বা দুটি শক্তিশালী server-এ চলেছে, আর অকারণ জটিলতা নিজেই একটি ঝুঁকি। দুটি মতেই সত্য আছে।

একটি যন্ত্রের পক্ষে যুক্তি: খরচ কম আর অনুমানযোগ্য; ডেটাবেস একই যন্ত্রে থাকায় query-র network latency প্রায় শূন্য; সমস্যা হলে খোঁজার জায়গা একটি; আর এই পর্বের মতো pm2-এর cluster আর reverse proxy দিয়ে zero-downtime deploy-ও সম্ভব। বাজারঘরের মতো একটি দোকানের দিনে কয়েক হাজার ভিজিটর একটি ছোট VPS-এর জন্য সাধারণত বড় চাপ নয়, বিশেষ করে static ফাইল CDN থেকে গেলে। নিশ্চিত হতে নিজের অ্যাপে load test করে মাপুন।

একটি যন্ত্রের বিপক্ষে যুক্তি: যন্ত্রটি নিজেই single point of failure. Disk নষ্ট হলে, data center-এ বিভ্রাট হলে, বা ভুল কমান্ডে সব একসাথে যায়। ডেটাবেস আর অ্যাপ একই মেমরি ভাগ করায় একটি ভারী রিপোর্ট পুরো দোকানকে ধীর করতে পারে। আর বৃদ্ধি একটা সীমায় গিয়ে আটকায়: বড় যন্ত্রে যাওয়া (vertical scaling) একসময় ব্যয়বহুল বা অসম্ভব হয়।

ভাগ করার স্বাভাবিক ক্রমটি প্রায়ই এমন: প্রথমে ডেটাবেস আলাদা করা (managed বা নিজের আলাদা যন্ত্র), কারণ সেটিই সবচেয়ে মূল্যবান আর ভিন্ন ধরনের চাপ নেয়; তারপর static ফাইল CDN আর object storage-এ; তারপর worker আলাদা; শেষে অ্যাপের একাধিক যন্ত্র আর load balancer. প্রতিটি ধাপের আগে প্রশ্ন: কোন মাপা সমস্যা এটি সমাধান করছে? পর্ব ৮৭-এ ১০০ থেকে ১০ লাখ ব্যবহারকারীর পথে এই প্রশ্নগুলোই বিস্তারিত আসবে।

মূল উপলব্ধি: পেশাদারিত্ব মাপা হয় জটিলতার পরিমাণে নয়, ঝুঁকি বোঝায়। একটি যন্ত্র ঠিক আছে, যদি backup, monitoring আর ফেরার পরিকল্পনা থাকে; দশটি যন্ত্রও অপেশাদার, যদি কেউ না জানে কোনটি কী করছে।

অনুশীলন

হিসাব, পূর্বাভাস আর সমালোচনা; একটি কাজে নিজের সংখ্যা বসিয়ে কোড চালাতে হবে।

  1. সংযোগের হিসাব: বাজারঘরের PostgreSQL-এর max_connections ১০০, যার ৩টি superuser-এর জন্য সংরক্ষিত, আর ৫টি আপনি monitoring ও migration-এর জন্য রাখতে চান। (ক) VPS-এ ৪টি pm2 worker আর ১টি queue worker; প্রতিটির pool ১০. সীমার মধ্যে থাকবেন? (খ) একই অ্যাপ serverless-এ, ভিড়ের সময় ৪০টি কপি, প্রতিটির pool ৫. কত সংযোগ চাওয়া হবে, আর pool-এর আকার সর্বোচ্চ কত হলে সীমা মানা যাবে?

    অ্যাপের জন্য পাওয়া যাবে ১০০ − ৩ − ৫ = ৯২টি সংযোগ।

    (ক) (৪ + ১) × ১০ = ৫০. ৫০ ≤ ৯২, তাই ঠিক আছে, ৪২টি বাকি।

    (খ) ৪০ × ৫ = ২০০, যা ৯২-এর দ্বিগুণের বেশি। প্রতিটি কপির pool সর্বোচ্চ ⌊৯২ ÷ ৪০⌋ = ২. তখন ৪০ × ২ = ৮০ ≤ ৯২. কিন্তু ভিড় বেড়ে ৫০টি কপি হলে ১০০ চাওয়া হবে, আবার সীমা ছাড়াবে; তাই টেকসই সমাধান হলো pooler, যা হাজার client-কে অল্প কয়েকটি আসল সংযোগে ভাগ করে, আর platform-এ কপির সর্বোচ্চ সংখ্যা বেঁধে দেওয়া, যদি সেই সুবিধা থাকে।

  2. ফল আগে বলুন: একটি cluster-এ দুটি process: id 0 (↺ 0, pid 500) আর id 1 (↺ 0, pid 501). এই ক্রমে ঘটল: (১) id 1 নিজে থেকে crash করল, pm2 আবার চালাল; (২) pm2 reload app; (৩) id 0-এর মেমরি max_memory_restart ছাড়াল। শেষে প্রতিটির ↺ কত, আর কোনগুলোর pid নিশ্চিতভাবে বদলেছে?

    এই পর্বের সত্যিকারের run-এ দেখা গেছে crash-এর পর ↺ এক বাড়ে, আর reload-এর পরেও প্রতিটির ↺ এক বাড়ে; reload-এর আগে 1 আর 0 ছিল, পরে হলো 2 আর 1. সেই নিয়মে:

    • (১)-এর পর: id 0 ↺ 0, id 1 ↺ 1.
    • (২)-এর পর: id 0 ↺ 1, id 1 ↺ 2; দুটিরই pid নতুন।
    • (৩)-এর পর: id 0 ↺ 2, id 1 ↺ 2; id 0-এর pid আবার নতুন।

    শেষে id 0 ↺ 2, id 1 ↺ 2, আর দুটির pid-ই শুরুর 500 বা 501 নয়। নিজে যাচাই করতে আলাদা PM2_HOME দিয়ে একটি ছোট অ্যাপে ধাপগুলো চালান আর প্রতিবার pm2 ls দেখুন।

  3. পরিকল্পনার সমালোচনা: একজন সহকর্মী AI-এর সাহায্যে এই পরিকল্পনা দিয়েছেন: “পুরো বাজারঘর একটি serverless platform-এ। Socket.IO server একটি route handler-এর ভেতরে শুরু হবে। রাতের রিপোর্ট বানাতে setInterval দিয়ে ২৪ ঘণ্টা পরপর চলবে। প্রতিটি function সরাসরি PostgreSQL-এ সংযোগ খুলবে, pool ২০. ছবি সেভ হবে function-এর /tmp ফোল্ডারে।” অন্তত চারটি সমস্যা আর প্রতিটির বিকল্প লিখুন।
    • Socket.IO route handler-এ: function অনুরোধ শেষে থামে; দীর্ঘ খোলা সংযোগ টেকে না। বিকল্প: আলাদা দীর্ঘজীবী realtime সার্ভিস (VPS বা PaaS-এ), managed realtime সেবা, অথবা দরকার একমুখী হলে SSE.
    • setInterval দিয়ে cron: instance যেকোনো সময় বন্ধ হয়, একাধিক কপিতে একাধিকবার চলতে পারে, বা একবারও না। বিকল্প: platform-এর scheduled trigger, বা queue আর worker-এর repeatable job (পর্ব ৬২)।
    • Pool ২০, সরাসরি সংযোগ: কয়েক ডজন কপিতেই max_connections শেষ। বিকল্প: প্রতিটি কপিতে pool ১ বা ২, আর pooler (পর্ব ৩৮)।
    • /tmp-এ ছবি: instance-এর disk অস্থায়ী আর অন্য কপির সাথে ভাগ হয় না; ছবি হারাবে। বিকল্প: object storage আর presigned URL (পর্ব ৬৪)।
    • রাতের রিপোর্ট যদি লম্বা হয়: function-এর সর্বোচ্চ সময়সীমায় কেটে যেতে পারে; queue-তে দিয়ে worker-এ চালানো, বা টুকরোয় ভাঙা।
  4. খরচের ক্যালকুলেটর বদলান: monthly-cost.js-এ দুটি পরিবর্তন করুন: বিনিময় হার 130 টাকা, আর PaaS-এর সারি থেকে managed Redis বাদ (ধরে নিন Redis-এর কাজ PostgreSQL দিয়েই চলবে)। PaaS-এর মাসিক খরচ ডলারে আর টাকায় কত হবে? Shared hosting-এর ডলারের সংখ্যা কেন বদলাবে, টাকারটি কেন নয়?

    PaaS: 7 + 7 + 15 = 29 ডলার, আর domain 150 ÷ 130 ≈ 1.15 ডলার; মোট ≈ 30.15 ডলার। টাকায় 30.15 × 130 ≈ ৩,৯২০ টাকা (৭ + ৭ + ১৫ = ২৯ ডলারে ৩,৭৭০ টাকা, সাথে domain-এর ১৫০ টাকা)। কোড চালালে PaaS 30.15 3920 47040 জাতীয় সারি আসবে।

    Shared hosting-এর প্ল্যান টাকায় দেওয়া, তাই টাকার অঙ্ক ৬৫০-ই থাকে, কিন্তু ডলারে রূপান্তর হার বদলায়: 650 ÷ 130 = 5.00 ডলার। এটাই মুদ্রার ঝুঁকির সরল চিত্র: ডলারে বিল হলে টাকার দাম পড়লে আপনার খরচ বাড়ে, টাকায় বিল হলে নয়। সাথে খেয়াল করুন, Redis বাদ দিলে সেই কাজ (cache, rate limit, queue) কোথায় যাবে, তার নকশাও বদলাতে হবে; খরচ কমানো শুধু একটি লাইন মোছা নয়।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি VPS-এ Next.js অ্যাপ প্রথমবার চালু করার ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. output: 'standalone' দিয়ে next build
  2. public আর .next/static standalone ফোল্ডারে কপি
  3. pm2-এ cluster mode-এ 127.0.0.1-এ চালু
  4. সামনে reverse proxy, domain-এর DNS আর TLS
  5. pm2 save আর startup, যাতে reboot-এর পরও চলে

একটি অনলাইন দোকানে অর্ডারের live আপডেটের জন্য WebSocket আর ১০ মিনিটের একটি রিপোর্ট job আছে। কোন hosting-এ এগুলো সবচেয়ে কম কৌশলে স্বাভাবিকভাবে চলে?

  • cPanel-এর shared hosting
  • একটি VPS, pm2 আর reverse proxy-সহ
  • শুধু serverless function
  • Static export, CDN থেকে

Next.js-এ output: 'standalone' দিয়ে build করে node .next/standalone/server.js চালানো হলো। পাতার HTML আসে, কিন্তু সব CSS আর JS ফাইলে 404. সবচেয়ে সম্ভাব্য কারণ কী?

  • PORT environment variable ভুল
  • React-এর version মেলেনি
  • .next/static (আর public) standalone ফোল্ডারে কপি করা হয়নি
  • HOSTNAME 127.0.0.1 দেওয়া হয়েছে

দুটি worker-এর pm2 cluster-এ টানা অনুরোধ চলার সময় একবার pm2 restart আর একবার pm2 reload চালানো হলো। কোন ফল সবচেয়ে প্রত্যাশিত?

  • restart-এ কিছু 502, reload-এ ব্যর্থতা শূন্য বা প্রায় শূন্য
  • দুটিতেই সমান সংখ্যক 502
  • reload-এ বেশি 502, restart-এ শূন্য
  • কোনোটিতেই কিছু হয় না, কারণ proxy সব অনুরোধ জমিয়ে রাখে

একটি serverless API-তে ১২টি অনুরোধের ৪টি cold start (প্রতিটি 960 ms), বাকি ৮টি 60 ms. গড় latency কত?

  • 60 ms
  • 510 ms
  • 960 ms
  • 360 ms

একটি VPS-এ Next.js, PostgreSQL আর Redis একসাথে চলে। Firewall-এ বাইরে থেকে কোন port খোলা রাখা উচিত?

  • 22, 80, 443, 3000, 5432, 6379
  • শুধু 22, 80 আর 443
  • শুধু 443 আর Node-এর port
  • কোনো port খোলা রাখা উচিত নয়

ঢাকা থেকে প্রায় ২,৮৮৫ কিলোমিটার দূরের একটি server. Fiber-এ আলোর গতি প্রতি মিলিসেকেন্ডে প্রায় ২০০ কিলোমিটার ধরলে, তাত্ত্বিক সর্বনিম্ন round-trip time কত?

  • প্রায় 14.4 ms
  • প্রায় 87 ms
  • প্রায় 28.9 ms
  • প্রায় 9.6 ms

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. প্রশ্ন হলো কোন অংশ কোথায়: static ফাইল যেকোনো জায়গায়, দীর্ঘজীবী process (WebSocket, worker, লম্বা job) VPS বা PaaS-এ।
  2. Shared hosting-এ static export বা PHP স্বচ্ছন্দ; Node চলে শুধু যেখানে hosting সেই সুবিধা দেয়, আর root নেই।
  3. VPS ঠিকভাবে: standalone build, pm2 cluster, Node 127.0.0.1-এ, সামনে proxy, firewall-এ শুধু 22/80/443, আর pm2 reload.
  4. Serverless-এ cold start, সময়সীমা আর ডেটাবেস সংযোগের হিসাব; pooler ছাড়া PostgreSQL ভাঙে।
  5. খরচ আর latency ধরে নেওয়া সংখ্যা লিখে হিসাব করুন; backup তখনই আছে, যখন restore করে দেখেছেন।

পরের পর্বে: দোকান এখন চালু। কিন্তু রাত দুটোয় একটি worker বারবার crash করলে আপনি জানবেন কীভাবে? পর্ব ৮৩-এ error tracking, log আর uptime monitoring.

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান