SSD Nodes Learn Hosting plans →
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-08-24

كيفية تشغيل ERPNext على VPS باستخدام Docker

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

ما الذي ستشغّله عند التسجيل

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

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

يستخدم هذا الدليل مستودع frappe_docker، وهو النشر الذي يحافظ عليه المشروع. اختُبرت كل الأوامر أدناه مقابل هذا المستودع في August 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 تشغيل المكدس، ثم يتوقف عند أول عملية استيراد أو أول تقرير طويل، لأن تسع حاويات طويلة التشغيل، إضافة إلى تجمع المخازن المؤقتة في MariaDB، وPython worker ينشئ تقريراً، لا تتسع لها تلك الذاكرة. لا يحدث الفشل بطريقة سلسة. يوقف kernel out of memory killer إحدى الحاويات، ثم يعرض docker inspect عليها "OOMKilled": true مع exit code 137. ويؤدي إيقاف worker أثناء تنفيذ المهمة إلى ترك مستند مُرسَل وقد اكتمل عمله في الخلفية جزئياً فقط.

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

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

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

HTTPS، وما يجب أن يكون صحيحاً قبل أن يعمل

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

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

لا تحاول إرسال البريد مباشرة من 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 بدلاً من سطر الأوامر، حتى تُخزَّن القيمة مشفّرة ولا تدخل أبداً في سجل أوامر shell.

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

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

البريد الصادر مهمة تعمل في الخلفية، لذلك تظهر الرسالة التي لا تصل عادةً كمهمة فاشلة في ذلك السجل، لا كخطأ في المتصفح. انشر أيضاً سجلات SPF (sender policy framework) وDKIM (domainkeys identified mail) لنطاق الإرسال، ثم أضف سياسة 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>'

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

احذف موقع الاختبار عند الانتهاء:

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

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 المفاضلات بين الخيارين.

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

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

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

FAQ

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

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

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

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

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

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