SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-26

Docker ব্যবহার করে VPS-এ ERPNext ইনস্টল করার নিয়ম

Docker ব্যবহার করে VPS-এ ERPNext সেটআপ করার পূর্ণাঙ্গ নির্দেশিকা। এগারোটি কন্টেইনার স্ট্যাক, TLS কনফিগারেশন, ইমেইল সেটিংস এবং ভার্সন পিনিংয়ের মাধ্যমে নিরাপদ ডিপ্লয়মেন্ট নিশ্চিত করুন।

আপনি যা চালানোর জন্য প্রস্তুতি নিচ্ছেন

একটি VPS-এ ERPNext self-host করা একটি অপারেশনাল কাজ, এটি কোনো একটি কমান্ড দিয়ে ইনস্টল করার বিষয় নয়। এর অফিসিয়াল Docker Compose স্ট্যাকটি এগারোটি কন্টেইনার নিয়ে গঠিত এবং এটি আপনার প্রতিষ্ঠানের সাধারণ লেজার (general ledger) ও গ্রাহকের রেকর্ড সংরক্ষণ করে। এটি নিচের প্রতিটি বিষয়ের জন্য মানদণ্ড বাড়িয়ে দেয়: একটি ব্যাকআপ ততক্ষণ পর্যন্ত ব্যাকআপ নয় যতক্ষণ না আপনি তা সফলভাবে রিস্টোর করতে পারছেন, এবং একটি আনপিন করা (unpinned) ইমেজ ট্যাগ যেকোনো সময় স্কিমা মাইগ্রেশনের জটিলতা তৈরি করতে পারে।

পুরো প্রক্রিয়াটিতে কয়েকটি নাম বারবার আসবে। ERPNext হলো মূল বিজনেস অ্যাপ্লিকেশন। Frappe হলো এর নিচের পাইথন ফ্রেমওয়ার্ক। Bench হলো কমান্ড লাইন টুল যা সাইটগুলো পরিচালনা করে এবং এটি কন্টেইনারের ভেতরেই ইনস্টল করা থাকে। একটি site হলো একজন টেন্যান্ট: একটি MariaDB ডাটাবেস এবং আপলোড করা ফাইলগুলোর একটি ডিরেক্টরি। এখানে প্রায় প্রতিটি কমান্ডই bench কন্টেইনারের ভেতরে backend-এর মাধ্যমে একটি নির্দিষ্ট সাইটের বিপরীতে চালানো হয়।

এই নির্দেশিকাটি frappe_docker রিপোজিটরি ব্যবহার করে, যা প্রজেক্টের রক্ষণাবেক্ষণ করা ডিপ্লয়মেন্ট। নিচের প্রতিটি কমান্ড আগস্ট 2026 সালে সেই রিপোজিটরির সাথে মিলিয়ে যাচাই করা হয়েছে। যদি Docker Compose আপনার কাছে নতুন হয়, তবে VPS-এ Docker Compose চালানো বিষয়টি এই নির্দেশিকার পূর্বশর্ত হিসেবে কাজ করবে।

ERPNext-এর জন্য কতটুকু VPS প্রয়োজন?

ChartCommon published ERPNext sizing tiers (guidance, not a measurement)
The data behind this chart
[
  {
    "label": "Evaluation",
    "vcpu": 2,
    "ram_gb": 4,
    "disk_gb": 40
  },
  {
    "label": "Small production",
    "vcpu": 4,
    "ram_gb": 8,
    "disk_gb": 100
  },
  {
    "label": "Room to grow",
    "vcpu": 4,
    "ram_gb": 16,
    "disk_gb": 160
  }
]

প্রকাশিত নির্দেশিকা অনুযায়ী, কোনো ব্যবহারকারী লগ-ইন করার আগেই 2 vCPU এবং 4 GB RAM প্রয়োজন। এটি হলো ইভালুয়েশন টিয়ার বা মূল্যায়নের স্তর। এগুলো কেবল শুরুর পয়েন্ট, এই গাইডের কোনো পরিমাপ নয়; আপনার নথির পরিমাণের ওপর ভিত্তি করেই প্রকৃত প্রয়োজনীয়তা নির্ধারিত হবে। তালিকার শেষ সারিটি কোনো প্রকাশিত সর্বনিম্ন সীমা নয়। এটি এমন একটি পর্যায় যেখানে মেমোরি নিয়ে আপনাকে আর খুব বেশি ভাবতে হবে না।

ছোট প্ল্যানগুলোর ব্যাপারে বাস্তববাদী হোন। 1 GB বা 2 GB-এর একটি VPS হয়তো স্ট্যাকটি চালু করবে, কিন্তু প্রথমবার কোনো কিছু ইমপোর্ট করতে গেলে বা দীর্ঘ কোনো রিপোর্ট তৈরি করতে গেলেই তা অকেজো হয়ে পড়বে। কারণ, নয়টি দীর্ঘস্থায়ী কন্টেইনার, MariaDB-এর বাফার পুল এবং রিপোর্ট তৈরি করা একটি Python ওয়ার্কারের সম্মিলিত চাপ ওই মেমোরিতে কুলাবে না। এই ব্যর্থতা খুব একটা মসৃণভাবে হয় না। কার্নেলের আউট অফ মেমোরি কিলার (OOM killer) একটি কন্টেইনার বন্ধ করে দেয় এবং তখন সেটির ওপর docker inspect চালালে exit code 137 সহ "OOMKilled": true দেখা যায়। কাজের মাঝপথে কোনো ওয়ার্কার বন্ধ হয়ে গেলে সাবমিট করা নথির ব্যাকগ্রাউন্ড কাজ অর্ধেক সম্পন্ন অবস্থায় আটকে থাকে।

