SSD Nodes Learn 🎉 VPS از $5.50/ماه
راهنماها Matt Connorتوسط Matt Connor

آموزش نصب و میزبانی ERPNext با Docker روی VPS

راهنمای کامل اجرای ERPNext با استفاده از Docker Compose و مدیریت 11 کانتینر. نکات کلیدی شامل تنظیمات TLS، ارسال ایمیل، ثابت‌سازی نسخه‌ها و روش صحیح بازیابی بک‌آپ در سال 2026.

آنچه برای اجرای آن ثبت‌نام می‌کنید

میزبانی شخصی ERPNext روی یک VPS یک وظیفهٔ عملیاتی است، نه یک نصب با یک دستور ساده. استک رسمی Docker Compose شامل یازده کانتینر است و دفتر کل عمومی و سوابق مشتریان شما را نگهداری می‌کند. این موضوع استاندارد همه موارد زیر را بالا می‌برد: یک نسخه پشتیبان تا زمانی که آن را بازیابی نکرده‌اید، نسخه پشتیبان محسوب نمی‌شود و یک image tag که ثابت (pinned) نشده باشد، یک مهاجرت دیتابیس (schema migration) است که در انتظار وقوع است.

چند نام در سراسر این راهنما تکرار می‌شوند. ERPNext همان برنامه کسب‌وکار است. Frappe فریم‌ورک پایتونی است که در زیرساخت آن قرار دارد. Bench ابزار خط فرمانی است که سایت‌ها را مدیریت می‌کند و از قبل داخل کانتینرها نصب شده است. یک سایت در واقع یک مستأجر (tenant) است: یک دیتابیس MariaDB به همراه یک دایرکتوری از فایل‌های آپلود شده. تقریباً هر دستوری در اینجا bench داخل کانتینر backend و علیه یک سایت مشخص اجرا می‌شود.

این راهنما از مخزن frappe_docker استفاده می‌کند که همان پیاده‌سازی رسمی نگهداری‌شده توسط پروژه است. تمامی دستورات زیر در اوت 2026 با آن مخزن بررسی شده‌اند. اگر Docker Compose برای شما جدید است، اجرای Docker Compose روی یک VPS مباحث پایه‌ای که این راهنما فرض می‌کند را پوشش می‌دهد.

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 گیگابایت رم پیش از ورود حتی یک کاربر در نظر می‌گیرد. این سطح برای ارزیابی است. این مقادیر صرفاً نقاط شروع هستند و نه اندازه‌گیری‌های دقیق این راهنما؛ حجم اسناد شما تعیین‌کننده نیاز واقعی است. ردیف آخر اصلاً یک حداقلِ اعلام‌شده نیست، بلکه سطحی است که در آن حافظه دیگر دغدغه اصلی شما نخواهد بود.

در مورد پلن‌های کوچک با خودتان صادق باشید. یک VPS با 1 یا 2 گیگابایت رم، استک را بالا می‌آورد اما در اولین عملیات import یا اولین گزارش طولانی از کار می‌افتد؛ زیرا 9 کانتینر در حال اجرا به همراه buffer pool دیتابیس MariaDB و یک worker پایتون که در حال ساخت گزارش است، در این مقدار حافظه جا نمی‌شوند. این شکست به شکل نرم رخ نمی‌دهد. قابلیت out of memory killer در هسته سیستم‌عامل، یک کانتینر را متوقف می‌کند و دستور docker inspect روی آن، وضعیت "OOMKilled": true را با کد خروج 137 نشان می‌دهد. اگر یک worker در میانه کار کشته شود، سند ثبت‌شده با پردازش‌های پس‌زمینه نیمه‌کاره باقی می‌ماند.

برای شرکتی که روزانه از ERPNext استفاده می‌کند، 8 گیگابایت رم و 4 هسته vCPU به همراه 100 گیگابایت فضای SSD، کفِ واقعی و صادقانه است. رم زودتر از سایر منابع تمام می‌شود. فضای دیسک نیز سریع‌تر از انتظار رشد می‌کند، زیرا تمام فایل‌های پیوست و بک‌آپ‌های محلی روی همان پارتیشنی ذخیره می‌شوند که دیتابیس قرار دارد.

یازده کانتینر و عملکرد هر یک

