SSD Nodes Learn 🎉 VPS من $5.50/شهر
الأدلة Matt Connorبقلم Matt Connor

استضافة ERPNext على VPS باستخدام Docker

تعرّف إلى متطلبات ERPNext على VPS وحزمة Docker المؤلفة من 11 حاوية، مع إعداد TLS والبريد الصادر وتثبيت الإصدار واختبار استعادة النسخ الاحتياطية.

ما الذي ستلتزم بتشغيله

استضافة ERPNext ذاتياً على VPS هي مهمة تشغيلية، وليست عملية تثبيت بأمر واحد. تتكوّن حزمة Docker Compose الرسمية من إحدى عشرة حاوية، وتحتوي على دفتر الأستاذ العام وسجلات العملاء. لذلك يجب رفع مستوى الدقة في كل ما يلي: لا تُعدّ النسخة الاحتياطية نسخة احتياطية حتى تستعيدها، ووسم الصورة غير المثبّت ينتظر ترقية لمخطط قاعدة البيانات.

ستظهر عدة أسماء في هذا الدليل. ERPNext هو تطبيق الأعمال. Frappe هو إطار Python الذي يعمل تحته. Bench هي أداة سطر الأوامر التي تدير المواقع، وهي مثبّتة مسبقاً داخل الحاويات. الـsite هو مستأجر واحد: قاعدة بيانات MariaDB واحدة، إضافة إلى دليل واحد للملفات المرفوعة. تُنفَّذ جميع الأوامر هنا تقريباً bench داخل الحاوية backend على موقع مسمّى واحد.

يستخدم هذا الدليل مستودع frappe_docker، وهو النشر الذي يصونه المشروع. اختُبر كل أمر أدناه مقابل ذلك المستودع في أغسطس 2026. إذا كانت Docker Compose جديدة عليك، فراجع تشغيل Docker Compose على VPS للاطلاع على الأساسيات التي يفترضها هذا الدليل.

ما مقدار موارد VPS التي يحتاجها ERPNext؟

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 قبل أن يسجّل أي مستخدم دخوله. هذه هي فئة التقييم. هذه أرقام بداية وليست قياسات واردة في هذا الدليل، ويحدد حجم مستنداتك الفعلي الرقم الحقيقي. أما الصف الأخير فليس حداً أدنى منشوراً على الإطلاق. إنه تقريباً المستوى الذي تتوقف عنده الذاكرة عن كونها مصدر القلق الرئيسي.

كن صريحاً مع نفسك بشأن الخطط الصغيرة. سيشغّل VPS بسعة 1 GB أو 2 GB الحزمة البرمجية، ثم سيفشل عند أول عملية استيراد أو أول تقرير طويل، لأن تسع حاويات طويلة التشغيل، إلى جانب buffer pool الخاص بـMariaDB وعامل Python الذي ينشئ التقرير، لا تتسع لها هذه الذاكرة. ولا يحدث الفشل بطريقة آمنة. يوقف kernel out of memory killer إحدى الحاويات، ثم يعرض docker inspect عليها الحالة "OOMKilled": true مع exit code 137. ويؤدي إنهاء عامل أثناء تنفيذ المهمة إلى ترك مستند مُرسل وقد اكتمل جزء فقط من عمله في الخلفية.

بالنسبة إلى شركة تستخدم ERPNext يومياً، فإن 8 GB و4 vCPU مع 100 GB من SSD تمثل الحد الأدنى الواقعي. تنفد RAM أولاً. ويزداد حجم القرص أسرع مما يتوقعه معظم الناس، لأن كل مرفق وكل نسخة احتياطية محلية تُحفظ على وحدة التخزين نفسها التي تستضيف قاعدة البيانات.

الحاويات الإحدى عشرة ووظيفة كل منها

شغّل docker compose ps بعد بدء المكدس وتشغيل تسع حاويات. تنفّذ configurator وcreate-site مهمتهما مرة واحدة ثم تتوقفان، ومن هنا يأتي العدد الإجمالي البالغ إحدى عشرة حاوية.

  • تشغّل backend تطبيق Frappe باستخدام gunicorn. يوجد 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 هو الأمر الصحيح. أما الصفحة التي تُحمّل لكن شارة الإشعارات فيها لا تتحدّث مطلقاً، فالمشكلة في websocket. تؤدي قراءة سجلات 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 وغيّر 4 قيم. يثبّت 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 السليم 9 خدمات بالحالة running، ولا يعرض أي خدمة بالحالة restarting.

تحدث مشكلتان هنا كثيراً. لا يمكن الاستغناء عن --mariadb-user-host-login-scope=% عند استخدام Docker. تصل حاوية التطبيق إلى MariaDB عبر شبكة Docker، ولذلك تظهر كأنها مضيف بعيد، ولا يمكن لمستخدم قاعدة بيانات محصور في localhost تسجيل الدخول منها. يفشل إنشاء الموقع حينها برسالة رفض وصول من MariaDB تذكر المستخدم root. يتيح نطاق % لمستخدم الموقع الجديد الوصول من أي مضيف على تلك الشبكة الخاصة.

