تثبيت Discourse على VPS باستخدام Docker
ثبّت Discourse عبر المشغّل الرسمي لـ Docker، وتعرّف إلى متطلبات RAM وswap، واسم النطاق الحقيقي، وSMTP، وملف app.yml، ثم أعد البناء وفعّل TLS.
ثبّت Discourse على VPS: حاوية واحدة، وملف إعداد واحد
لتثبيت Discourse على VPS، شغّل أداة التثبيت الخاصة بالمشروع، وأجب عن أسئلة المعالج القصير، ثم انتظر اكتمال البناء. يُوزَّع Discourse في حاوية Docker واحدة تضم تطبيق Rails وPostgreSQL وRedis وnginx. توجد كل الإعدادات التي ستغيّرها لاحقاً في ملف واحد هو /var/discourse/containers/app.yml، وتصل كل التغييرات إلى الموقع عبر إعادة البناء.
التثبيت الرسمي هو discourse_docker: نص shell برمجي launcher ومجموعة من قوالب YAML. لا يدعم Discourse ملف Compose تكتبه بنفسك، كما أن الحاوية ليست مصممة لتقسيمها يدوياً. إذا كنت معتاداً على تشغيل الخدمات على VPS باستخدام Docker Compose، فتوقّع بنية مختلفة. لا يوجد docker compose up -d هنا، و./launcher rebuild app هو عملية النشر.
ما يحتاج إليه Discourse قبل البدء
هناك 4 متطلبات تفاجئ المستخدمين، ويظهر أثر كل منها قبل الوصول إلى صفحة تسجيل الدخول.
- الذاكرة. يشغّل حاوي واحد PostgreSQL وRedis وSidekiq وخادم ويب Ruby. وتترجم خطوة البناء الأصول، وتحتاج إلى ذاكرة أكبر من الموقع أثناء تشغيله.
- اسم نطاق حقيقي. يذكر نموذج الإعداد المرفق ذلك بوضوح: "لن يعمل Discourse باستخدام عنوان IP مجرد."
- مسار لإرسال البريد الصادر. تُرسل رسائل تفعيل الحساب، وإعادة تعيين كلمات المرور، ودعوات المسؤولين، والرسائل الموجزة عبر SMTP (بروتوكول نقل البريد البسيط).
- أن يكون المنفذان 80 و443 متاحين على المضيف، ما لم تنقل Discourse عمداً خلف proxy تديره مسبقاً.
The data behind this chart
[
{
"label": "Documented minimum",
"ram_gb": 1,
"storage_gb": 10
},
{
"label": "Documented recommended",
"ram_gb": 2,
"storage_gb": 20
}
]يحدد مستند التثبيت الرسمي الحد الأدنى عند 1 GB من RAM مع swap، وعند 10 GB من مساحة القرص، ويوصي باستخدام 2 GB من RAM مع 20 GB من مساحة القرص. اقرأ الصف الأول على أنه الرقم الذي يتيح للمثبّت إكمال عمله، لا الرقم الذي تحتاج إليه لتشغيل مجتمع. هذا الفرق مهم لأن ذروة استهلاك الذاكرة تحدث أثناء البناء، لا بسبب حركة المرور.
وجّه النطاق إلى الخادم قبل التثبيت
أنشئ سجلاً من نوع A لاسم المضيف الذي ستستخدمه، ثم تحقّق منه من الخادم نفسه.
dig +short forum.example.com
curl -4 -s https://ifconfig.coيجب أن يعرض الأمران العنوان نفسه. يجب أن يتطابقا لأن معالج الإعداد يختبر الاتصال باسم المضيف، ويفشل هذا الاختبار إذا كان السجل لا يزال يشير إلى مكان آخر. قد يظل السجل الذي أنشأته قبل دقيقتين مخزناً مؤقتاً أيضاً، لذلك انتظر حتى تنتهي مدة TTL القديمة (مدة البقاء) بدلاً من محاولة تجاوز المعالج.
حدّد الآن ما إذا كان CDN سيعمل كوكيل للسجل. يخفي السجل الذي يعمل كوكيل عنوان خادمك، ولذلك يفشل طلب الشهادة من الحاوية، لأن الوكيل يجيب عن تحدي ACME (بيئة إدارة الشهادات التلقائية) بدلاً من Discourse. اترك السجل دون وكيل أثناء التثبيت الأول.
تشغيل برنامج التثبيت الرسمي
يُثبّت أمر واحد git، ويثبّت Docker باستخدام برنامج التثبيت الخاص بـDocker، وينسخ discourse_docker إلى /var/discourse، ثم يبدأ معالج الإعداد.
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bashإذا كان Docker مثبتاً على الخادم وتفضّل رؤية كل خطوة، فنفّذ العملية نفسها يدوياً.
sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
./discourse-setupشغّله بصفة root. إذا شغّلته كمستخدم عادي، يتوقف discourse-setup فوراً مع This script must be run as root. Please sudo or log in as root first.. وإذا لم يكن Docker مثبتاً على الخادم، يتوقف مع Docker is not installed. Please install Docker first.، لأن النسخ اليدوي للمستودع لا يثبت أي شيء نيابةً عنك.
ما يطلبه معالج الإعداد وما يكتبه
اعتباراً من August 2026، discourse-setup عبارة عن غلاف رفيع. يشغّل discourse/setup-wizard:release في حاوية مع استخدام شبكة المضيف وربط Docker socket، حتى يتمكن المعالج من فحص الجهاز الذي يضبطه. يطلب اسم المضيف وعناوين البريد الإلكتروني للمسؤول، ثم يطلب إعدادات SMTP. يكتب containers/app.yml، ثم يعيد عملية البناء.
ينبغي معرفة سلوكين قبل البدء. إذا كانت ذاكرة الجهاز غير كافية ولم يكن هناك swap، يتوقف المعالج ويعرض إنشاءه. ينشئ الغلاف عندئذٍ /swapfile بحجم 2 GB، ويضيفه إلى /etc/fstab، ويضبط vm.swappiness = 10 في /etc/sysctl.d/30-discourse-swap.conf، ثم يعيد تشغيل المعالج. عند انتهاء المعالج، يطبع Rebuilding app in 5 seconds (Ctrl+C to cancel)... ويشغّل ./launcher rebuild app على المضيف. تستغرق عملية البناء هذه عدة دقائق على VPS صغير. ويكون البناء الأول هو الأبطأ، لأن كل أصل يُجمَّع من البداية.
يسرد ./discourse-setup --help الخيارات المهمة عند حدوث مشكلة. يكتب --skip-rebuild الإعدادات من دون تنفيذ البناء، بينما يتجاوز --skip-connection-test فحوصات DNS والمنافذ. استخدم --skip-connection-test فقط عندما تعرف سبب فشل الاختبار مسبقاً، مثلاً عندما يكون المضيف خلف جدار ناري للشبكة تتحكم فيه.
اقرأ app.yml قبل أول إعادة إنشاء
يكتب المعالج ملفاً أصبحت الآن مسؤولاً عن صيانته. افتحه باستخدام sudo nano /var/discourse/containers/app.yml. هذه هي الأجزاء التي تتحكم في كل شيء تقريباً.
templates:
- "templates/postgres.template.yml"
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
## Uncomment these two lines if you wish to add Lets Encrypt (https)
#- "templates/web.ssl.template.yml"
#- "templates/web.letsencrypt.ssl.template.yml"
expose:
- "80:80" # http
- "443:443" # https
env:
DISCOURSE_HOSTNAME: "forum.example.com"
DISCOURSE_DEVELOPER_EMAILS: "you@example.com"
DISCOURSE_SMTP_ADDRESS: smtp.example.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: user@example.com
DISCOURSE_SMTP_PASSWORD: "your-smtp-password"DISCOURSE_HOSTNAME هو العنوان الذي يستجيب عليه الموقع، ويبني Discourse روابطه اعتماداً عليه. لذلك تؤدي القيمة الخاطئة إلى تحميل الموقع مرة واحدة، ثم توجيهك إلى مكان آخر. DISCOURSE_DEVELOPER_EMAILS هي قائمة مفصولة بفواصل، وتُمنح هذه العناوين صلاحيات المسؤول تلقائياً عند أول تسجيل. ضع عنوانك فيها وسجّل به، لأن هذه هي الطريقة التي يُنشأ بها حساب المسؤول الأول.
يخزّن الملف كلمة مرور SMTP بنص واضح، لذلك قيّد الوصول إلى الدليل باستخدام sudo chmod 700 /var/discourse/containers. الملف مكتوب أيضاً بتنسيق YAML، ما يعني أن المسافات البيضاء جزء من الإعدادات. يؤدي عدم محاذاة مفتاح إلى فشل عملية الإنشاء بسبب خطأ في التحليل، ويتركك من دون موقع. توجد حالة شائعة موثقة في ملف العينة نفسه. يبدأ # داخل كلمة مرور غير محاطة بعلامات اقتباس تعليقاً، لذلك ضع أي كلمة مرور تحتوي عليه بين علامتي اقتباس.
البريد الإلكتروني هو الخطوة التي تتسبب في فشل معظم عمليات التثبيت
اعتباراً من August 2026، يتيح لك المعالج تخطي إعداد SMTP واستخدام تسجيل الدخول عبر Discourse ID بدلاً منه، كما يتضمن app.yml مفتاح DISCOURSE_SKIP_EMAIL_SETUP مطابقاً، وتصفه الوثائق هناك بأنه يتخطى التحقق من إعداد البريد الإلكتروني. يُعد التخطي مناسباً لإلقاء نظرة أولى على البرنامج. لكنه خيار سيئ لمجتمع، لأن عدم توفر البريد الصادر يمنع أي شخص من تفعيل حساب أو إعادة تعيين كلمة مرور.
المشكلة العملية هي أن معظم موفري VPS يحظرون المنفذ الصادر 25، لذلك لن يسلّم خادم بريد عادي على الخادم الرسائل. استخدم relay موثّقاً على المنفذ 587، أو على المنفذ 465 مع TLS ضمني (أمان طبقة النقل). بالنسبة إلى 465، اضبط DISCOURSE_SMTP_FORCE_TLS: true، إذ توصي إعدادات العينة باستخدامه لهذا المنفذ. اختبر إمكانية الوصول من المضيف قبل إعادة الإنشاء.
nc -vz smtp.example.com 587النتيجة السليمة هي سطر واحد ينتهي بـ succeeded!. يعني توقف الأمر ثم انتهاء مهلته أن المنفذ محظور في المسار الصادر من VPS، ولا يمكن لأي إعداد في Discourse إصلاح ذلك. انتقل إلى منفذ يسمح به موفرك، أو اطلب من الموفّر فتحه.
بعد تشغيل الموقع، أرسل رسالة اختبار من صفحة Email في Admin، ثم اقرأ علامتي التبويب Skipped وBounced في الصفحة نفسها. يسجّل Discourse في هاتين العلامتين الرسائل التي رفض إرسالها والرسائل التي رفضها relay، كما يوضح سبب الرفض، وهذا أسرع من قراءة السجلات.
TLS: دع الحاوية تحصل على شهادتها الخاصة
إذا كان Discourse يملك المنفذين 80 و443، فاستخدم آلية الإصدار المضمّنة فيه. أزل التعليق عن سطري قالب SSL الموضحين أعلاه، ثم أعد البناء. يقود القالب acme.sh، ويخزّن الشهادات في وحدة التخزين المشتركة ضمن /shared/ssl، ويجددها وفق جدول زمني داخل الحاوية، ويضبط Discourse لفرض HTTPS.
يجب أن يظل المنفذ 80 قابلاً للوصول من الإنترنت كي ينجح ذلك، لأن استجابة تحدي HTTP تتم عبره. يمنحك جدار ناري يسمح بالمنفذ 443 فقط عملية بناء تكتمل، لكن الشهادة لا تُصدر أبداً. تحقّق من النتيجة باستخدام ./launcher logs app مباشرة بعد إعادة البناء.
هل تضع nginx أو Caddy أمام Discourse؟
إذا كان Discourse هو خدمة الويب الوحيدة على VPS، فلا تفعل ذلك. تحتوي الحاوية على nginx مضبوط مسبقاً، ويضيف Proxy ثانٍ قفزة إضافية، وشهادة أخرى لتجديدها، ومصدراً جديداً لأخطاء الرؤوس.
استخدم Proxy أمامه عندما يقدّم VPS نفسه مواقع أخرى. أضف templates/web.socketed.template.yml إلى قائمة القوالب، وعلّق سطري expose، واترك قالبَي SSL معلّقين أيضاً. عندئذ تستمع الحاوية على Unix socket في /var/discourse/shared/standalone/nginx.http.sock ولا تفتح أي منافذ، مما يحرر المنفذين 80 و443 لاستخدام Proxy الخاص بك.
server {
listen 443 ssl;
server_name forum.example.com;
location / {
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
}النقطتان الرأسيتان في نهاية .sock جزء من صيغة Unix socket في nginx، ويرفض sudo nginx -t الإعداد من دونهما. كما أن X-Forwarded-Proto ليست اختيارية. ينشئ Discourse روابط مطلقة، ولذلك سيصدر روابط http:// في صفحة HTTPS من دون هذا الرأس، وتحظرها المتصفحات باعتبارها محتوى مختلطاً. عند استخدام socket للحاوية، تصبح مسؤولية TLS عليك، لذا أصدر الشهادة على الخادم المضيف باستخدام Certbot على Ubuntu 24.04 وnginx. إذا لم تكن قد اخترت Proxy بعد، فتشرح مقارنة nginx وCaddy وTraefik المفاضلة التي تجريها.
إعادة البناء والترقية والأوامر التي ستستخدمها فعلياً
cd /var/discourse
./launcher rebuild appيدمر rebuild الحاوية قيد التشغيل، وينشئ حاوية جديدة من app.yml، ثم يشغّلها. يكون الموقع خارج الخدمة طوال عملية البناء، لذلك تعامل مع كل تغيير في الإعدادات على أنه توقف مجدول يستمر بضع دقائق.
لا تحتاج إلى ذلك عند تغيير القيم الموجودة تحت env: فقط. يعيد ./launcher destroy app && ./launcher start app إنشاء الحاوية من الصورة التي بنيتها مسبقاً، وتستغرق العملية ثواني. يغيّر أي شيء تحت templates: أو hooks: الصورة نفسها، ولذلك يتطلب إعادة البناء الكاملة.
تصل الترقيات بطريقتين. تُطبَّق الإصدارات الفرعية من واجهة الويب على /admin/upgrade، ويوفرها المكوّن الإضافي docker_manager الذي يستنسخه app.yml أثناء البناء. تأتي التغييرات على الصورة الأساسية أو القوالب من git.
cd /var/discourse
git pull
./launcher rebuild appتتسبب عمليات إعادة البناء في تعطل الخوادم الصغيرة، لأن تجميع الأصول يستهلك أكبر قدر من الذاكرة في النظام بأكمله. إذا توقفت عملية بناء في منتصفها، وظهر في dmesg سطر مثل Out of memory: Killed process يذكر عملية ruby، فهذا يعني نفاد الذاكرة أثناء البناء، حتى لو كان الموقع يعمل بشكل سليم قبل ذلك. أضف swap ثم شغّل إعادة البناء مرة أخرى.
./launcher logs app
./launcher enter app
./launcher cleanupيعرض logs مخرجات الحاوية، ويفتح enter shell داخلها، ويزيل cleanup الحاويات التي أُوقفت منذ أكثر من 24 ساعة. شغّل cleanup من وقت إلى آخر، لأن كل عملية إعادة بناء تترك حاوية قديمة، وقد تنفد مساحة القرص على VPS صغير من دون ملاحظة.
النسخ الاحتياطية، والملف الذي لا يتضمنه النسخ الاحتياطي
أنشئ النسخ الاحتياطية من صفحة Backups ضمن Admin. يُحفظ الأرشيف على المضيف في /var/discourse/shared/standalone/backups/default/. ويمكن تشغيل المهمة نفسها من shell.
cd /var/discourse
./launcher enter app
discourse backupيعكس discourse restore <filename> العملية، ويُرفض الاستعادة إلى أن تشغّل discourse enable_restore. وُضع هذا الحاجز حتى لا يتمكن أمر عابر من الكتابة فوق منتدى قيد التشغيل.
هناك فجوتان يجب أن تسدهما بنفسك. يتضمن الأرشيف قاعدة البيانات، ويتضمن الملفات المرفوعة فقط عندما يكون إعداد النسخ الاحتياطي الذي يشمل التحميلات مفعّلاً، لذلك تحقق من هذا الإعداد قبل الاعتماد عليه. ولا يتضمن الأرشيف app.yml مطلقاً، لذلك تحتاج عملية الاستعادة إلى VPS جديد إلى اسم المضيف وكتلة SMTP، ما يعني أيضاً نسخ ذلك الملف خارج الخادم.
يوجد الأرشيف كذلك على القرص نفسه الذي يستضيف الموقع الذي يحميه، وهذا لا يُعد نسخة احتياطية. انقله إلى مكان آخر وفق جدول زمني.
rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/ما مقدار RAM الذي يستهلكه المنتدى النشط
يضبط برنامج bootstrap القيمتين UNICORN_WORKERS وdb_shared_buffers استناداً إلى الذاكرة ووحدة المعالجة المركزية اللتين يكتشفهما، ويحدد نموذج الإعدادات الحد الأقصى للمخازن المشتركة عند ربع إجمالي الذاكرة. كل عامل unicorn هو عملية Ruby كاملة، ويشغّل Sidekiq المهام الخلفية إلى جانبها، لذلك يرتبط استهلاك الذاكرة بعدد الطلبات المتزامنة، لا بعدد الأعضاء المسجلين. المنتدى الهادئ الذي يضم بضع مئات من الأعضاء لا يمثل حملاً كبيراً. يعتمد الأمر عادةً بدرجة أكبر على ما تشاركه الخدمات الأخرى على الخادم، وإذا كانت تلك الخدمة مكتبة صور، فستوضحك الحدود الدنيا المقاسة لاستهلاك RAM في مقارنة PhotoPrism وImmich ما إذا كان لا يزال لدى إعادة بناء Discourse هامش كافٍ لإكمالها.
لا تحدد حجم الخادم استناداً إلى رقم ورد في مقالة، بما في ذلك هذه المقالة. قِس احتياجاتك بنفسك.
free -m
docker stats --no-streamيعني استخدام Swap باستمرار مع بطء الصفحات أن RAM غير كافية. أما استقرار الذاكرة مع بطء الصفحات فيعني عادةً أن السبب مختلف، لذلك اقرأ ./launcher logs app قبل شراء خطة أكبر. أضف أيضاً فحصاً من خارج الخادم، لأن المنتدى الذي تنفد ذاكرته عند الساعة 3am يتوقف عن العمل بصمت: يتيح لك مراقب حالة Uptime Kuma مستضاف ذاتياً على مضيف منفصل معرفة المشكلة قبل أعضائك.
عندما لا يكون Discourse الخيار المناسب
Discourse تطبيق كبير، ويتطلب تثبيتاً ثقيلاً وإعادة إنشاء في كل مرة تغيّر فيها إعداداً موجوداً في app.yml. يوفّر هذا الثمن أدوات حقيقية لإدارة الإشراف، ومحرك بحث يظل يعمل حتى عندما يكون الأرشيف كبيراً. إذا كان لديك ثلاثون شخصاً يريدون مساحة للنقاش، فسيكون أكبر من احتياجات هذا النقاش. اقرأ أولاً مقارنة برمجيات المنتديات ذاتية الاستضافة، واختر Discourse لأنك تريد الوظائف التي يوفّرها، لا لأنه الاسم الذي تعرفه مسبقاً.
FAQ
هل يمكنني تثبيت Discourse على VPS من دون اسم نطاق؟
لا. ينص الإعداد المرفق على أن Discourse لن يعمل باستخدام عنوان IP مجرد، وأن DISCOURSE_HOSTNAME مطلوب. ينشئ Discourse الروابط المطلقة من اسم المضيف هذا، لذلك يؤدي وضع عنوان IP هناك إلى كسر الروابط ومنع إصدار الشهادة. أنشئ سجل A قبل البدء، وتحقق باستخدام dig +short forum.example.com من أنه يُحل إلى عنوان خادمك.
هل يجب أن أضبط SMTP لإكمال التثبيت؟
اعتباراً من August 2026، يمكنك تخطي ذلك. يوفّر معالج الإعداد عمليات تسجيل الدخول عبر Discourse ID بدلاً منه، ويتضمن app.yml مفتاحاً يتجاوز التحقق من إعداد البريد الإلكتروني. لكن بالنسبة إلى أي استخدام يتجاوز التجربة الأولية، اضبطه، لأن تفعيل الحسابات وإعادة تعيين كلمات المرور يُرسلان عبر البريد. استخدم مرحّل SMTP موثّقاً على المنفذ 587 أو 465، لأن معظم مزوّدي VPS يحظرون المنفذ الصادر 25.
لماذا فشلت إعادة بناء Discourse في منتصف العملية؟
الذاكرة هي السبب المعتاد. تحتاج عملية تجميع الأصول أثناء البناء إلى ذاكرة أكبر من الموقع أثناء تشغيله، لذلك قد يفشل خادم يشغّل المنتدى بشكل جيد في إعادة بنائه. إذا عرض dmesg قيمة Out of memory: Killed process تتضمن اسم عملية ruby، فأضف swap وشغّل ./launcher rebuild app مرة أخرى. أما توقف البناء بسبب خطأ YAML فيشير بدلاً من ذلك إلى خطأ في المسافة البادئة داخل app.yml.
هل ينبغي أن يعمل Discourse خلف nginx أو Caddy الخاص بي؟
فقط عندما يقدّم VPS مواقع أخرى أيضاً. إذا كان Discourse هو الخدمة الوحيدة على الخادم، فاترك للحاوية المنفذين 80 و443 وأصدر الشهادة بنفسها، فهذا يقلل عدد المكونات التي يجب إدارتها. لمشاركة الخادم، أضف templates/web.socketed.template.yml، وعلّق أسطر expose، ومرّر الطلبات إلى مقبس Unix الموجود في /var/discourse/shared/standalone/nginx.http.sock. مرّر X-Forwarded-Proto، وإلا فسيصدر Discourse روابط http:// داخل صفحة HTTPS.
كيف أنشئ نسخة احتياطية من Discourse المستضاف ذاتياً؟
استخدم صفحة النسخ الاحتياطية في Admin، أو شغّل discourse backup بعد ./launcher enter app. تُحفظ الأرشيفات على المضيف في /var/discourse/shared/standalone/backups/default/. تأكد من تفعيل الإعداد الذي يضمّن الملفات المرفوعة، وانسخ /var/discourse/containers/app.yml إلى جانب الأرشيف، ثم انقل كليهما إلى جهاز آخر، لأن النسخة الاحتياطية الموجودة على القرص نفسه الذي يوجد عليه الموقع لا تصمد أمام العطل الذي أُنشئت النسخة للحماية منه.