প্রতিদিন ERPNext ব্যবহার করে এমন একটি কোম্পানির জন্য 8 GB RAM, 4 vCPU এবং 100 GB SSD হলো প্রকৃত সর্বনিম্ন প্রয়োজনীয়তা। RAM সবার আগে শেষ হয়ে যায়। ডিস্কের ব্যবহার মানুষের ধারণার চেয়ে দ্রুত বৃদ্ধি পায়, কারণ প্রতিটি অ্যাটাচমেন্ট এবং লোকাল ব্যাকআপ ডাটাবেসের একই ভলিউমে জমা হয়।

এগারোটি কন্টেইনার এবং তাদের কাজ

স্ট্যাক চালু হওয়ার পর যখন নয়টি কন্টেইনার সচল থাকে, তখন docker compose ps চালান। আরও দুটি কন্টেইনার, configurator এবং create-site, তাদের কাজ একবার সম্পন্ন করে বন্ধ হয়ে যায়, যার ফলে মোট কন্টেইনারের সংখ্যা এগারোটি হয়।

  • backend কন্টেইনারটি gunicorn-এর অধীনে Frappe অ্যাপ্লিকেশন চালায়। এখানেই bench থাকে।
  • frontend হলো nginx। এটি স্ট্যাটিক অ্যাসেট পরিবেশন করে এবং বাকি সবকিছু ব্যাকএন্ডে পাঠিয়ে দেয়।
  • queue-short এবং queue-long হলো RQ (Redis Queue) ওয়ার্কার। এরা ব্যাকগ্রাউন্ড জব যেমন ইমেইল পাঠানো, ডেটা ইমপোর্ট এবং রিপোর্ট তৈরির কাজ করে।
  • scheduler সময়ভিত্তিক জবগুলো পরিচালনা করে, যার মধ্যে রয়েছে শিডিউল করা রিপোর্ট এবং অটো-রিপিট ডকুমেন্ট।
  • websocket হলো socket.io প্রসেস, যা ব্রাউজারে লাইভ আপডেট নিশ্চিত করে।
  • db হলো MariaDB।
  • redis-cache এবং redis-queue হলো দুটি আলাদা Redis ইনস্ট্যান্স, যার একটি ক্যাশের জন্য এবং অন্যটি জব কিউ-এর জন্য ব্যবহৃত হয়।

এই বিভাজনটি বোঝা জরুরি, কারণ এটি আপনাকে বলে দেয় কোন লগটি পড়তে হবে। ইমেইল আটকে গেলে সেটি একটি কিউ ওয়ার্কারের সমস্যা, তাই docker compose logs -f queue-short হলো সঠিক কমান্ড। কোনো পেজ লোড হচ্ছে কিন্তু নোটিফিকেশন ব্যাজ আপডেট হচ্ছে না, তবে সেটি একটি ওয়েব-সকেট সমস্যা। এই সমস্যাগুলোর জন্য backend লগ পড়া মানে সময়ের অপচয়।

Production compose ফাইল ব্যবহার করে ইনস্টল করুন, ডেমো ফাইল নয়

এই রিপোজিটরিতে pwd.yml থাকে এবং README-তে স্পষ্টভাবে বলা আছে: "এই সেটআপটি শুধুমাত্র স্বল্পমেয়াদী মূল্যায়নের জন্য। আপনি এই সেটআপে কোনো কাস্টম অ্যাপ ইনস্টল করতে পারবেন না।" ERPNext দেখার জন্য এটি ব্যবহার করুন, কিন্তু কোনো কোম্পানির কাজে এটি ব্যবহার করবেন না।

sudo apt update && sudo apt install -y git
curl -fsSL https://get.docker.com | bash
git clone https://github.com/frappe/frappe_docker
cd frappe_docker
mkdir -p ~/gitops
cp example.env ~/gitops/erpnext.env

~/gitops/erpnext.env খুলুন এবং চারটি ভ্যালু পরিবর্তন করুন। ERPNEXT_VERSION ইমেজ ট্যাগটি নির্দিষ্ট করে। উদাহরণ ফাইলে DB_PASSWORD হিসেবে 123 থাকে। SITES_RULE হলো Traefik রাউটিং রুল এবং LETSENCRYPT_EMAIL সার্টিফিকেট সংক্রান্ত সতর্কতা গ্রহণ করে।

ERPNEXT_VERSION=v16.32.1
DB_PASSWORD=<a long random password>
SITES_RULE=Host(`erp.example.com`)
LETSENCRYPT_EMAIL=ops@example.com

এখন একটি compose ফাইল রেন্ডার করুন এবং তারপর সেটি চালু করুন।