پس از بالا آمدن استک و اجرای 9 کانتینر، دستور docker compose ps را اجرا کنید. دو کانتینر دیگر، یعنی configurator و create-site، وظیفه خود را یک‌بار انجام داده و سپس خارج می‌شوند؛ به همین دلیل مجموع آن‌ها به 11 می‌رسد.

  • backend برنامه Frappe را تحت gunicorn اجرا می‌کند. bench در این بخش قرار دارد.
  • frontend همان nginx است. این کانتینر دارایی‌های ایستا (static assets) را سرویس‌دهی کرده و سایر درخواست‌ها را به backend می‌فرستد.
  • queue-short و queue-long پردازشگرهای RQ (Redis Queue) هستند. آن‌ها وظایف پس‌زمینه مانند ارسال ایمیل، وارد کردن داده‌ها و ساخت گزارش‌ها را انجام می‌دهند.
  • scheduler وظایف زمان‌بندی‌شده از جمله گزارش‌های دوره‌ای و اسناد تکرار شونده خودکار را اجرا می‌کند.
  • websocket پردازش socket.io است که مسئول به‌روزرسانی‌های زنده در مرورگر می‌باشد.
  • db همان MariaDB است.
  • redis-cache و redis-queue دو نمونه مجزای Redis هستند؛ یکی برای کش (cache) و دیگری برای صف وظایف (job queue).

یادگیری این تفکیک بسیار مفید است، زیرا مشخص می‌کند کدام لاگ را باید بررسی کنید. گیر کردن یک ایمیل به معنای بروز مشکل در پردازشگر صف است، بنابراین docker compose logs -f queue-short دستور مناسب برای بررسی آن است. صفحه‌ای که بارگذاری می‌شود اما نشان اعلان (notification badge) آن به‌روز نمی‌شود، یک مشکل مربوط به وب‌ساکت است. خواندن لاگ‌های backend برای هر یک از این موارد، تنها اتلاف وقت است.

نصب با استفاده از فایل‌های 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 تگ image را ثابت می‌کند. 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 هیچ چیزی را اجرا نمی‌کند. این دستور فایل پایه را با فایل‌های override ادغام کرده و نتیجه را با تمام متغیرهای جای‌گذاری‌شده چاپ می‌کند. سپس شما آن فایل رندرشده را اجرا می‌کنید. این مرحلهٔ اضافی ارزشش را دارد: stack در حال اجرا یک فایل واحد است که می‌توانید آن را بخوانید و commit کنید، بنابراین اگر کسی فایل env را ویرایش کند یا شما مخزن را pull کنید، تنظیمات به‌طور ناگهانی تغییر نمی‌کند. نحوه ادغام چندین فایل Docker Compose قوانین override را با جزئیات توضیح می‌دهد.

منتظر بمانید تا 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 باشد.

دو مورد اغلب در اینجا دچار مشکل می‌شوند. --mariadb-user-host-login-scope=% در Docker اختیاری نیست. کانتینر برنامه از طریق شبکه Docker به MariaDB متصل می‌شود، بنابراین به عنوان یک میزبان راه دور (remote host) شناخته می‌شود و کاربری دیتابیس که محدود به localhost باشد، نمی‌تواند از آنجا وارد شود. در نتیجه، ایجاد سایت با خطای دسترسی MariaDB برای کاربر root شکست می‌خورد. محدوده % به کاربر سایت جدید اجازه می‌دهد از هر میزبانی در آن شبکه خصوصی دسترسی داشته باشد.

مورد دوم نام سایت است. frontend به‌طور پیش‌فرض انتخاب می‌کند که کدام سایت را بر اساس هدر HTTP Host سرویس‌دهی کند، بنابراین سایتی که به نام erpnext ایجاد شده، در erp.example.com قابل دسترسی نیست، حتی اگر هر دو وجود داشته باشند. نام سایت را مطابق دامنه انتخاب کنید (مانند بالا)، یا FRAPPE_SITE_NAME_HEADER را در فایل env روی نام سایت تنظیم کرده و فایل compose را دوباره رندر کنید.

HTTPS و پیش‌نیازهای عملکرد آن

پیکربندی compose.https.yaml، سرویس Traefik را روی پورت 443 اجرا می‌کند، ترافیک پورت 80 را به آن هدایت کرده و گواهی‌های لازم را از Let's Encrypt درخواست می‌کند. TLS (امنیت لایه انتقال) همان مکانیزمی است که از ارسال صورت‌حساب‌ها و کوکی‌های نشست (session cookie) به صورت متن ساده (plain text) در شبکه جلوگیری می‌کند.

