SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-27

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

راهنمای کامل میزبانی ERPNext با Docker روی VPS. نحوه مدیریت پشته 11 کانتینری، تنظیمات TLS، ارسال ایمیل، ثابت‌سازی نسخه و استراتژی تست بازیابی دیتابیس برای پایداری کامل.

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

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

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

یازده کانتینر و وظیفه هر کدام

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

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

یادگیری این تفکیک بسیار مفید است، زیرا به شما می‌گوید که کدام لاگ را بررسی کنید. گیر کردن یک ایمیل، مشکلی مربوط به ورکر صف است، بنابراین 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) به‌صورت متن ساده در شبکه منتقل شوند.

دو شرط باید برقرار باشد تا گواهی صادر شود. رکورد 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، از پروکسی به‌صورت اشتراکی استفاده کنید. برنامه دوم روی چنین سروری اغلب با مشتری در ارتباط است و یک میز پشتیبانی Chatwoot خودمیزبان پشت همان پروکسی قرار می‌گیرد تا افرادی که با فاکتورها کار می‌کنند، بتوانند ایمیل‌ها و چت‌های مشتریان را نیز در یک مکان پاسخ دهند.

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

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

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

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

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

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

بنابراین تگ را تثبیت کنید. ERPNEXT_VERSION=v16.32.1 نسخه‌ای بود که در pwd.yml خودِ مخزن در اوت 2026 تثبیت شده بود. آن شماره را بدون بررسی مجدد به نسخه‌های بعدی منتقل نکنید. نسخه‌های فعلی در صفحه انتشار frappe/erpnext فهرست شده‌اند و تگ‌های ایمیج موجود نیز در 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 را ارائه می‌دهد که یک کانتینر برای اجرای bench --site all migrate در هر بار شروع اضافه می‌کند. این قابلیت راحت است، اما به این معناست که یک docker compose up با تگ تغییریافته، پایگاه داده عملیاتی شما را بدون نظارت مهاجرت می‌دهد. در یک سیستم تجاری، اجرای 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 در معرض دید قرار می‌گیرند. برای تسهیل اتصال کلاینت دیتابیس، هیچ mapping مربوط به ports را به سرویس db اضافه نکنید؛ چرا که این کار MariaDB را روی اینترنت عمومی قرار می‌دهد. به‌جای آن از docker compose --project-name erpnext exec backend bench mariadb استفاده کنید. روی میزبان (host)، پورت‌های 22، 80 و 443 را مجاز کنید، بقیه را مسدود نمایید و فایروال شبکه جداگانه ارائه‌دهنده سرویس را نیز بررسی کنید.

برای تمامی حساب‌هایی که نقش System Manager دارند، احراز هویت دو مرحله‌ای (2FA) را در 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های Python برای حافظه با یکدیگر رقابت می‌کنند و buffer pool بخشی است که به حافظه بیشتری نیاز دارد. ارتقای سرور اپلیکیشن معمولاً کمتر از آنچه تصور می‌شود تأثیرگذار است. اجرای دیتابیس در 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 است؛ بنابراین بازیابی بدون آن، رمزهای عبور ذخیره‌شده برای یکپارچه‌سازی‌ها را غیرقابل رمزگشایی می‌کند که به صورت خطای 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) و داده‌های اسناد را بازنویسی می‌کند و راه بازگشتی ندارد. بازگشت به نسخه قبل (rollback) به معنای بازیابی بک‌آپی است که در ابتدا تهیه کرده‌اید.