docker compose --project-name erpnext \
  --env-file ~/gitops/erpnext.env \
  -f compose.yaml \
  -f overrides/compose.mariadb.yaml \
  -f overrides/compose.redis.yaml \
  -f overrides/compose.https.yaml \
  config > ~/gitops/erpnext.yaml

docker compose --project-name erpnext -f ~/gitops/erpnext.yaml up -d

config নিজে থেকে কিছু শুরু করে না। এটি বেস ফাইলের সাথে ওভাররাইড ফাইলগুলোকে মার্জ করে এবং সমস্ত ভেরিয়েবল প্রতিস্থাপন করে ফলাফলটি প্রদর্শন করে। এরপর আপনি সেই রেন্ডার করা ফাইলটি চালান। এই অতিরিক্ত ধাপটি কার্যকর: চলমান স্ট্যাকটি একটি একক ফাইলে থাকে যা আপনি পড়তে এবং কমিট করতে পারেন, ফলে কেউ env ফাইল এডিট করলে বা আপনি রিপোজিটরি পুল করলে এটি নিজে থেকে পরিবর্তিত হয় না। কিভাবে একাধিক Docker Compose ফাইল মার্জ হয় সেটিতে ওভাররাইড রুলগুলো বিস্তারিতভাবে ব্যাখ্যা করা হয়েছে।

db চালু হওয়া এবং configurator বন্ধ হওয়া পর্যন্ত অপেক্ষা করুন, এতে কয়েক সেকেন্ড সময় লাগবে, তারপর সাইটটি তৈরি করুন।

docker compose --project-name erpnext exec backend \
  bench new-site --mariadb-user-host-login-scope=% \
  --db-root-password '<your DB_PASSWORD>' \
  --install-app erpnext \
  --admin-password '<a strong admin password>' \
  erp.example.com

এটি যাচাই করুন:

docker compose --project-name erpnext ps
docker compose --project-name erpnext exec backend bench --site erp.example.com list-apps

list-apps কমান্ডটি frappe এবং erpnext-এর ভার্সন প্রদর্শন করবে। একটি সুস্থ ps-এ নয়টি সার্ভিস running অবস্থায় থাকবে এবং কোনোটিই restarting অবস্থায় থাকবে না।

এখানে সাধারণত দুটি সমস্যা হয়। Docker-এর অধীনে --mariadb-user-host-login-scope=% ঐচ্ছিক নয়। অ্যাপ কন্টেইনারটি Docker নেটওয়ার্কের মাধ্যমে MariaDB-তে পৌঁছায়, তাই এটি একটি রিমোট হোস্ট হিসেবে গণ্য হয় এবং localhost-এ সীমাবদ্ধ কোনো ডাটাবেস ইউজার সেখান থেকে লগইন করতে পারে না। তখন root ইউজারকে ব্যবহার করে সাইট তৈরির সময় MariaDB access denied এরর দেখায়। % স্কোপটি নতুন সাইটের ইউজারকে সেই প্রাইভেট নেটওয়ার্কের যেকোনো হোস্ট থেকে অ্যাক্সেস করার অনুমতি দেয়।

দ্বিতীয় সমস্যাটি হলো সাইটের নাম। ফ্রন্টএন্ড ডিফল্টভাবে HTTP Host হেডার থেকে সাইট নির্বাচন করে, তাই erpnext নামে তৈরি করা একটি সাইট erp.example.com-এ অ্যাক্সেস করা যায় না, যদিও উভয়ই বিদ্যমান। সাইটের নাম ডোমেইনের সাথে মিল রেখে দিন, অথবা env ফাইলে FRAPPE_SITE_NAME_HEADER-কে সাইটের নামে সেট করুন এবং compose ফাইলটি পুনরায় রেন্ডার করুন।

HTTPS এবং এটি কাজ করার পূর্বশর্তসমূহ

compose.https.yaml ওভাররাইডটি Traefik-কে 443 পোর্টে চালায়, 80 পোর্ট থেকে ট্রাফিক রিডাইরেক্ট করে এবং Let's Encrypt থেকে সার্টিফিকেট অনুরোধ করে। TLS (transport layer security) নিশ্চিত করে যেন ইনভয়েস বা সেশন কুকি ইন্টারনেটে প্লেইন টেক্সট হিসেবে না যায়।

দুটি বিষয় অবশ্যই নিশ্চিত হতে হবে, অন্যথায় কোনো সার্টিফিকেট ইস্যু হবে না। erp.example.com-এর জন্য DNS A রেকর্ডটি অবশ্যই আগে থেকেই VPS-এর দিকে নির্দেশ করা থাকতে হবে। 80 এবং 443 পোর্ট ইন্টারনেট থেকে অ্যাক্সেসযোগ্য হতে হবে, কারণ Let's Encrypt 80 পোর্টে HTTP-01 চ্যালেঞ্জের মাধ্যমে যাচাই করে যে আপনি ডোমেইনটির নিয়ন্ত্রণ করেন কি না। আপনার প্রোভাইডারের নেটওয়ার্ক ফায়ারওয়াল এবং সার্ভারের নিজস্ব ফায়ারওয়াল—উভয়ই পরীক্ষা করুন। এগুলো আলাদা নিয়ন্ত্রণ ব্যবস্থা এবং সাধারণত মানুষ প্যানেল ফায়ারওয়ালের কথা ভুলে যায়।