برای صدور گواهی، دو شرط باید برقرار باشد. رکورد DNS A برای erp.example.com باید از قبل به VPS اشاره کند. پورت‌های 80 و 443 باید از طریق اینترنت در دسترس باشند، زیرا Let's Encrypt مالکیت شما بر دامنه را از طریق چالش HTTP-01 روی پورت 80 تایید می‌کند. علاوه بر فایروال سیستم، فایروال شبکه ارائه‌دهنده سرور را نیز بررسی کنید. این‌ها کنترل‌های مجزایی هستند و فایروال پنل مدیریتی همان موردی است که معمولاً فراموش می‌شود.

گواهی‌ها در volume مربوط به cert-data در مسیر /letsencrypt/acme.json ذخیره می‌شوند. اگر مرورگر به جای گواهی شما، گواهی پیش‌فرض را نمایش می‌دهد، نام سرویس پروکسی را در docker compose --project-name erpnext ps پیدا کرده و لاگ‌های آن را برای یافتن خطای ACME (محیط مدیریت خودکار گواهی) بررسی کنید. آیا برنامه‌های وب دیگری روی همان سرور اجرا می‌کنید؟ مطلب استفاده از یک نمونه Traefik در مقابل چندین برنامه Docker Compose نشان می‌دهد که چگونه به جای رقابت بر سر پورت 443، از پروکسی به صورت اشتراکی استفاده کنید.

ایمیل خروجی، یا فاکتورهایی که هرگز از سرور خارج نمی‌شوند

این مرحله‌ای است که اکثر راهنماهای ERPNext از آن عبور می‌کنند، در حالی که تعیین‌کننده کارآمدی سیستم است. بدون ایمیل خروجی فعال، هیچ فاکتوری به دست مشتری نمی‌رسد، بازنشانی رمز عبور انجام نمی‌شود و هیچ گزارش زمان‌بندی‌شده‌ای ارسال نخواهد شد. این پشته (stack) شامل هیچ سرور ایمیلی نیست.

سعی نکنید ایمیل را مستقیماً از طریق پورت 25 از روی VPS ارسال کنید. اکثر ارائه‌دهندگان، پورت 25 خروجی را در اکانت‌های جدید مسدود می‌کنند و هر ایمیلی که خارج شود نیز به دلیل نداشتن اعتبار (reputation) برای آدرس IP یک VPS تازه، رد شده یا به عنوان اسپم شناخته می‌شود. از یک relay احراز هویت‌شده روی پورت 587 استفاده کنید.

مسیر پشتیبانی‌شده، صفحه Email Account در رابط کاربری ERPNext است که رمز عبور را به‌صورت رمزنگاری‌شده ذخیره می‌کند. همچنین می‌توانید کلیدها را در فایل پیکربندی سایت (site config) بنویسید:

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". فایل را بازخوانی کنید و مطمئن شوید که این دو مقدار فاقد کوتیشن هستند:

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

تنظیمات mail_password را از طریق صفحه Email Account انجام دهید و نه از طریق خط فرمان، تا به‌صورت رمزنگاری‌شده ذخیره شود و هرگز وارد تاریخچه shell شما نشود.

سپس یک پیام واقعی ارسال کنید. یک Sales Invoice ایجاد کنید، آن را به آدرسی که تحت کنترل خودتان است ایمیل کنید و در حین انجام این کار، صف ارسال را مشاهده کنید:

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

ایمیل خروجی یک job پس‌زمینه است، بنابراین پیامی که هرگز به مقصد نمی‌رسد، معمولاً به جای نمایش خطا در مرورگر، به عنوان یک job ناموفق در آن لاگ ظاهر می‌شود. رکوردهای SPF (sender policy framework) و DKIM (domainkeys identified mail) را برای دامنه فرستنده منتشر کنید و سپس یک سیاست DMARC اضافه کنید. بدون این موارد، حتی یک فاکتور که از نظر فنی صحیح است، در پوشه اسپم مشتری قرار می‌گیرد. اگر ترجیح می‌دهید مالکیت کل مسیر را در اختیار داشته باشید، یک سرور ایمیل Mailcow خودمیزبان یک relay تحت کنترل شما، روی سروری جدا از ERP، در اختیارتان قرار می‌دهد.

پشتیبان‌گیری‌هایی که واقعاً بازیابی می‌شوند