المشكلة الثانية هي اسم الموقع. يختار الواجهة الأمامية الموقع الذي ستعرضه استناداً إلى ترويسة HTTP Host افتراضياً، ولذلك لا يمكن الوصول إلى موقع أُنشئ باسم erpnext عبر erp.example.com رغم وجود الموقعين. سمِّ الموقع باسم النطاق، كما سبق، أو عيّن FRAPPE_SITE_NAME_HEADER في ملف env إلى اسم الموقع، ثم أنشئ ملف Compose من جديد.

HTTPS، وما يجب أن يتحقق قبل أن يعمل

يشغّل ملف override ‏compose.https.yaml Traefik على المنفذ 443، ويعيد توجيه المنفذ 80 إليه، ويطلب الشهادات من Let's Encrypt. يوفّر TLS (أمان طبقة النقل) الحماية بحيث لا تظهر الفاتورة وملف تعريف ارتباط الجلسة على الشبكة بنص واضح.

يجب أن يتحقق شرطان، وإلا فلن تُصدر أي شهادة. يجب أن يكون سجل DNS من النوع A للاسم erp.example.com موجهاً مسبقاً إلى VPS. ويجب أن يكون المنفذان 80 و443 قابلين للوصول من الإنترنت، لأن Let's Encrypt يثبت أنك تتحكم في الاسم باستخدام تحدي HTTP-01 عبر المنفذ 80. تحقّق من جدار الحماية الشبكي لدى مزود الخدمة، ومن جدار الحماية على الخادم أيضاً. هذان إعدادان منفصلان، وغالباً ما يُنسى جدار الحماية في لوحة التحكم.

تُخزَّن الشهادات في وحدة التخزين cert-data ضمن المسار /letsencrypt/acme.json. إذا عرض المتصفح شهادة افتراضية بدلاً من شهادتك، فاعثر على اسم خدمة الـproxy في docker compose --project-name erpnext ps، وراجع سجلاتها بحثاً عن خطأ ACME (بيئة إدارة الشهادات الآلية). هل تشغّل تطبيقات ويب أخرى على الخادم نفسه؟ يوضّح مثيل Traefik واحد أمام عدة تطبيقات Docker Compose كيفية مشاركة الـproxy بدلاً من التنافس على المنفذ 443.

البريد الصادر، وإلا فلن تغادر الفواتير الخادم

هذه هي الخطوة التي تتجاوزها معظم أدلة ERPNext، وهي التي تحدد ما إذا كان النظام مفيداً. من دون بريد صادر يعمل، لن تصل أي فاتورة إلى العميل، ولن تصل رسائل إعادة تعيين كلمات المرور، ولن يُسلَّم أي تقرير مجدول. لا تتضمن هذه الحزمة خادم بريد.

لا تحاول إرسال البريد مباشرة من VPS عبر المنفذ 25. يحظر معظم المزوّدين المنفذ الصادر 25 في الحسابات الجديدة، وما يخرج منه يُرفض أو يُصنَّف كبريد عشوائي، لأن عنوان 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 بدلاً من سطر الأوامر، لكي تُخزَّن القيمة بصيغة مشفّرة ولا تدخل مطلقاً في سجل أوامر الصدفة.

أرسل بعد ذلك رسالة فعلية. أنشئ Sales Invoice، وأرسلها بالبريد إلى عنوان تتحكم فيه، وراقب قائمة الانتظار أثناء ذلك:

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

يُرسل البريد الصادر عبر مهمة في الخلفية، لذلك تظهر الرسالة التي لا تصل عادةً كمهمة فاشلة في ذلك السجل، وليس كخطأ في المتصفح. انشر أيضاً سجلات SPF (إطار سياسة المرسل) وDKIM (البريد المحدد بمفاتيح النطاق) لنطاق الإرسال، ثم أضف سياسة DMARC. من دون هذه السجلات، قد تصل الفاتورة الصحيحة تقنياً إلى مجلد البريد العشوائي لدى العميل. إذا كنت تفضّل امتلاك المسار بالكامل، فإن خادم بريد Mailcow مستضاف ذاتياً يوفّر لك relay تتحكم فيه، على خادم منفصل عن ERP.

النسخ الاحتياطية التي يمكن استعادتها فعلياً

لا يُعد تفريغ قاعدة البيانات وحده نسخة احتياطية من ERPNext. توجد المرفقات والملفات الخاصة في دليل sites، وليس في MariaDB. إذا استعدت قاعدة البيانات فقط، فستعود كل أوامر الشراء المرفوعة كرابط معطّل.

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