সার্টিফিকেটগুলো cert-data ভলিউমের /letsencrypt/acme.json পাথ-এ জমা হয়। ব্রাউজারে যদি আপনার সার্টিফিকেটের পরিবর্তে ডিফল্ট সার্টিফিকেট দেখায়, তবে docker compose --project-name erpnext ps থেকে প্রক্সি সার্ভিসের নাম খুঁজে বের করুন এবং ACME (automatic certificate management environment) এরর দেখার জন্য এর লগ পড়ুন। একই সার্ভারে অন্য ওয়েব অ্যাপ চালাচ্ছেন? একাধিক Docker Compose অ্যাপের সামনে একটি Traefik ইনস্ট্যান্স দেখাচ্ছে কীভাবে 443 পোর্টের দখল নিয়ে সংঘাত না করে প্রক্সিকে শেয়ার করা যায়। এই ধরনের সার্ভারে দ্বিতীয় অ্যাপটি প্রায়শই গ্রাহককেন্দ্রিক হয় এবং একটি self-hosted Chatwoot সাপোর্ট ডেস্ক সেই একই প্রক্সির পেছনে থাকে, যাতে যারা ইনভয়েস নিয়ে কাজ করেন তারা একই জায়গা থেকে গ্রাহকের ইমেইল এবং চ্যাটের উত্তর দিতে পারেন।

আউটবাউন্ড ইমেইল, অথবা ইনভয়েসগুলো সার্ভার থেকে বের হচ্ছে না

এটি এমন একটি ধাপ যা বেশিরভাগ ERPNext গাইডে এড়িয়ে যাওয়া হয়, অথচ সিস্টেমটি কার্যকর হবে কি না তা এই ধাপটিই নির্ধারণ করে। আউটবাউন্ড মেইল কাজ না করলে কোনো ইনভয়েস গ্রাহকের কাছে পৌঁছাবে না, পাসওয়ার্ড রিসেট ইমেইল আসবে না এবং কোনো নির্ধারিত রিপোর্টও পাঠানো সম্ভব হবে না। এই স্ট্যাকে কোনো মেইল সার্ভার অন্তর্ভুক্ত নেই।

VPS থেকে সরাসরি port 25 ব্যবহার করে মেইল পাঠানোর চেষ্টা করবেন না। বেশিরভাগ প্রোভাইডার নতুন অ্যাকাউন্টের ক্ষেত্রে আউটবাউন্ড port 25 ব্লক করে রাখে। আর যা-ও বা বের হয়, তা প্রত্যাখ্যাত হয় অথবা স্প্যাম হিসেবে গণ্য হয়, কারণ একটি নতুন VPS অ্যাড্রেসের কোনো সেন্ডিং রেপুটেশন থাকে না। port 587-এ একটি অথেন্টিকেটেড রিলে ব্যবহার করুন।

সমর্থিত পদ্ধতি হলো ERPNext ইন্টারফেসের Email Account স্ক্রিন ব্যবহার করা, যা পাসওয়ার্ড এনক্রিপ্ট করে সংরক্ষণ করে। আপনি চাইলে site config-এও কি (key) গুলো লিখে রাখতে পারেন:

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com set-config mail_server smtp.example.com

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com set-config mail_port 587 --parse

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com set-config use_tls 1 --parse

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com set-config mail_login 'erp@example.com'

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com set-config auto_email_id 'erp@example.com'

--parse, "587" স্ট্রিংয়ের পরিবর্তে 587-কে সংখ্যা হিসেবে সংরক্ষণ করে। ফাইলটি পুনরায় পড়ুন এবং নিশ্চিত করুন যে এই দুটি মানের চারপাশে কোনো উদ্ধৃতি চিহ্ন (quotes) নেই:

docker compose --project-name erpnext exec backend \
  cat sites/erp.example.com/site_config.json

mail_password-কে কমান্ড লাইনের পরিবর্তে Email Account স্ক্রিনের মাধ্যমে সেট করুন, যাতে এটি এনক্রিপ্ট করা অবস্থায় থাকে এবং কখনোই আপনার শেল হিস্ট্রিতে না আসে।

এরপর একটি আসল মেসেজ পাঠান। একটি Sales Invoice তৈরি করুন, আপনার নিয়ন্ত্রণে থাকা একটি ঠিকানায় সেটি ইমেইল করুন এবং পাঠানোর সময় কিউ (queue) পর্যবেক্ষণ করুন:

docker compose --project-name erpnext logs -f queue-short

আউটগোয়িং মেইল একটি ব্যাকগ্রাউন্ড জব, তাই কোনো মেসেজ না পৌঁছালে তা সাধারণত ব্রাউজারে এরর হিসেবে না দেখিয়ে ওই লগে একটি ফেইলড জব হিসেবে দেখা যায়। সেন্ডিং ডোমেইনের জন্য SPF (sender policy framework) এবং DKIM (domainkeys identified mail) রেকর্ড প্রকাশ করুন, এবং তারপর একটি DMARC পলিসি যোগ করুন। এগুলো ছাড়া প্রযুক্তিগতভাবে সঠিক ইনভয়েসও গ্রাহকের স্প্যাম ফোল্ডারে চলে যেতে পারে। আপনি যদি পুরো পথটি নিজের নিয়ন্ত্রণে রাখতে চান, তবে একটি self-hosted Mailcow মেইল সার্ভার আপনাকে এমন একটি রিলে দেয় যা আপনার নিয়ন্ত্রণে থাকে এবং এটি ERP থেকে আলাদা একটি বক্সে থাকে।