یک dump از پایگاه داده به‌تنهایی پشتیبان کاملی برای ERPNext نیست. فایل‌های پیوست و فایل‌های خصوصی در دایرکتوری sites قرار دارند، نه در MariaDB. اگر فقط پایگاه داده را بازیابی کنید، تمام سفارش‌های خرید بارگذاری‌شده به لینک‌های خراب تبدیل می‌شوند.

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

این دستور چهار فایل را در sites/erp.example.com/private/backups داخل volume مربوط به sites می‌نویسد:

  • یک dump از -database.sql.gz
  • یک آرشیو -files.tar از فایل‌های عمومی
  • یک آرشیو -private-files.tar از فایل‌های خصوصی
  • یک کپی از تنظیمات سایت -site_config_backup.json

فایل چهارم همان فایلی است که کاربران معمولاً دور می‌ریزند و نبودش باعث دردسر می‌شود. این فایل حاوی encryption_key است؛ کلیدی که Frappe برای رمزنگاری گذرواژه‌های ذخیره‌شده استفاده می‌کند: اعتبارنامه‌های حساب ایمیل، کلیدهای درگاه پرداخت و تمام اسرار مربوط به یکپارچه‌سازی‌ها. اگر پایگاه داده را بدون کلید منطبق بازیابی کنید، سایت به‌ظاهر به‌درستی بالا می‌آید، اما ارسال ایمیل با خطای زیر مواجه می‌شود:

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

همیشه هر چهار فایل را در کنار هم نگه دارید.

سپس آن‌ها را از سرور خارج کنید. پشتیبانی که داخل volume باقی بماند، در صورت خرابی سرور از بین می‌رود. علاوه بر این، 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>'

کلید رمزنگاری را از تنظیمات بک‌آپ کپی کرده و در سایت بازیابی‌شده قرار دهید، در غیر این صورت یکپارچه‌سازی‌های آن از کار می‌افتند:

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

چرا ثابت‌سازی نسخه (version pinning) برای ERPNext اهمیت بیشتری دارد

در یک وب‌سایت ایستا، استفاده از تگ image بدون نسخه ثابت، تنها به معنای یک راه‌اندازی مجدد غیرمنتظره است. اما در ERPNext، این کار به معنای مهاجرت طرح‌واره (schema migration) است. bench migrate جداول پایگاه‌داده را بازنویسی می‌کند و ممکن است داده‌های اسناد را نیز تغییر دهد؛ این فرآیند قابلیت بازگشت (undo) ندارد. بازگشت به وضعیت قبل، مستلزم بازیابی از نسخه پشتیبان است، نه یک docker compose down ساده.

بنابراین، تگ را ثابت کنید. ERPNEXT_VERSION=v16.32.1 نسخه‌ای بود که در pwd.yml خود مخزن در اوت 2026 ثابت شده بود. آن عدد را بدون بررسی مجدد به نسخه‌های بعدی منتقل نکنید. نسخه‌های فعلی در صفحه انتشار frappe/erpnext فهرست شده‌اند و تگ‌های موجود image نیز در 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

فایل ERPNEXT_VERSION را در ~/gitops/erpnext.env ویرایش کنید، سپس دستورات 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

حالت نگهداری اهمیت حیاتی دارد، زیرا migrate در حین اجرا، طرح‌واره را تغییر می‌دهد. اگر کاربری در حین مهاجرت ناقص جداول، سندی را ثبت کند، مجبور خواهید شد رکوردها را به‌صورت دستی تعمیر کنید.

هر بار فقط یک نسخه اصلی (major version) ارتقا دهید و بین هر مرحله نسخه پشتیبان تهیه کنید. کد مهاجرت در هر نسخه، برای ارتقا از نسخه پیش از خود نوشته شده است؛ بنابراین پرش از نسخه‌های اصلی باعث اجرای مهاجرت‌ها در ترکیبی می‌شود که توسط هیچ‌کس تست نشده است.

این مخزن همچنین overrides/compose.migrator.yaml را ارائه می‌دهد که یک container برای اجرای bench --site all migrate در هر بار راه‌اندازی اضافه می‌کند. این قابلیت راحت است، اما به این معناست که یک docker compose up با تگ تغییریافته، پایگاه‌داده عملیاتی (production) شما را بدون نظارت مستقیم مهاجرت می‌دهد. در سیستم‌های تجاری، اجرای migrate باید تصمیمی باشد که همان روز صبح اتخاذ کرده‌اید.