ينشئ ذلك أربعة ملفات داخل sites/erp.example.com/private/backups في وحدة التخزين sites:

  • تفريغ بصيغة -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

احتفظ بالملفات الأربعة معاً دائماً.

بعد ذلك، انقلها خارج الخادم. فالنسخة الاحتياطية الموجودة داخل وحدة التخزين لا تصمد أمام فقدان الخادم، كما أن 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>'

تحقق الآن من الاستعادة بالطريقة التي يتبعها المحاسب. افتح تقرير الحسابات المدينة، وقارن الرصيد الختامي بالرصيد في الموقع الفعلي. افتح فاتورة شراء حديثة، ونزّل المرفق الخاص بها. الموقع الذي يعرض صفحة تسجيل الدخول لا يثبت شيئاً على الإطلاق.

أزل موقع الاختبار عند الانتهاء:

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

لماذا يكون تثبيت الإصدار أكثر أهمية في ERPNext

في موقع ثابت، يعني وسم الصورة غير المثبّت إعادة تشغيل مفاجئة. أما في ERPNext، فيعني ترحيل مخطط قاعدة البيانات. يعيد bench migrate كتابة جداول قاعدة البيانات، وقد يعيد كتابة بيانات المستندات، ولا يوفّر طريقة للتراجع. التراجع يعني الاستعادة من نسخة احتياطية، وليس docker compose down.

لذلك ثبّت الوسم. كان ERPNEXT_VERSION=v16.32.1 هو الإصدار المثبّت في pwd.yml الخاص بالمستودع نفسه في أغسطس 2026. لا تستخدم هذا الرقم لاحقاً من دون التحقق منه. تُدرج الإصدارات الحالية في صفحة إصدارات frappe/erpnext، بينما توجد وسوم الصور المتاحة على 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

حرّر 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 يغيّر المخطط أثناء تشغيله. إذا أرسل مستخدم مستنداً إلى جدول جرت له ترقية جزئية، فقد تضطر إلى إصلاح السجلات يدوياً.

انتقل إصداراً رئيسياً واحداً في كل مرة، وأنشئ نسخة احتياطية بين كل خطوة وأخرى. كُتب رمز الترحيل في كل إصدار للترقية من الإصدار السابق له، ولذلك يؤدي تخطي الإصدارات الرئيسية إلى تشغيل عمليات ترحيل ضمن مجموعة لم يختبرها أحد.

يأتي المستودع أيضاً مع overrides/compose.migrator.yaml، الذي يضيف حاوية تشغّل bench --site all migrate عند كل بدء تشغيل. هذا مريح. لكنه يعني أيضاً أن docker compose up مع وسم متغيّر قد يرحّل قاعدة بيانات الإنتاج من دون أن يراقب أحد العملية. في نظام أعمال، شغّل migrate باعتباره قراراً اتخذته في ذلك الصباح.

تأمين خادم يحتفظ بسجلات العملاء

غيّر كلمة مرور Administrator عند تسجيل الدخول لأول مرة. يوزّع ملف Compose المستخدم في التقييم admin على أنّها كلمة المرور، وقد تنتقل هذه العادة إلى بيئة الإنتاج.

غيّر DB_PASSWORD بحيث لا تطابق 123 في example.env. تظهر هذه القيمة في ~/gitops/erpnext.yaml الناتج بنص واضح، لذلك chmod 600 الملف وأبقِه خارج أي مستودع git. وللحصول على أمان أقوى، يقرأ overrides/compose.mariadb-secrets.yaml كلمة المرور من ملف Docker secret بدلاً من متغير بيئة. يشرح التعامل مع ملفات البيئة والأسرار في Docker Compose المفاضلات بين الخيارين.

انشر المنافذ التي تحتاج إليها فقط. مع إعداد HTTPS التجاوزي، يكون المنفذان 80 و443 هما المنفذين المكشوفين فقط. لا تضف تعيين ports إلى خدمة db لتسهيل اتصال عميل قاعدة البيانات، لأن ذلك يضع MariaDB على الإنترنت العام. استخدم docker compose --project-name erpnext exec backend bench mariadb بدلاً من ذلك. على الخادم، اسمح بالمنافذ 22 و80 و443، وارفض باقي المنافذ، وافحص أيضاً جدار الشبكة الناري المنفصل لدى مزوّد الخدمة.

فعّل المصادقة الثنائية في System Settings لكل حساب يحمل دور System Manager. يستطيع هذا الدور قراءة كل مستند وتصدير كل جدول، لذلك تعامل معه كحساب إداري لا كخيار مريح. إذا كنت تشغّل عدة تطبيقات مستضافة ذاتياً، فإن Authentik كمزوّد تسجيل دخول موحّد مستضاف ذاتياً أفضل من إضافة كلمة مرور أخرى لكل تطبيق.