যে ব্যাকআপ প্রকৃতপক্ষে রিস্টোর করা যায়

শুধুমাত্র একটি ডাটাবেস ডাম্প ERPNext-এর পূর্ণাঙ্গ ব্যাকআপ নয়। অ্যাটাচমেন্ট এবং ব্যক্তিগত ফাইলগুলো MariaDB-তে নয়, বরং sites ডিরেক্টরিতে থাকে। শুধুমাত্র ডাটাবেস রিস্টোর করলে প্রতিটি আপলোড করা পারচেজ অর্ডার ব্রোকেন লিঙ্ক হিসেবে দেখাবে।

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com backup --with-files

এটি sites ভলিউমের ভেতরে sites/erp.example.com/private/backups ডিরেক্টরিতে চারটি ফাইল তৈরি করে:

  • একটি -database.sql.gz ডাম্প
  • পাবলিক ফাইলগুলোর একটি -files.tar আর্কাইভ
  • ব্যক্তিগত ফাইলগুলোর একটি -private-files.tar আর্কাইভ
  • সাইট কনফিগারেশনের একটি -site_config_backup.json কপি

চতুর্থ ফাইলটি মানুষ প্রায়ই ফেলে দেয়, আর এটিই সবচেয়ে গুরুত্বপূর্ণ। এতে encryption_key থাকে, যা Frappe সংরক্ষিত পাসওয়ার্ড এনক্রিপ্ট করতে ব্যবহার করে: ইমেইল অ্যাকাউন্টের ক্রেডেনশিয়াল, পেমেন্ট গেটওয়ের কি (key), এবং প্রতিটি ইন্টিগ্রেশন সিক্রেট। সঠিক কি (key) ছাড়া ডাটাবেস রিস্টোর করলে সাইট স্বাভাবিকভাবে লোড হবে, কিন্তু ইমেইল পাঠানোর সময় নিচের এররটি দেখাবে:

frappe.exceptions.ValidationError: Encryption key is invalid! Please check site_config.json

চারটি ফাইল সবসময় একসাথে রাখুন।

এরপর এগুলো সার্ভার থেকে সরিয়ে ফেলুন। ভলিউমের ভেতরে রাখা ব্যাকআপ সার্ভার নষ্ট হয়ে গেলে আর পাওয়া যাবে না, তাছাড়া bench এমনিতেই এগুলো মুছে ফেলে: ডিফল্টভাবে এটি ওই ডিরেক্টরি থেকে 24 ঘণ্টার বেশি পুরনো ব্যাকআপ ডিলিট করে দেয়।

docker compose --project-name erpnext cp \
  backend:/home/frappe/frappe-bench/sites/erp.example.com/private/backups \
  ~/erpnext-backups

এটি cron থেকে চালান, তারপর ডিরেক্টরিটিকে এমন কোথাও পাঠান যা আপনি নিজে পরিচালনা করেন না। অফ-সাইট স্টোরেজে এনক্রিপ্টেড restic ব্যাকআপ এর জন্য সঠিক টুল, কারণ এটি আপলোডের আগেই এনক্রিপ্ট করে এবং restic check প্রমাণ করে যে রিপোজিটরি এখনো পড়ার যোগ্য। একটি ERP ব্যাকআপ আপনার পুরো লেজারের কপি, তাই এটি এই হার্ডওয়্যার থেকে ভিন্ন কোনো হার্ডওয়্যারে এনক্রিপ্ট করে রাখা উচিত।

প্রয়োজনের আগেই রিস্টোর পরীক্ষা করুন

পরীক্ষা না করা ব্যাকআপ কেবল একটি অনুমান। এটিকে একই সার্ভারের অন্য একটি সাইটে রিস্টোর করে পরীক্ষা করুন, কখনোই সরাসরি লাইভ সাইটে করবেন না।

docker compose --project-name erpnext exec backend \
  bench new-site --mariadb-user-host-login-scope=% \
  --db-root-password '<your DB_PASSWORD>' \
  --admin-password '<a strong admin password>' \
  restore-test.example.com

docker compose --project-name erpnext exec backend \
  bench --site restore-test.example.com --force restore \
  sites/erp.example.com/private/backups/<stamp>-erp.example.com-database.sql.gz \
  --with-public-files sites/erp.example.com/private/backups/<stamp>-erp.example.com-files.tar \
  --with-private-files sites/erp.example.com/private/backups/<stamp>-erp.example.com-private-files.tar \
  --db-root-password '<your DB_PASSWORD>'

এনক্রিপশন কি (encryption key) ব্যাকআপ করা কনফিগারেশন থেকে কপি করে রিস্টোর করা সাইটে বসান, অন্যথায় এর ইন্টিগ্রেশনগুলো অকেজো হয়ে থাকবে:

docker compose --project-name erpnext exec backend \
  bench --site restore-test.example.com set-config encryption_key '<value from site_config_backup.json>'

এখন একজন হিসাবরক্ষকের মতো রিস্টোর করা ডেটা যাচাই করুন। Accounts Receivable রিপোর্ট খুলুন এবং ক্লোজিং ব্যালেন্সের সাথে লাইভ সাইটের ব্যালেন্স মিলিয়ে দেখুন। সাম্প্রতিক একটি পারচেজ ইনভয়েস খুলুন এবং এর অ্যাটাচমেন্ট ডাউনলোড করুন। শুধু লগইন পেজ দেখা যাচ্ছে মানেই সাইট ঠিক আছে, এমনটি ভাবার কোনো কারণ নেই।

কাজ শেষ হলে টেস্ট সাইটটি মুছে ফেলুন:

docker compose --project-name erpnext exec backend \
  bench drop-site restore-test.example.com

কেন ERPNext-এর ক্ষেত্রে version pinning অত্যন্ত গুরুত্বপূর্ণ

একটি static সাইটে unpinned image tag থাকার অর্থ হলো একটি অপ্রত্যাশিত রিস্টার্ট। কিন্তু ERPNext-এর ক্ষেত্রে এর অর্থ হলো একটি schema migration। bench migrate ডাটাবেস টেবিলগুলোকে নতুন করে লেখে এবং এটি document data-কেও পরিবর্তন করতে পারে, যার কোনো undo অপশন নেই। এক্ষেত্রে রোলব্যাক করার অর্থ হলো ব্যাকআপ থেকে রিস্টোর করা, কোনো docker compose down নয়।

তাই tag-টিকে পিন করে রাখুন। ERPNEXT_VERSION=v16.32.1 ছিল সেই রিলিজ যা 2026 সালের আগস্ট মাসে রিপোজিটরির নিজস্ব pwd.yml-এ পিন করা ছিল। যাচাই না করে সেই নম্বরটি সামনে এগিয়ে নেবেন না। বর্তমান রিলিজগুলো frappe/erpnext releases page-এ তালিকাভুক্ত আছে এবং বিদ্যমান image tag-গুলো Docker Hub-এ পাওয়া যাবে। যে ভার্সনে আপনি যেতে চাচ্ছেন, সেটির নোটগুলো আগে পড়ে নিন।

আপগ্রেড প্রক্রিয়াটি শুরু হয় একটি ব্যাকআপ এবং maintenance mode-এর মাধ্যমে।

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com backup --with-files

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com set-maintenance-mode on

~/gitops/erpnext.env-এর মধ্যে ERPNEXT_VERSION এডিট করুন, তারপর render, pull এবং migrate করুন।

docker compose --project-name erpnext \
  --env-file ~/gitops/erpnext.env \
  -f compose.yaml \
  -f overrides/compose.mariadb.yaml \
  -f overrides/compose.redis.yaml \
  -f overrides/compose.https.yaml \
  config > ~/gitops/erpnext.yaml

docker compose --project-name erpnext -f ~/gitops/erpnext.yaml pull
docker compose --project-name erpnext -f ~/gitops/erpnext.yaml up -d

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com migrate

docker compose --project-name erpnext exec backend \
  bench --site erp.example.com set-maintenance-mode off

Maintenance mode গুরুত্বপূর্ণ কারণ migrate চলার সময় schema পরিবর্তন করে। কোনো ইউজার যদি অর্ধেক মাইগ্রেট হওয়া টেবিলের ওপর কোনো ডকুমেন্ট সাবমিট করে, তবে আপনাকে হাতে ধরে রেকর্ড মেরামত করতে হবে।

একবারে একটি major ভার্সন পরিবর্তন করুন এবং প্রতিটি ধাপের মাঝে ব্যাকআপ রাখুন। একটি রিলিজের মাইগ্রেশন কোড তার আগের রিলিজ থেকে আপগ্রেড করার জন্য লেখা হয়, তাই major ভার্সন বাদ দিয়ে সরাসরি আপগ্রেড করলে এমন সব মাইগ্রেশন রান হতে পারে যা কেউ পরীক্ষা করেনি।

এই রিপোজিটরি overrides/compose.migrator.yaml-ও সরবরাহ করে, যা প্রতিটি স্টার্টের সময় bench --site all migrate রান করার জন্য একটি কন্টেইনার যোগ করে। এটি সুবিধাজনক। তবে এর অর্থ হলো, একটি পরিবর্তিত tag-সহ docker compose up আপনার প্রোডাকশন ডাটাবেসকে কারো নজরদারি ছাড়াই মাইগ্রেট করে ফেলবে। একটি ব্যবসায়িক সিস্টেমের ক্ষেত্রে, migrate রান করার সিদ্ধান্তটি সেই সকালে আপনার নিজের নেওয়া উচিত।

গ্রাহকের রেকর্ড ধারণকারী সার্ভার সুরক্ষিত করা

প্রথমবার লগইন করার সময় Administrator পাসওয়ার্ড পরিবর্তন করুন। ইভালুয়েশন compose ফাইলে admin পাসওয়ার্ড হিসেবে থাকে এবং এই অভ্যাসটি অনেকেই প্রোডাকশন এনভায়রনমেন্টেও বজায় রাখেন।