ایمن‌سازی سروری که حاوی سوابق مشتریان است

در اولین ورود، رمز عبور Administrator را تغییر دهید. فایل compose ارزیابی، از admin به عنوان رمز عبور استفاده می‌کند و این عادت ممکن است به محیط عملیاتی (production) نیز منتقل شود.

مقدار DB_PASSWORD را از 123 در فایل example.env تغییر دهید. این مقدار در نهایت به صورت متن ساده در ~/gitops/erpnext.yaml رندر می‌شود، بنابراین فایل را chmod 600 کرده و آن را از هر مخزن git دور نگه دارید. برای امنیت بیشتر، overrides/compose.mariadb-secrets.yaml رمز عبور را به‌جای متغیر محیطی، از یک فایل Docker secret می‌خواند. مدیریت فایل‌های env و secretها در Docker Compose به بررسی مزایا و معایب این روش می‌پردازد.

فقط آنچه نیاز دارید را منتشر کنید. با استفاده از override مربوط به HTTPS، تنها پورت‌های 80 و 443 در معرض دید قرار می‌گیرند. برای تسهیل اتصال کلاینت دیتابیس، هیچ نگاشت ports به سرویس db اضافه نکنید؛ این کار MariaDB را در معرض اینترنت عمومی قرار می‌دهد. به‌جای آن از docker compose --project-name erpnext exec backend bench mariadb استفاده کنید. روی میزبان، پورت‌های 22، 80 و 443 را مجاز کنید، بقیه را مسدود نمایید و فایروال شبکه جداگانه ارائه‌دهنده سرویس را نیز بررسی کنید.

برای هر حسابی که نقش System Manager دارد، احراز هویت دو مرحله‌ای را در System Settings فعال کنید. این نقش می‌تواند تمام اسناد را بخواند و از تمام جداول خروجی بگیرد، بنابراین با آن به عنوان یک حساب مدیریتی برخورد کنید، نه یک حساب کاربری ساده. اگر چندین برنامه self-hosted اجرا می‌کنید، استفاده از Authentik به عنوان ارائه‌دهنده SSO برای سرویس‌های شخصی بهتر از داشتن یک رمز عبور مجزا برای هر برنامه است.

میزبان را وصله (patch) کنید و برای به‌روزرسانی‌های هسته (kernel)، سیستم را reboot نمایید. پیش از آنکه به بالا آمدن مجدد stack اطمینان کنید، فایل رندر شده را برای سیاست restart روی هر سرویس بررسی کنید، زیرا stack بدون این سیاست پس از reboot خاموش می‌ماند. راه‌اندازی مجدد stack در Docker Compose پس از reboot به بررسی جنبه‌های مربوط به systemd می‌پردازد.

زمانی که ERPNext دیگر روی یک VPS پاسخگو نیست

یک VPS ممکن است برای مدت طولانی نیازهای یک شرکت کوچک را برآورده کند. نشانه‌هایی که ثابت می‌کند این سرور دیگر کافی نیست:

  • صف کارهای پس‌زمینه (Background jobs) انباشته می‌شود و در نتیجه ایمیل‌ها و فایل‌های واردشده با تأخیر چند دقیقه‌ای یا چند ساعته پردازش می‌شوند.
  • دستور docker inspect کانتینرهایی را با وضعیت "OOMKilled": true یا کد خروج 137 گزارش می‌دهد.
  • گزارش‌هایی که قبلاً در 2 ثانیه اجرا می‌شدند اکنون 30 ثانیه زمان می‌برند و MariaDB پردازشی است که بیشترین سهم CPU را اشغال کرده است.
  • زمان اجرای پشتیبان‌گیری (Backup) به قدری طولانی می‌شود که با اجرای زمان‌بندی‌شدهٔ بعدی تداخل پیدا می‌کند.

ابتدا منابعی را به MariaDB اختصاص دهید که با سرویس‌های دیگر مشترک نباشد؛ زیرا دیتابیس و workerهای پایتون برای حافظه با یکدیگر رقابت می‌کنند و buffer pool بخشی است که بیشترین نیاز را به حافظه دارد. ارتقای سرور برنامه (Application server) معمولاً کمتر از حد انتظار تأثیرگذار است. بخش اجرای دیتابیس در Docker یا روی host به این تصمیم می‌پردازد و تنظیم محدودیت حافظه در Docker Compose از اشغال بیش از حد منابع توسط یک کانتینر و ایجاد اختلال در سایر سرویس‌ها جلوگیری می‌کند.

