VPS-এ Docker দিয়ে 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 প্রয়োজন?
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 ওয়ার্কারের সম্মিলিত চাপ এই মেমোরিতে কুলাবে না। এই ব্যর্থতা খুব একটা মসৃণভাবে হয় না। কার্নেলের out of memory 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-এর লগ পড়া কেবল সময়ের অপচয়।
ডেমো নয়, প্রোডাকশন কম্পোজ ফাইল ব্যবহার করে ইনস্টল করুন
এই রিপোজিটরিতে 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এখন একটি কম্পোজ ফাইল রেন্ডার করুন, তারপর সেটি চালু করুন।
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 -dconfig নিজে থেকে কিছু শুরু করে না। এটি বেস ফাইলের সাথে ওভাররাইড ফাইলগুলোকে একত্রিত করে এবং সমস্ত ভেরিয়েবল প্রতিস্থাপিত করে ফলাফল প্রদর্শন করে। এরপর আপনি সেই রেন্ডার করা ফাইলটি চালান। এই অতিরিক্ত ধাপটি কার্যকর: চলমান স্ট্যাকটি একটি একক ফাইল হিসেবে থাকে যা আপনি পড়তে এবং কমিট করতে পারেন, ফলে কেউ 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-appslist-apps কমান্ডটি frappe এবং erpnext এর ভার্সন প্রদর্শন করবে। একটি সুস্থ ps-এ নয়টি সার্ভিস running অবস্থায় থাকবে এবং কোনোটিই restarting অবস্থায় থাকবে না।
এখানে সাধারণত দুটি সমস্যা হয়। Docker-এর অধীনে --mariadb-user-host-login-scope=% ঐচ্ছিক নয়। অ্যাপ কন্টেইনারটি Docker নেটওয়ার্কের মাধ্যমে MariaDB-তে পৌঁছায়, তাই এটি একটি রিমোট হোস্ট হিসেবে গণ্য হয় এবং localhost-এ সীমাবদ্ধ কোনো ডাটাবেস ইউজার সেখান থেকে লগইন করতে পারে না। তখন root ইউজারকে ব্যবহার করে সাইট তৈরির সময় MariaDB অ্যাক্সেস ডিনাইড এরর দেখায়। % স্কোপ নতুন সাইটের ইউজারকে সেই প্রাইভেট নেটওয়ার্কের যেকোনো হোস্ট থেকে অ্যাক্সেস করার অনুমতি দেয়।
দ্বিতীয় সমস্যাটি হলো সাইটের নাম। ফ্রন্টএন্ড ডিফল্টভাবে HTTP Host হেডার থেকে সাইট নির্বাচন করে, তাই erpnext নামে তৈরি করা সাইট erp.example.com ঠিকানায় পাওয়া যাবে না, যদিও উভয়ই বিদ্যমান। সাইটের নাম ডোমেইনের সাথে মিলিয়ে রাখুন, অথবা env ফাইলে FRAPPE_SITE_NAME_HEADER-কে সাইটের নামে সেট করুন এবং কম্পোজ ফাইলটি পুনরায় রেন্ডার করুন।
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 পোর্টের দখল নিয়ে সংঘাত না করে কীভাবে প্রক্সিকে শেয়ার করা যায় তা দেখানো হয়েছে।
আউটবাউন্ড ইমেইল, অথবা ইনভয়েস সার্ভার থেকে বের না হওয়া
এটি এমন একটি ধাপ যা বেশিরভাগ 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.jsonmail_password-কে কমান্ড লাইনের পরিবর্তে Email Account স্ক্রিনের মাধ্যমে সেট করুন, যাতে এটি এনক্রিপ্ট করা অবস্থায় সংরক্ষিত থাকে এবং কখনোই আপনার শেল হিস্ট্রিতে না আসে।
এরপর একটি আসল বার্তা পাঠান। একটি Sales Invoice তৈরি করুন, আপনার নিয়ন্ত্রণে থাকা একটি ঠিকানায় সেটি ইমেইল করুন এবং পাঠানোর সময় কিউ (queue) পর্যবেক্ষণ করুন:
docker compose --project-name erpnext logs -f queue-shortআউটগোয়িং মেইল একটি ব্যাকগ্রাউন্ড জব, তাই যে বার্তাটি পৌঁছায় না তা সাধারণত ব্রাউজারে কোনো ত্রুটি হিসেবে না দেখিয়ে এই লগে একটি ফেইলড জব হিসেবে দেখা যায়। সেন্ডিং ডোমেইনের জন্য SPF (sender policy framework) এবং DKIM (domainkeys identified mail) রেকর্ড প্রকাশ করুন, এবং তারপর একটি DMARC পলিসি যোগ করুন। এগুলো ছাড়া কারিগরিভাবে সঠিক ইনভয়েসও গ্রাহকের স্প্যাম ফোল্ডারে চলে যেতে পারে। আপনি যদি পুরো পথটি নিজের নিয়ন্ত্রণে রাখতে চান, তবে একটি সেলফ-হোস্টেড 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) অত্যন্ত গুরুত্বপূর্ণ
একটি স্ট্যাটিক সাইটে আনপিন করা ইমেজ ট্যাগ মানে কেবল একটি অপ্রত্যাশিত রিস্টার্ট। কিন্তু ERPNext-এর ক্ষেত্রে এর অর্থ হলো একটি স্কিমা মাইগ্রেশন। bench migrate ডাটাবেস টেবিলগুলোকে নতুন করে লেখে এবং ডকুমেন্ট ডাটা পরিবর্তন করতে পারে, যার কোনো undo অপশন নেই। এক্ষেত্রে রোলব্যাক করার অর্থ হলো ব্যাকআপ থেকে রিস্টোর করা, কোনো docker compose down নয়।
তাই ট্যাগটি পিন করে রাখুন। ERPNEXT_VERSION=v16.32.1 ছিল 2026 সালের আগস্ট মাসে রিপোজিটরির নিজস্ব pwd.yml-এ পিন করা রিলিজ। যাচাই না করে সেই নম্বরটি সামনে এগিয়ে নেবেন না। বর্তমান রিলিজগুলো frappe/erpnext releases page-এ তালিকাভুক্ত আছে এবং বিদ্যমান ইমেজ ট্যাগগুলো Docker Hub-এ পাওয়া যাবে। নতুন ভার্সনে যাওয়ার আগে সেই ভার্সনের নোটগুলো পড়ে নিন।
আপগ্রেড প্রক্রিয়াটি শুরু হয় ব্যাকআপ এবং মেইনটেন্যান্স মোড দিয়ে।
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 এডিট করুন, তারপর রেন্ডার, পুল এবং মাইগ্রেট করুন।
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মেইনটেন্যান্স মোড গুরুত্বপূর্ণ কারণ migrate চলার সময় স্কিমা পরিবর্তন করে। কোনো ইউজার যদি অর্ধেক মাইগ্রেট হওয়া টেবিলের ওপর কোনো ডকুমেন্ট সাবমিট করেন, তবে আপনাকে হাতে ধরে রেকর্ড মেরামত করতে হবে।
প্রতিটি ধাপের মাঝে ব্যাকআপ নিয়ে একবারে একটি মেজর ভার্সন আপগ্রেড করুন। একটি রিলিজের মাইগ্রেশন কোড তার আগের রিলিজ থেকে আপগ্রেড করার জন্য লেখা হয়, তাই মেজর ভার্সন স্কিপ করলে এমন সব মাইগ্রেশন রান হতে পারে যা কেউ পরীক্ষা করেনি।
এই রিপোজিটরিতে overrides/compose.migrator.yaml-ও থাকে, যা প্রতিটি স্টার্টের সময় bench --site all migrate রান করার জন্য একটি কন্টেইনার যোগ করে। এটি সুবিধাজনক। তবে এর অর্থ হলো, ট্যাগ পরিবর্তন করে docker compose up করলে আপনার প্রোডাকশন ডাটাবেস কারো নজরদারি ছাড়াই মাইগ্রেট হয়ে যাবে। ব্যবসায়িক সিস্টেমের ক্ষেত্রে, মাইগ্রেট করার সিদ্ধান্তটি সেই সকালে সচেতনভাবে গ্রহণ করুন।
গ্রাহকের রেকর্ড ধারণকারী সার্ভার সুরক্ষিত করা
প্রথমবার লগইন করার সময়ই 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 অ্যাপ চালান, তবে প্রতিটি অ্যাপের জন্য আলাদা পাসওয়ার্ড ব্যবহারের চেয়ে self-hosted সিঙ্গেল সাইন-অন প্রোভাইডার হিসেবে Authentik ব্যবহার করা বেশি কার্যকর।
হোস্ট মেশিন প্যাচ করুন এবং কার্নেল আপডেটের জন্য রিবুট করুন। স্ট্যাকটি রিবুটের পর স্বয়ংক্রিয়ভাবে চালু হবে কি না তা নিশ্চিত করার আগে প্রতিটি সার্ভিসের জন্য রেন্ডার করা ফাইলে 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
ERPNext চালানোর জন্য VPS-এ কতটুকু 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 হিসেবে দেখা যায়। এগুলো প্রাথমিক ধারণা মাত্র, তাই প্রথম মাস ব্যবহারের সময় আপনার সার্ভারের মেমোরি ব্যবহারের দিকে নজর রাখুন।
আমি কি production-এ pwd.yml চালাতে পারি?
না। প্রকল্পের README-তে বলা হয়েছে এটি শুধুমাত্র স্বল্পস্থায়ী মূল্যায়নের জন্য তৈরি এবং এতে কোনো কাস্টম অ্যাপ ইনস্টল করা যায় না। MariaDB, Redis এবং HTTPS ওভাররাইডসহ compose.yaml ব্যবহার করুন, docker compose config দিয়ে সেগুলোকে একটি ফাইলে রেন্ডার করুন এবং সেই ফাইলটি চালান।
তৈরি করার পরপরই আমার ERPNext সাইটটি কেন অ্যাক্সেস করা যাচ্ছে না?
ফ্রন্টএন্ড ডিফল্টভাবে HTTP Host হেডার দেখে নির্ধারণ করে কোন সাইটটি পরিবেশন করতে হবে, তাই ব্রাউজারের ডোমেইনের সাথে সাইটের নামের মিল থাকা আবশ্যক। erpnext নামে তৈরি করা সাইট erp.example.com ঠিকানায় পরিবেশিত হবে না। হয় ডোমেইনটিকে সাইটের নাম হিসেবে ব্যবহার করে সাইট তৈরি করুন, অথবা env ফাইলে FRAPPE_SITE_NAME_HEADER-এ সাইটের নাম সেট করুন, এরপর compose ফাইলটি পুনরায় রেন্ডার করে স্ট্যাকটি রিস্টার্ট করুন।
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 পরিবর্তন করুন, compose ফাইলটি পুনরায় রেন্ডার করুন, pull করুন, স্ট্যাকটি চালু করুন এবং সবশেষে bench --site erp.example.com migrate চালান ও মেইনটেন্যান্স মোড বন্ধ করুন। একবারে একটি মেজর ভার্সন আপগ্রেড করুন এবং আগে রিলিজ নোটগুলো পড়ে নিন, কারণ migrate স্কিমা এবং ডকুমেন্ট ডেটা নতুন করে লিখে ফেলে যা আর আগের অবস্থায় ফিরিয়ে আনা যায় না। রোলব্যাক করার একমাত্র উপায় হলো শুরুতে নেওয়া ব্যাকআপটি রিস্টোর করা।