example.env ফাইলে 123 থেকে DB_PASSWORD পরিবর্তন করুন। এই মানটি রেন্ডার করা ~/gitops/erpnext.yaml ফাইলে প্লেইন টেক্সট হিসেবে থেকে যায়, তাই ফাইলটিকে chmod 600 করুন এবং কোনো git রিপোজিটরিতে এটি রাখবেন না। আরও শক্তিশালী নিরাপত্তার জন্য, overrides/compose.mariadb-secrets.yaml এনভায়রনমেন্ট ভেরিয়েবলের পরিবর্তে Docker secret ফাইল থেকে পাসওয়ার্ড পড়ে। Docker Compose-এ env ফাইল এবং সিক্রেট পরিচালনা অংশে এর সুবিধা ও অসুবিধাগুলো আলোচনা করা হয়েছে।

শুধুমাত্র প্রয়োজনীয় পোর্টগুলো উন্মুক্ত রাখুন। HTTPS ওভাররাইড ব্যবহারের ক্ষেত্রে শুধুমাত্র 80 এবং 443 পোর্ট উন্মুক্ত থাকে। ডাটাবেস ক্লায়েন্টের সংযোগ সহজ করার জন্য db সার্ভিসে কোনো ports ম্যাপিং যোগ করবেন না: এটি MariaDB-কে পাবলিক ইন্টারনেটে উন্মুক্ত করে দেয়। এর পরিবর্তে docker compose --project-name erpnext exec backend bench mariadb ব্যবহার করুন। হোস্ট মেশিনে শুধুমাত্র 22, 80 এবং 443 পোর্ট অনুমতি দিন, বাকিগুলো বন্ধ রাখুন এবং প্রোভাইডারের আলাদা নেটওয়ার্ক ফায়ারওয়ালও পরীক্ষা করুন।

System Manager রোলধারী প্রতিটি অ্যাকাউন্টের জন্য System Settings থেকে টু-ফ্যাক্টর অথেন্টিকেশন চালু করুন। এই রোলটি প্রতিটি ডকুমেন্ট পড়তে এবং প্রতিটি টেবিল এক্সপোর্ট করতে পারে, তাই এটিকে সাধারণ অ্যাকাউন্টের পরিবর্তে একজন অ্যাডমিনিস্ট্রেটর অ্যাকাউন্ট হিসেবে বিবেচনা করুন। আপনি যদি একাধিক self-hosted অ্যাপ চালান, তবে প্রতিটির জন্য আলাদা পাসওয়ার্ড ব্যবহারের চেয়ে Authentik-কে self-hosted সিঙ্গেল সাইন-অন প্রোভাইডার হিসেবে ব্যবহার করা বেশি কার্যকর।

হোস্ট মেশিন প্যাচ করুন এবং কার্নেল আপডেটের জন্য রিবুট করুন। স্ট্যাকটি স্বয়ংক্রিয়ভাবে চালু হবে কি না তা নিশ্চিত করার আগে প্রতিটি সার্ভিসের জন্য রেন্ডার করা ফাইলে restart পলিসি পরীক্ষা করুন, কারণ এটি ছাড়া রিবুটের পর স্ট্যাকটি বন্ধই থাকবে। রিবুটের পর Docker Compose স্ট্যাক পুনরায় চালু করা অংশে systemd-এর দিকগুলো আলোচনা করা হয়েছে।

যখন একটি VPS-এ ERPNext আর স্বাচ্ছন্দ্যে চলে না

একটি VPS দীর্ঘ সময় ধরে একটি ছোট কোম্পানির কাজের চাপ সামলাতে পারে। যখন এটি আর পারে না, তখন কিছু লক্ষণ দেখা দেয়:

  • ব্যাকগ্রাউন্ড জবগুলো জমতে থাকে, ফলে ইমেইল এবং ইমপোর্ট কয়েক মিনিট বা কয়েক ঘণ্টা দেরিতে পৌঁছায়।
  • docker inspect কন্টেইনারগুলো "OOMKilled": true বা exit code 137 প্রদর্শন করে।
  • যে রিপোর্টগুলো আগে দুই সেকেন্ডে তৈরি হতো, এখন তা ত্রিশ সেকেন্ড সময় নেয় এবং MariaDB প্রসেসটি CPU-এর বেশিরভাগ অংশ দখল করে রাখে।
  • ব্যাকআপ প্রক্রিয়া এত দীর্ঘ হয় যে একটি শেষ হওয়ার আগেই পরবর্তী নির্ধারিত ব্যাকআপ শুরু হয়ে যায়।

শুরুতেই MariaDB-কে এমন রিসোর্স দিন যা অন্য কোনো প্রসেসের সাথে শেয়ার করতে হয় না, কারণ ডাটাবেস এবং Python ওয়ার্কাররা একই মেমরির জন্য প্রতিযোগিতা করে এবং buffer pool-এর জন্য আরও বেশি মেমরি প্রয়োজন হয়। অ্যাপ্লিকেশন সার্ভারের আকার বাড়ানো প্রত্যাশার তুলনায় কম কার্যকর। ডাটাবেসকে Docker-এ বা সরাসরি host-এ চালানো এই সিদ্ধান্ত নিতে সাহায্য করবে এবং Docker Compose-এ মেমরি লিমিট সেট করা একটি কন্টেইনারকে অন্যগুলোর রিসোর্স কেড়ে নেওয়া থেকে বিরত রাখবে।