پس از آن، به‌جای افزایش ظرفیت وب، workerهای صف (Queue workers) را اضافه کنید. کندی ERPNext معمولاً مربوط به کارهای پس‌زمینه مانند تولید گزارش و وارد کردن داده‌های حجیم است. هزینهٔ کانتینرهای worker بیشتر، کمتر از ارتقای کل سرور است و مستقیماً مشکلی را حل می‌کند که کاربران از آن شکایت دارند.

FAQ

ERPNext روی یک VPS به چه مقدار RAM نیاز دارد؟

راهنمای منتشرشده با 4 گیگابایت رم و 2 هسته vCPU شروع می‌شود که این سطح فقط برای ارزیابی است. برای شرکتی که روزانه از آن استفاده می‌کند، 8 گیگابایت رم و 4 هسته vCPU به همراه 100 گیگابایت فضای SSD در نظر بگیرید. در مقادیر کمتر از این، قابلیت out of memory killer در هسته سیستم‌عامل، کانتینرها را تحت بار کاری متوقف می‌کند که docker inspect آن را به صورت "OOMKilled": true با کد خروج 137 گزارش می‌دهد. این مقادیر نقاط شروع هستند و نه اندازه‌گیری‌های قطعی؛ بنابراین در طول ماه اول، میزان مصرف حافظه خود را مانیتور کنید.

آیا می‌توانم pwd.yml را در محیط production اجرا کنم؟

خیر. فایل README پروژه توضیح می‌دهد که این فایل فقط برای ارزیابی‌های کوتاه‌مدت در نظر گرفته شده است و اشاره می‌کند که نمی‌توانید برنامه‌های سفارشی (custom apps) را در آن نصب کنید. از compose.yaml به همراه overrideهای MariaDB، Redis و HTTPS استفاده کنید، آن‌ها را با docker compose config در یک فایل واحد ادغام کرده و سپس آن فایل را اجرا کنید.

چرا سایت ERPNext من بلافاصله پس از ایجاد، غیرقابل دسترس است؟

فرانت‌اند به‌صورت پیش‌فرض تصمیم می‌گیرد که کدام سایت را بر اساس هدر HTTP Host ارائه دهد، بنابراین نام سایت باید با دامنه موجود در مرورگر مطابقت داشته باشد. سایتی که با نام erpnext ایجاد شده است، در erp.example.com ارائه نمی‌شود. یا سایت را با استفاده از نام دامنه ایجاد کنید، یا در فایل env مقدار FRAPPE_SITE_NAME_HEADER را روی نام سایت تنظیم کنید، فایل compose را دوباره render کرده و stack را restart کنید.

چه مواردی باید در بک‌آپ ERPNext وجود داشته باشد؟

چهار فایل که باید با هم نگهداری شوند: دامپ -database.sql.gz، آرشیوهای -files.tar و -private-files.tar، و کپی تنظیمات -site_config_backup.json. اجرای bench --site erp.example.com backup --with-files هر چهار مورد را تولید می‌کند. کپی تنظیمات شامل encryption_key است، بنابراین بازیابی بدون آن باعث می‌شود رمزهای عبور یکپارچه‌سازی (integration passwords) غیرقابل رمزگشایی شوند که به صورت Encryption key is invalid! Please check site_config.json نمایان می‌شود.

چگونه ERPNext را بدون آسیب به داده‌ها ارتقا دهم؟

با استفاده از --with-files بک‌آپ بگیرید، حالت maintenance را فعال کنید، مقدار ERPNEXT_VERSION را در فایل env تغییر دهید، فایل compose را دوباره render کنید، pull انجام دهید، stack را بالا بیاورید، سپس bench --site erp.example.com migrate را اجرا کرده و حالت maintenance را غیرفعال کنید. هر بار یک نسخه اصلی (major version) ارتقا دهید و ابتدا release notes را مطالعه کنید، زیرا migrate ساختار دیتابیس (schema) و داده‌های اسناد را بازنویسی می‌کند و امکان بازگشت (undo) وجود ندارد. بازگشت به نسخه قبل (rollback) به معنای بازیابی بک‌آپی است که در ابتدا تهیه کرده‌اید.