طبّق التحديثات على الخادم وأعد تشغيله عند توفر تحديثات kernel. قبل الاعتماد على عودة الحزمة إلى العمل، افحص الملف الناتج بحثاً عن سياسة restart لكل خدمة، لأن الحزمة التي لا تتضمن هذه السياسة تبقى متوقفة بعد إعادة التشغيل. يشرح إعادة تشغيل حزمة Docker Compose بعد إعادة التشغيل إعداد جانب systemd.

عندما لا يعود ERPNext مريحاً على VPS واحد

يمكن لـVPS واحد أن يستضيف شركة صغيرة مدة طويلة. وتظهر علامات أن قدرته لم تعد كافية عندما:

  • تتراكم المهام في الخلفية، فتصل رسائل البريد الإلكتروني وعمليات الاستيراد بعد دقائق أو ساعات.
  • تسجّل حاويات docker inspect قيمة "OOMKilled": true أو رمز خروج 137.
  • تستغرق التقارير التي كانت تحتاج إلى ثانيتين 30 ثانية، وتكون MariaDB العملية التي تستهلك CPU.
  • تستغرق عمليات النسخ الاحتياطي وقتاً يكفي لتتداخل إحدى العمليات مع العملية المجدولة التالية.

ابدأ بتخصيص موارد لا تشاركها MariaDB مع غيرها، لأن قاعدة البيانات وعمال Python يتنافسون على الذاكرة نفسها، ولأن buffer pool هو الجزء الذي يحتاج إلى مزيد منها. يساعد خادم تطبيقات أكبر بدرجة أقل مما يتوقعه كثيرون. يشرح تشغيل قاعدة البيانات في Docker أو على المضيف هذا القرار، بينما يضمن ضبط حدود الذاكرة في Docker Compose ألا تتسبب حاوية واحدة في حرمان الحاويات الأخرى من الموارد أثناء إجراء التغيير.

بعد ذلك، أضف عمالاً لمعالجة قوائم الانتظار بدلاً من زيادة سعة الويب. العمل البطيء في ERPNext يحدث في الخلفية، مثل إنشاء التقارير وعمليات الاستيراد المجمّعة. تكلف حاويات العمال الإضافية أقل من خادم أكبر، وتعالج المشكلة التي يشتكي منها المستخدمون فعلياً.

FAQ

ما مقدار RAM الذي يحتاج إليه ERPNext على VPS؟

تبدأ الإرشادات المنشورة من 4 GB مع 2 vCPU، وهذه الفئة مخصصة للتقييم فقط. بالنسبة إلى شركة تستخدمه يومياً، خطط لاستخدام 8 GB و4 vCPU مع 100 GB من SSD. عند استخدام موارد أقل، يوقف قاتل نفاد الذاكرة في kernel الحاويات أثناء الحمل، وتُبلغ docker inspect عن ذلك بوصفه "OOMKilled": true مع exit code 137. هذه نقاط بداية وليست قياسات فعلية، لذلك راقب استخدام الذاكرة لديك خلال الشهر الأول.

هل يمكنني تشغيل pwd.yml في بيئة الإنتاج؟

لا. يصف README الخاص بالمشروع هذا الملف بأنه مخصص للتقييم قصير الأجل فقط، ويذكر أنه لا يمكنك تثبيت تطبيقات مخصصة فيه. استخدم compose.yaml مع تجاوزات MariaDB وRedis وHTTPS، ثم أنشئ منها ملفاً واحداً باستخدام docker compose config وشغّل ذلك الملف.

لماذا يتعذر الوصول إلى موقع ERPNext بعد إنشائه مباشرة؟

تختار الواجهة الأمامية الموقع الذي ستخدمه من رأس HTTP Host افتراضياً، لذلك يجب أن يطابق اسم الموقع النطاق الموجود في المتصفح. لا يُخدَم موقع أُنشئ باسم erpnext على erp.example.com. أنشئ الموقع باستخدام النطاق اسماً له، أو اضبط FRAPPE_SITE_NAME_HEADER في ملف env على اسم الموقع، ثم أنشئ ملف compose مرة أخرى وأعد تشغيل الـstack.

ما الملفات المطلوبة في نسخة 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، فعّل وضع الصيانة، وغيّر ERPNEXT_VERSION في ملف env، ثم أنشئ ملف compose مرة أخرى، واسحب الصور، وشغّل الـstack، ثم نفّذ bench --site erp.example.com migrate وعطّل وضع الصيانة. انتقل إصداراً رئيسياً واحداً في كل مرة، واقرأ ملاحظات الإصدار أولاً، لأن migrate يعيد كتابة المخطط وبيانات المستندات من دون إمكانية التراجع. تعني العودة إلى الإصدار السابق استعادة النسخة الاحتياطية التي أنشأتها في البداية.