এরপরে, ওয়েব ক্যাপাসিটি বাড়ানোর চেয়ে কিউ ওয়ার্কার (queue workers) যোগ করুন। ERPNext-এর ধীরগতির কাজগুলো মূলত ব্যাকগ্রাউন্ডে হয়: রিপোর্ট জেনারেশন এবং বাল্ক ইমপোর্ট। একটি বড় সার্ভারের চেয়ে একাধিক ওয়ার্কার কন্টেইনার চালানো সাশ্রয়ী এবং এটি ব্যবহারকারীদের অভিযোগের মূল কারণগুলো সমাধান করে।

FAQ

VPS-এ ERPNext চালানোর জন্য কতটুকু RAM প্রয়োজন?

প্রকাশিত নির্দেশিকা অনুযায়ী 4 GB RAM এবং 2 vCPU দিয়ে শুরু করার পরামর্শ দেওয়া হয়, তবে এই কনফিগারেশনটি শুধুমাত্র মূল্যায়নের জন্য। দৈনন্দিন ব্যবহারের জন্য 8 GB RAM, 4 vCPU এবং 100 GB SSD রাখার পরিকল্পনা করুন। এর চেয়ে কম রিসোর্স থাকলে লোড বাড়লে কার্নেলের out of memory killer কন্টেইনারগুলোকে বন্ধ করে দেয়, যা docker inspect-এ "OOMKilled": true এবং exit code 137 হিসেবে দেখা যায়। এগুলো প্রাথমিক ধারণা মাত্র, তাই প্রথম মাস ব্যবহারের সময় আপনার সার্ভারের মেমোরি ব্যবহারের দিকে নজর রাখুন।

আমি কি প্রোডাকশনে pwd.yml চালাতে পারি?

না। প্রজেক্টের README-তে বলা হয়েছে এটি শুধুমাত্র স্বল্পস্থায়ী মূল্যায়নের জন্য, এবং এতে কোনো কাস্টম অ্যাপ ইনস্টল করা যায় না। MariaDB, Redis এবং HTTPS ওভাররাইডসহ compose.yaml ব্যবহার করুন, docker compose config দিয়ে সেগুলোকে একটি ফাইলে রেন্ডার করুন এবং সেই ফাইলটি রান করুন।

ERPNext সাইট তৈরির পরপরই কেন তা অ্যাক্সেস করা যাচ্ছে না?

ফ্রন্টএন্ড ডিফল্টভাবে HTTP Host হেডার দেখে নির্ধারণ করে কোন সাইটটি সার্ভ করতে হবে, তাই ব্রাউজারের ডোমেইনের সাথে সাইটের নামের মিল থাকতে হবে। erpnext নামে তৈরি করা সাইট erp.example.com-এ সার্ভ হবে না। হয় ডোমেইন নাম ব্যবহার করে সাইটটি তৈরি করুন, অথবা env ফাইলে FRAPPE_SITE_NAME_HEADER-এ সাইটের নামটি সেট করুন, এরপর কম্পোজ ফাইলটি পুনরায় রেন্ডার করে স্ট্যাকটি রিস্টার্ট করুন।

ERPNext ব্যাকআপে কী কী থাকা আবশ্যক?

চারটি ফাইল একসাথে রাখতে হবে: -database.sql.gz ডাম্প, -files.tar এবং -private-files.tar আর্কাইভ, এবং -site_config_backup.json কনফিগারেশন কপি। bench --site erp.example.com backup --with-files রান করলে এই চারটি ফাইলই তৈরি হয়। কনফিগারেশন কপিতে encryption_key থাকে, তাই এটি ছাড়া রিস্টোর করলে সংরক্ষিত ইন্টিগ্রেশন পাসওয়ার্ডগুলো ডিক্রিপ্ট করা যায় না, যা Encryption key is invalid! Please check site_config.json হিসেবে দেখা দেয়।

ডেটা নষ্ট না করে কীভাবে ERPNext আপগ্রেড করব?

--with-files দিয়ে ব্যাকআপ নিন, মেইনটেন্যান্স মোড চালু করুন, আপনার env ফাইলে ERPNEXT_VERSION পরিবর্তন করুন, কম্পোজ ফাইলটি পুনরায় রেন্ডার করুন, pull করুন, স্ট্যাকটি আপ করুন এবং তারপর bench --site erp.example.com migrate রান করে মেইনটেন্যান্স মোড বন্ধ করুন। একবারে একটি মেজর ভার্সন আপগ্রেড করুন এবং আগে রিলিজ নোটগুলো পড়ে নিন, কারণ migrate স্কিমা এবং ডকুমেন্ট ডেটা পরিবর্তন করে ফেলে যা আর আগের অবস্থায় ফিরিয়ে আনা যায় না। রোলব্যাক করার একমাত্র উপায় হলো শুরুতে নেওয়া ব্যাকআপটি রিস্টোর করা।