لقد مضت عدة سنوات وأنا أدير منتدى Discourse يحتوي على كمية كبيرة من المحتوى وصورًا كثيرة. يحتوي Maker Forums على أكثر من 100 جيجابايت من الصور وأكثر من 400,000 منشور، تم استيراد جزء كبير منها، بشكل أساسي من Google+، وتم إنشاء الباقي على الموقع. يصف هذا المنشور عناصر كيفية تكويني لـ Maker Forums في النهاية، وفي وقت لاحق، بعض حالات Discourse الأخرى. هذه هي المعلومات التي أتمنى لو أنني عرفتُها عندما بدأت، والتي استخدمتها لمساعدة الآخرين على تجنب بعض المزالق نفسها في حالات Discourse الخاصة بهم.
حان الوقت للوصول إلى جمهور أوسع.
تحذير: إذا لم تكن مرتاحًا للعمل كمسؤول أنظمة Linux، فإن هذا الدليل ربما لا يناسبك. قد لا أكون على دراية بجميع الطرق التي يفترض بها معرفة Linux. إذا شعرت أن القراءة مضيئة، فقد تكون أنت الجمهور المستهدف. إذا شعرت أن القراءة مربكة، فأنت على الأرجح لست من الجمهور المستهدف. إذا شعرت أن هذا عمل، يرجى التفكير في دفع رسوم لـ CDCK أو @pfaffman لتشغيل Discourse نيابة عنك؛ فهم يعرفون ما يفعلونه. أو ابدأ بموقع discourse.group المجاني، ثم ادفع مقابل ما ينمو إليه.
وكأن ذلك لا يكفي: لدي خبرة أكبر في Linux منها في Discourse. آرائي لا تأتي مع أي ضمان. إذا تسبب اتباع نصائحي في كسر أي شيء لك (منتدى Discourse الخاص بك، نظام التشغيل المضيف، أو قلبك)، فستحتفظ بالقطعتين، مع جميع الحواف الحادة. لا أخطط لتقديم أي شكل من أشكال الدعم للمحتوى في هذا المنشور.
أخطط (لكنني لا أضمن) لإبقاء هذا المستند محدثًا مع ممارساتي التي تغطي حالات Discourse التي أشارك في صيانتها. كُتب هذا النص على شكل نصيحة، لكنني أقصده في المقام الأول كنصيحة لنفسي ولأي مسؤولين يرثون نشرات Discourse التي كنت مسؤولاً عنها. بخلاف ذلك، يجب أن تعتبره نقطة انطلاق واحدة لـ بحثك الخاص لتحديد كيفية رغبتك في نشر Discourse.
إعداد النظام
استخدم نظام تشغيل مشتق من CentOS أو Ubuntu LTS. يمكن على الأرجح جعل أي شيء يدعم Docker يعمل، لكنني استخدمت هذين النظامين.
Docker
أنا مستخدم Fedora. كنت أول قائد مشروع Fedora في Red Hat، وكنت أفضل تشغيل Discourse فوق Podman لأنني أرى أن نموذج أمانه أفضل من نموذج Docker. ومع ذلك، لا يتم دعم نشرات Discourse إلا على Docker، وستكون رائدًا كبيرًا إذا حاولت التشغيل فوق أي شيء آخر. (قد يعمل في يوم من الأيام مع Podman باستخدام podman-compose إذا تم دعم docker-compose يومًا ما.)
الآن أن Docker يدعم cgroups v2، يمكنك تثبيت Builds الرسمية لـ Docker على نظام مشتق من CentOS:
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install --allowerasing docker-ce docker-ce-cli
(تضمين --alloweraseing بسبب تعارض مع podman، runc، و buildah التي قد تكون مثبتة بالفعل؛ يلزم حذفها لتثبيت docker.)
systemctl enable --now docker
لقد اختبرت هذا مع AlmaLinux 9.
الأمان
لا علاقة لهذا القسم بـ Discourse per se، لكنه جزء من ممارساتي الأمنية العادية. لا تسمح بالوصول إلى shell بكلمة مرور فقط لأي نظام على الشبكة، بما في ذلك VM يعمل Discourse. قم بإعداد الوصول عبر SSH باستخدام مفتاح SSH مشفر بعبارات مرور، وقم بتكوين خادم ssh على جهازك الافتراضي لعدم السماح بالوصول بكلمة المرور.
laptop$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/.../.ssh/id_rsa):
Enter passphrase (empty for no passphrase): SOME LONG PHRASE
Enter same passphrase again: SOME LONG PHRASE
Your identification has been saved in .ssh/id_rsa
Your public key has been saved in .ssh/id_rsa.pub
عادةً ما تكون توزيعات Linux مهيأة لتذكر عبارة المرور في الذاكرة، لذا عليك فقط كتابتها مرة واحدة عند كل إقلاع. Windows ليس مريحًا بنفس القدر؛ قد تفكر في استخدام Pageant مع PuTTY للقيام بذلك.
أولاً، تحقق من أن وصول SSH الوارد يعمل دون كلمة مرور. فقط بعد القيام بذلك، على الخادم، قم بتعديل الملف /etc/ssh/sshd_config وابحث عن السطر PasswordAuthentication. اضبطه على no لتعطيل الوصول الوارد بكلمة المرور.
PasswordAuthentication no
جدار الحماية
ستحتاج إلى ترك المنافذ 80 و 443 مفتوحتين بشكل عام لـ letsencrypt لتوليد وتجديد شهادات SSL الخاصة بك، حتى قبل أن يصبح Discourse الخاص بك مفتوحًا للجمهور.
إذا كنت تستخدم firewalld، ستحقق هذه الأوامر ذلك:
firewall-cmd --add-service http --add-service https --zone public
firewall-cmd --runtime-to-permanent
جهاز ونظام ملفات منفصل
اجعل /var/discourse/shared جهازًا منفصلًا بنظام ملفات خاص به، بسعة 20 جيجابايت بالإضافة إلى مساحة ضعف ما تحتاجه للصور على الأقل؛ أضف مساحة أكثر إذا كنت ستستخدم prometheus. إذا كان الجهاز سهل التوسع لاحقًا (مثل LVM أو أي تخزين كتلي سحابي مثل AWS elastic block storage) يمكنك مراقبته وتوسيعه حسب الحاجة؛ وإلا كن كريمًا في البداية. إذا كنت تستخدم جهاز تخزين كتلي شبكي، فلا تضع جدول تقسيم عليه. استخدام الجهاز دون جدول تقسيم سيجعل التوسع أسهل؛ لن تضطر إلى تعديل جدول تقسيم. في العديد من الحالات، ستتمكن من التوسع دون أي توقف للنظام.
على Maker Forums، هذا هو جهاز تخزين كتلي شبكي متصل بـ VM الذي يعمل عليه Maker Forums. على منتدى Discourse آخر، هو Digital Ocean Block Storage Volume. في Amazon، سيكون هذا AWS Elastic Block Storage. على نظام الاختبار الخاص بي الذي يعمل VM KVM تحت libvirt على Fedora، هو ملف LVM على مضيف Fedora مُصدّر إلى VM AlmaLinux كقرص افتراضي. في كل حالة، يمكنني إنشاء VM جديد، نسخ الملفات الرئيسية إليه، إيقاف VM القديم، ربط ملف /var/discourse/shared بـ VM الجديد، والعودة للعمل في دقائق. هذا يجعل ترقيات نظام التشغيل على VM منخفضة المخاطر نسبيًا.
تأكد من أن تبدأ بمساحة 25 جيجابايت على الأقل على نظام الملفات الجذر لـ VM الخاص بك، باستثناء أي مساحة لـ /var/discourse/shared. سيتم استخدام هذا لجميع حاويات docker، وسيخفق discourse launcher إذا كانت المساحة الحرة أقل من 5 جيجابايت في أي وقت. تريد أيضًا توفر مساحة كافية لتحديثات النظام. إذا لم يكن لديك مساحة قرص كافية، فمن الصعب التعافي من ذلك.
في تكوين الموقع، اضبط force_https لكن انتبه للتحذيرات. قم بإعداده في الاختبار، قبل جعل موقع Discourse عامًا. لاحظ أنه حتى مع force_https تحتاج إلى فتح المنفذ 80، لإعادة التوجيه إلى SSL على المنفذ 443 وتجديد شهادة SSL الخاصة بـ letsencrypt. (ومع ذلك، إذا كنت تستخدم cloudflare، استخدم ميزته بدلاً من ذلك؛ يُبلغ عن عدم توافقه مع force_https في Discourse.)
تكوين النواة
يوصي Redis (أحد المكونات الرئيسية التي يُبنى عليها Discourse) بإيقاف الصفحات الكبيرة الشفافة عند استخدام الاستمرارية على القرص (وهو ما يفعله Discourse)، وأسمح أيضًا بفرط تخصيص الذاكرة.
echo 'w /sys/kernel/mm/transparent_hugepage/enabled - - - - never
w /sys/kernel/mm/transparent_hugepage/defrag - - - - never' > /etc/tmpfiles.d/thp.conf
systemd-tmpfiles --create
echo 'vm.overcommit_memory=1' > /etc/sysctl.d/90-vm_overcommit_memory.conf
sysctl --system
تثبيت Discourse
بينما يكون التثبيت الافتراضي حاوية واحدة، فإن هذا يجعل كل ترقية، يُوصى بها شهريًا، عادةً توقفًا لمدة 10-15 دقيقة إذا تم من سطر الأوامر، وهو ضروري لبعض التحديثات، بما في ذلك تلك التي تحدّث الأدوات التي يُبنى عليها Discourse، للأمان أو الميزات الجديدة، أو عندما يفشل التحديث المباشر من واجهة المستخدم لأي سبب. يمكنك تقليل وقت التوقف هذا عمليًا باستخدام تثبيت الحاويتين.
تثبيت الحاويتين
ابدأ التكوين بحاويتين.
./discourse-setup --two-container --skip-rebuild
${EDITOR:-nano} containers/data.yml
./launcher rebuild data
# تفضيلي استخدام app.yml لكن قد تلتزم بـ web_only.yml، اقرأ النص
mv containers/web_only.yml containers/app.yml
${EDITOR:-nano} containers/app.yml
./launcher rebuild app
هذا يجعل وقت التوقف الإلزامي للنظام كل بضعة أشهر قصيرًا جدًا، نادرًا ما يُلاحظ؛ قد لا يلاحظه العديد من المستخدمين على الإطلاق إذا لم ينقروا أو يلفوا إلى ما بعد المحتوى أثناء الانقطاع. هذا يسهل تطبيق معظم تحديثات الأمان؛ فهو مجرد وميض بدلاً من إعادة بناء كل شيء لمدة 15 دقيقة تقريبًا. تعمل العملية التالية لمعظم التحديثات وتعطي عادةً حوالي 30-90 ثانية من وقت التوقف، اعتمادًا بشكل أساسي على أداء نظام المضيف ومجموعة الإضافات المثبتة.
cd /var/discourse
git pull
./launcher bootstrap app
./launcher destroy app && ./launcher start app
./launcher cleanup
لا تؤخر بين استدعاءات bootstrap و destroy/start. بشكل غير متكرر (ربما مرة أو مرتين في السنة عمليًا)، ستسبب هجرات قاعدة البيانات التي تتم في نهاية مرحلة bootstrap أخطاء أكثر أو أقل خطورة للمستخدمين في التطبيق، بسبب وصول الكود الأقدم إلى قاعدة البيانات المحدثة.
هذا يعني أنه عندما تقوم بتحديث Discourse، يجب عليك أيضًا التحقق مما إذا كان يجب تحديث حاوية البيانات أيضًا، لكن هذا نادرًا ما يكون مطلوبًا (تتوقع عادةً مرة أو مرتين في السنة). اعتمادًا على محتوى حاويات البيانات والتطبيق الخاصة بك وسرعة النظام، سيؤدي هذا عادةً إلى توقف بين 5 و 20 دقيقة.
cd /var/discourse
git pull
./launcher stop app
./launcher rebuild data
./launcher rebuild app
لمعرفة المزيد حول متى يجب تحديث حاوية البيانات، راجع:
(في نشراتي الخاصة، اخترت شخصيًا تسمية حاوية web_only باسم app لأنها أسهل في الكتابة ولأنها تجعل معظم التعليمات أسهل في المتابعة. هذا غير قياسي لكنني أقدّر دائمًا سهولة الاستخدام. ومع ذلك، كان ذلك عملًا إضافيًا، ويعمل بالنسبة لي لأنني أعرف ما يحدث. إذا بدا ذلك سيئًا لك، التزم بـ web_only الافتراضي بدلاً من ذلك لنشر متعدد الحاويات.)
لاحظ أنه في مرحلة ما في المستقبل، قد يجبرك Docker على القيام بهجرة إلى تكوين جديد لربط حاوياتك:
إذا كان لديك 4 جيجابايت أو أكثر من الذاكرة، أو معالجات متعددة، اقرأ النصائح في:
جدول التحديث
راقب وسم release-notes (انقر على release-notes وانقر على الجرس في الزاوية العلوية اليمنى؛ أستخدم “مراقبة المنشور الأول”) و/أو أضف https://meta.discourse.org/tag/release-notes.rss إلى تغذية RSS الخاصة بك لمعرفة وقت الإصدارات. اقرأ ملاحظات الإصدار قبل التحديث. إذا كان هناك تغيير في قاعدة البيانات، ستذكره ملاحظات الإصدار. ستشير أيضًا إلى الإصدارات التي تحتوي على تحديثات أمنية. اقرأ جميع ملاحظات الإصدار حتى إذا تخطيت التحديث الفعلي إلى بعض الإصدارات؛ إذا لم تقرأ ملاحظات الإصدار لإصدار يحدث قاعدة البيانات، قد تفوتك تعليمات تحديث قاعدة البيانات في ملاحظات الإصدار التي لم تقرأها.
البريد
البريد لا يزال أحد الطرق الرئيسية لإبقاء الناس متصلين. قم بإعداد البريد الصادر والوارد لجعل البريد يعمل لصالحك. إذا واجهت مشكلة، راجع:
الاستمرار في التواصل
رأى Maker Forums زوارًا متفردين يغيبون لفترات طويلة قبل العودة. بشكل افتراضي، يتوقف Discourse عن إرسال رسائل البريد الإلكتروني الملخصة بعد عام. فكر في ضبط suppress_digest_email_after_days على شيء أطول من 365 يومًا الافتراضي إذا أردت تشجيع الزوار المتفردين على العودة عندما يرون شيئًا جديدًا ومثيرًا للاهتمام. جعلته أطول بكثير لـ Maker Forums لدعم الزوار المتفردين في مواكبة الأخبار. قراءة رسائل البريد الإلكتروني الملخصة هي طريقة صالحة لـ “التجسس” على المنتدى، وأنت لا تعرف أبدًا متى سيثير شيء ما اهتمام شخص ما بالمساهمة.
وبالمثل، بشكل افتراضي، يتم حذف المستخدمين غير المتمتعين بالامتيازات الذين لم يتفاعلوا كثيرًا (مستوى الثقة 0 بدون منشورات) في النهاية بعد 730 يومًا من عدم تسجيل الدخول. اضبط “تنظيف المستخدمين غير النشطين بعد أيام” على 0 لتعطيل حذف المستخدمين، إذا أردت أن يكونوا قادرين على التجسس لقراءة رسائل البريد الإلكتروني الملخصة إلى الأبد.
فكر في إضافة إضافة المراجعة السنوية التي ستولد منشورًا مثل 2020: The Year in Review وفي النهاية ترسله عبر البريد الإلكتروني إلى مستخدميك غير النشطين مما قد يشجعهم على تجديد مشاركتهم.
حاوية مستقبل البريد
قم بإعداد حاوية ثالثة كمستقبل للبريد. يضمن معالجة الارتداد، ويجعل معالجة الارتداد الخاصة بك مستقلة عن مزود البريد الصادر، ويعطيك خيار الرد عبر البريد الإلكتروني.
تأكد من إعداد SPF للثقة في مرسل البريد الإلكتروني الخاص بك؛ على الأقل، سياسة مثل v=spf1 +mx -all إذا كنت ترسل وتستقبل عبر نفس MX، لكن الأكثر تحديدًا قد يكون أكثر ثقة كحماية من البريد العشوائي. فكر في DKIM أيضًا.
إذا كنت تستخدم اسم المضيف نفسه لاستقبال البريد الإلكتروني، فيجب عليك حقًا إنهاء SSL خارج حاويتك كما في “صفحة غير متصلة” (انظر أدناه) وستحتاج إلى ربط شهادات certbot الخاصة بك في الحاوية وإعادة تشغيل الحاوية بعد تشغيل certbot.
إنهاء اتصالات SSL للمستخدم خارج الحاوية
هناك خياران لإنهاء SSL خارج الحاوية، أيهما يوفر مزايا كبيرة على الإنهاء داخل الحاوية. قم بإعداد أحدهما بعد إكمال discourse-setup بنجاح وتأسيس منتدىك.
nginx الخارجي
استخدم nginx يعمل على نظام المضيف، بدلاً من العمل فقط في حاوية، لاستضافة صفحة صيانة، ودعم تسجيل عناوين IPv6 إذا كان نظامك المضيف يدعم IPv6. (بخلاف ذلك، سيتم تسجيل جميع اتصالات IPv6 وكأنها قادمة من عنوان RFC1918 الداخلي المرتبط بواجهة الشبكة الافتراضية المحلية لـ docker الخاص بك.) سيقدم هذا التكوين صفحة صيانة مؤقتة أثناء معظم عمليات الصيانة التي ستعيد التوجيه في النهاية إلى الصفحة التي كان المستخدم ينظر إليها.
لاحظ أن التعليمات في تلك الصفحة (حاليًا) تقترح تثبيت حزمة تسمى letsencrypt لكنها تُسمى الآن عادةً certbot بدلاً من ذلك. إذا اتبعت التعليمات في تلك الصفحة لاستخدام --certonly، فلن تحتاج إلى إضافة nginx لـ certbot، لكن تثبيت إضافة nginx هو آلية أخرى. على مشتقات CentOS:
dnf config-manager --set-enabled crb
dnf install epel-release
dnf install certbot python3-certbot-nginx
systemctl enable --now certbot-renew.timer
تأكد من أن certbot يعيد تشغيل nginx وحاوية مستقبل البريد بحيث لا ينتهي بك الأمر بمتصفحات أو بريد إلكتروني يحظر حركة المرور مع موقعك بسبب الاستمرار في استخدام شهادة قديمة منتهية الصلاحية.
# systemctl edit certbot-renew
لنظام بدون مستقبل بريد، أضفت السطرين:
[Service]
ExecStartPost=/bin/systemctl reload nginx
على نظام أستخدم فيه حاوية مستقبل بريد منفصلة تشارك أيضًا الشهادة من النظام:
[Service]
ExecStartPost=/bin/systemctl reload nginx
ExecStartPost=/bin/sh -c 'cd /var/discourse && ./launcher restart mail-receiver'
إذا كنت تستخدم SELinux، فإن حاويات Ubuntu ليست مهيأة لتوسيم ملف nginx.http.sock بـ httpd_sys_content_t لتمكن nginx الخارجي من الوصول إليه. لديك خياران.
الأول هو تشغيل nginx في الوضع التصريحي، وإزالة حماية SELinux له: semanage permissive -a httpd_t
ومع ذلك، فإن ذلك يزيل حماية SELinux عن الخدمة الأكثر صلة على الأرجح! لإبقاء SELinux مفعّلًا، ستحتاج إلى السماح لـ nginx بالوصول إلى صفحات الخطأ والتبديل من التوجيه عبر unix domain socket إلى منفذ (وهو أبطأ بضع ميكروثانية، لكن لا ينبغي أن يلاحظه مستخدموك).
أولاً، قم بتشغيل هذه الأوامر للسماح لـ nginx بالوصول إلى صفحات الخطأ:
semanage fcontext -a -t httpd_sys_content_t /var/www
restorecon -R -v /var/www
ثم في ملف app.yaml الخاص بك، علّق أو احذف - "templates/web.socketed.template.yml"، وعرض المنفذ 80 كمنفذ مختلف على الجهاز المحلي وأعد بناء الحاوية.
expose:
- "8008:80" # http
لا تستخدم https هنا — لقد أنهيت SSL في nginx الخارجي، ويخبر رأس X-Forwarded-Proto Discourse أن الطلب جاء عبر https. تأكد من أن المنفذ 8008 (أو أي منفذ آخر اخترته) غير مُعرض للعامة بواسطة إعدادات جدار الحماية الخاص بك.
ثم قم بتشغيل هذا الأمر للسماح لـ nginx بالاتصال عبر الشبكة بالحاوية:
setsebool -P httpd_can_network_connect 1
ثم قم بتعديل تكوين nginx الخارجي الخاص بك من التوجيه عبر nginx.http.sock إلى http://127.0.0.1:8008 (أو المنفذ الذي اخترته) واضبط الرأس الافتراضي Connection: close على فارغ، بحيث لا يضطر nginx الخارجي إلى إنشاء اتصال IP جديد لكل طلب.
...
location / {
proxy_pass http://127.0.0.1:8008;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
# تعطيل "Connection: close" الافتراضي
proxy_set_header "Connection" "";
...
إزالة web.socketed.template.yml أزالت أيضًا استدعاء real_ip، لذا أضف ذلك مرة أخرى. تأكد من أن نطاق عنوان IP الذي تستخدمه منطقي؛ الافتراضي لـ Docker هو استخدام مساحة عناوين RFC1918 172.16* التي لا يتم توجيهها على الإنترنت العام حسب السياسة. أضف إلى ملف app.yml الخاص بك شيئًا مثل هذا في قسم التشغيل، واختيار واحد أو أكثر من مساحات عناوين RFC1918 أو أي شيء آخر مناسب لنشرك:
run:
- file:
path: /etc/nginx/conf.d/outlets/server/real-ip-recursive.conf
chmod: 644
contents: |
real_ip_recursive on;
- file:
path: /etc/nginx/conf.d/outlets/server/real-ip-header.conf
chmod: 644
contents: |
real_ip_header X-Forwarded-For;
- file:
path: /etc/nginx/conf.d/outlets/server/set-real-ip-from.conf
chmod: 644
contents: |
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 10.0.0.0/8;
هذا مطلوب لعمل تحديد معدل بشكل صحيح، وكذلك لتسجيل عناوين IP للتسجيل وآخر استخدام للمستخدمين.
لمزيد من المعلومات:
خدمة خارجية
لم أقم بتكوين Fastly أو Cloudflare أمام Discourse، لكن آخرين فعلوا، وعلى عكس nginx الخارجي الذي يعمل على المضيف، يمكن أن تسمح لك بتقديم صفحة صيانة بينما يكون نظام المضيف متوقفًا تمامًا، مثل عند إعادة التشغيل أثناء تحديث النظام على مضيفك. إذا كان ذلك يستحق الجهد بالنسبة لك، إليك كيفية القيام بذلك:
لا تستعجل في التحميلات إلى S3
تأكد تمامًا من أنك تريد دائمًا استخدام S3 (أو ما يعادله) للصور المحملة قبل تمكين enable_s3_uploads أثناء الإعداد، أو الهجرة إليه لاحقًا. كن على دراية بأن استخدام S3 (s3_endpoint) مع CDN المرتبط به (s3_cdn_url) للصور سيؤدي أيضًا إلى تقديم javascript عبر ذلك CDN. الهجرة من S3 مرة أخرى إلى التخزين المحلي غير مدعومة ولا توجد خطط ملموسة لتنفيذها في الوقت الحالي. إنها “باب ذو اتجاه واحد” لا يمكن حتى إلغاؤه عن طريق النسخ الاحتياطي والاستعادة الكاملة. إذا استخدمت S3 أو ما شابه، لا تستخدم Digital Ocean Spaces بدلاً من S3. هناك مراجع هنا على meta بأنها غير موثوقة.
نقلت موقعي لتقديم الصور عبر Digital Ocean Spaces و CDN المرتبط به في وقت مبكر، واضطررت إلى كتابة مئات الأسطر من الكود المخصص للهجرة مرة أخرى إلى التخزين المحلي، مما تسبب في أضرار طفيفة في نسخة Discourse الخاصة بي في العملية، بسبب عدم فهم “الباب ذو الاتجاه الواحد” جيدًا.
لمزيد من المعلومات:
لا تحتاج إلى تمكين تحميلات S3 لاستخدام CDN لـ Discourse الخاص بك. فكر في استخدام CDN مستقل (مثل Cloudflare، CloudFront، Fastly، GCS CDN) أمام Discourse يدير صوره الخاصة. فهمي غير المباشر هو أن التحذير من عدم التوصية بـ Cloudflare يرجع إلى تعديل “Rocket Loader” لـ JavaScript؛ وأن في الوقت الحالي، طالما أنك لا تستخدم “Rocket Loader” فإنه يعمل بشكل صحيح.
إعدادات Discourse للإشراف
على أي موقع يكون فيه الإشراف نشطًا، فكر بقوة في تكوين enable_whispers الذي يسمح للمشرفين والمديرين بالتحدث عن موضوع في السطر. أيضًا، تم منح مشرفي الفئات المزيد من القدرات في الإصدارات الأخيرة من Discourse. من الجيد أن تكون على دراية بـ enable_category_group_moderation إذا كان لديك خبراء في مواضيع مختلفة بفئاتهم الخاصة، أو إذا كان لديك فئات منفصلة وظيفيًا مثل الدعم.
يمكن أن يكون تحديد الموقع الجغرافي مفيدًا عند محاولة فهم ما إذا كانت الحسابات شرعية.
ميزة Discourse Templates مفيدة حقًا للمشرفين. تتيح لك التعاون على الردود الشائعة. لدينا بضع عشرات في Maker Forums. لديها المزيد من الميزات من إضافة “Canned Responses” السابقة التي تحل محلها.
ستساعد ميزة User Notes المشرفين على مشاركة ملاحظات حول المستخدمين. يمكنك استخدام هذه لأشياء مثل:
- “راقب هذا المستخدم، قد يكون ضارًا لأن …”
- “بينما يبدو هذا السلوك مشبوهًا، لقد تأكدت من أن هذا مستخدم شرعي عن طريق …”
- “أنا بالفعل في محادثة مع هذا المستخدم لمعالجة المخاوف، لا يحتاج المشرفون الآخرون إلى التزاحم.”
إمكانية الوصول إلى المعلومات
إضافة Discourse Solved لا تحدد فقط المشكلات المحلولة بحيث يمكن لزوار الموقع تحديدها بسهولة أكبر، لكنني أفهم أنها قد تعطي أيضًا الأولوية لنتائج بحث Google.
المعلومات العامة أكثر سهولة من المعلومات الخاصة. على Maker Forums، يُحذر FAQ بشدة من الرسائل الشخصية ويذكر الجميع بأن الرسائل الشخصية ليست خاصة حقًا. ومع ذلك، بشكل افتراضي، قد يرى المستخدمون الرسالة:
لقد رددت على user 3 مرات، هل كنت تعلم أنه يمكنك إرسال رسالة شخصية لهم بدلاً من ذلك؟
إذا أردت حقًا تشجيع المستخدمين على الذهاب إلى الرسائل الشخصية، أقترح أن تذهب إلى Admin → Customize → Text وتغيير قالب get_a_room لإصلاح فصل الفواصل.
إذا، مثل Maker Forums، أردت إبقاء المحادثة عامة لفائدة الجميع، يمكن ضبط Admin → Settings → Other → get_a_room_threshold على قيمة أعلى، مثل 1000000.
وبالمثل، إذا كان لديك منتدى يقدم المساعدة، قد يدفع الافتراضي max_replies_in_first_day 10 المستخدمين الجدد في محادثة يطلبون المساعدة إلى الرسائل الشخصية عندما يستنفدون ميزانية الردود الخاصة بهم. فكر في زيادة هذا الإعداد لتجنب دفع المحادثات إلى الرسائل الشخصية.
ربط المستخدمين، بناء مجتمع
بعض الإضافات يمكن أن تساعد في ربط المستخدمين ببعضهم البعض.
إذا لم يكن لديك منتدى به الكثير من المستخدمين المتزامنين، فكر في إضافة Who’s Online لإعطاء الناس شعورًا أكبر بالاتصال. قد ترغب في تقييد العرض للمستخدمين المسجلين الدخول، ربما فقط أولئك الذين وصلوا إلى مستوى ثقة 1 على الأقل. يمكنك استخدامه فقط لإضافة علامة حضور (whos_online_avatar_indicator) إلى الرموز التعريفية عن طريق ضبط whose_online_minimum_display على قيمة عالية جدًا و whos_online_hide_below_minimum_display على true. يمكن أن يكون هذا مفيدًا لمنتديات الدعم لدعم وتشجيع الأسئلة والإجابات السريعة أثناء مساعدة المستخدمين على حل المشكلات.
ومع ذلك، يمكن أن يكون شعور الحضور ذا حدين. قد يشعر المستخدم الذي يكون متصلًا في وقت مختلف عن أغلبية مستخدمي المنتدى بالوحدة، أو قد يبدو المنتدى كـ “مدينة أشباح” بالنسبة لهم.
إذا كان لديك مستخدمون في العديد من البلدان وتريد أن يكون لديهم تلميحات حول وقت احتمالية توفر بعضهم البعض، فكر في إضافة National Flags، وشجع المستخدمين على تعيين علم وطني في ملفاتهم التعريفية.
واحد معقد هو الترجمة. سيكون من المريح مساعدة الناس على التواصل عندما لا يتحدثون نفس اللغة، لكن حاليًا (حتى وقت كتابة هذا) لا توجد خدمات ترجمة ذات مستويات مجانية من الخدمة. إذا اخترت الدفع مقابل خدمات الترجمة، يمكنك تمكين الترجمة مع إضافة Discourse Translator.
النسخ الاحتياطي
لملفات النظام، فكر في النسخ الاحتياطي على الأقل لـ:
/var/discourse/containers(لتفاصيل تكوين discourse)/var/www(لصفحات الخطأ)/etc/ssl(لتكوين letsencrypt، لتجنب الحاجة إلى تأسيس certbot كجزء من استعادة النسخ الاحتياطي؛ وإلا عليك تعليق جزء SSL من تكوين nginx الخاص بك أثناء التأسيس؛ هذا يعمل فقط إذا حافظت على النسخ الاحتياطية حديثة لأن الشهادات لها صلاحية قصيرة)/etc/systemd/system/backup-uploads.service(لعمل نسخ احتياطية للصور إلى S3)/usr/local/bin/mc(minio-client كأداة نسخ احتياطي للصور، إذا اخترت استخدامه)/root/.mc(تكوين النسخ الاحتياطي للصور مع minio-client)/root/.ssh(مصادقة جلسات SSH الواردة)
بعض هذه الملفات قد تنسخها احتياطيًا عن طريق التحقق منها في Git ودفعها إلى مكان ما خارج الموقع. إذا كانت الملفات التي تتحقق منها في Git تتضمن أسرارًا (مثل كلمات مرور قاعدة البيانات)، فلا تدفعها بالتأكيد إلى مستودع عام. بديلاً، يمكنك برمجة نسخها خارج النظام والتحقق منها في Git على نظام إشرافي تتحكم فيه. برمج هذا بشكل متكرر بما يكفي لإبقاء نسخك الاحتياطية من /etc/ssl حديثة.
الهدف هو وجود نسخ احتياطية في حالة الكوارث ولوجود سجل للتغييرات في حالة الخطأ.
بديل أفضل لمعظم هذه الملفات هو إبقاء النسخ الأصلية في مكان آخر، واستخدام أداة مثل Ansible للحفاظ على التكوين على النظام، مما يجعله سهل التحديث بعد النسخ الاحتياطي. لكن إذا كنت ستفعل ذلك، فأنت على الأرجح قد توصلت إليه دون أن أخبرك!
تكوين Discourse للنسخ الاحتياطي
-
انسخ الصور المصغرة احتياطيًا مع
include_thumbnails_in_backups. تستغرق الاستعادة بدون صور مصغرة وقتًا طويلاً لإعادة توليدها. إذا لم يكن موقعك يحتوي على الكثير من الرسوميات، فإن الصور المصغرة تأخذ مساحة ضئيلة. إذا كان موقعك غنيًا بالرسوميات، فقد يستغرق إعادة توليد الصور المصغرة أيامًا. بينما يتم إعادة توليد الصور المصغرة، سيتم تعطيل إشعارات البريد الإلكتروني. بأي حال، لا معنى لإغفال الصور المصغرة من النسخ الاحتياطية. -
لا تتضمن الصور في النسخ الاحتياطية إذا كان لديك الكثير من الصور. هذا سيجعل النسخ الاحتياطية بطيئة وغير عملية. انسخها احتياطيًا بشكل منفصل. إذا نسخت الصور احتياطيًا بعد نسخ قاعدة البيانات احتياطيًا، ستكون نسخك الاحتياطية متسقة.
-
رتب لإرسال النسخ الاحتياطية إلى خارج الموقع بطريقة ما.
هذه الصفحة تظهر كيفية إعداد نسخ احتياطية لقاعدة البيانات إلى S3 أو شيء يشبه S3:
النسخ الاحتياطي مع restic
قم بتكوين discourse للنسخ الاحتياطي إلى نظام الملفات، ثم انسخ من نظام الملفات إلى هدف نسخ احتياطي بعيد مع restic. إليك وصفة عينة.
# dnf install restic
# mkdir /var/restic
# mkdir /opt/backup
# cd /opt/backup
# cat > backup <<EOF
#!/usr/bin/bash
set -e
. /opt/backup/backup-config
restic --cache-dir=/var/restic \
backup \
/etc \
/root \
/var/discourse \
/opt/backup \
--exclude /var/discourse/shared/data/postgres_data
restic --cache-dir=/var/restic forget \
--prune --keep-hourly 24 --keep-daily 7 --keep-monthly 3
EOF
# chmod +x backup
ستختلف هذه التفاصيل اعتمادًا على مستودع restic المستهدف. لا تستخدم جميعها متغيرات البيئة الخاصة بـ AWS، لذا اقرأ وثائق restic.
# cat > backup-config <<EOF
### تعتمد هذه التفاصيل على مستودع restic الذي تقوم بتكوينه، لذا قم بتغييرها
export AWS_ACCESS_KEY_ID=yours-here
export AWS_SECRET_ACCESS_KEY=same
export RESTIC_PASSWORD_FILE=/root/restic-password
export RESTIC_REPOSITORY=see-the-restic-documentation
EOF
# {$EDITOR:-nano} /root/restic-password
ستحتاج إلى تخزين نسخة مما تضعه في /root/restic-password وإلا لن تتمكن من قراءة النسخ الاحتياطية! استخدم خزانة كلمات المرور الخاصة بك.
أخيرًا، أنشئ بعض الخدمات، قم بتهيئة مستودع restic، وحدد مؤقتًا لبدء عمليات النسخ الاحتياطي.
# cat > /etc/systemd/system/backup.service <<EOF
[Unit]
Description=Back up to remote target
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
StandardOutput=file:/var/log/backup.out
StandardError=file:/var/log/backup.err
WorkingDirectory=/var/discourse
ExecStart=/opt/backup/backup
[Install]
WantedBy=multi-user.target
EOF
# cat > /etc/systemd/system/backup.timer <<EOF
[Unit]
Description=Regular system backups
[Timer]
Persistent=true
OnCalendar=00/4:30:00
Unit=backup.service
[Install]
WantedBy=timers.target
EOF
# systemctl daemon-reload
# . /opt/backup/backup-config
# restic init
# /opt/backup/backup
# systemctl enable backup.timer
بعد هذه العملية، يجب أن تتمكن من رؤية أنك أنشأت نسختك الاحتياطية الأولية.
# restic snapshots
لقد استخدمت بنجاح نسخ restic الاحتياطية التي تم إنشاؤها بهذه الطريقة لنقل خادم Discourse من نظام إلى آخر باستخدام أمر restic restore.
نسخ صور minio الاحتياطية المتدفقة
كبديل لـ Restic، بينما يمكن تخزين نسخ قواعد البيانات الاحتياطية في S3، فلا يوجد نسخ احتياطي للصور في S3 منفصل عن خدمة الصور من S3. بديل هو استخدام minio-client لنسخ الصور إلى أي تخزين يشبه S3. يمكن أن يكون هذا العديد من الأهداف المشابهة لـ S3، بما في ذلك S3 و minio، لكن ليس DigitalOcean Spaces لأنه مبنٍ على نظام ملفات Ceph الذي لا ينفذ واجهة برمجة التطبيقات ListObjectsV2 بنفس طريقة S3.
في S3، أنشئ دلوًا يمنع الوصول العام (Permissions → Block public access هي الطريقة السهلة لفعل ذلك بشكل صحيح في AWS).
قم بتثبيت minio-client (mc) بطريقة ما. إليك إحدى الطرق.
curl https://dl.min.io/client/mc/release/linux-amd64/mc > /usr/local/bin/mc && chmod +x /usr/local/bin/mc
قم بتكوين minio-client مع اسم مستعار يسمى backup باستخدام أمر شبيه بهذا:
# mc alias set backup https://s3.amazonaws.com ACCESSKEY SECRETKEY --api S3v4
# mc mirror /var/discourse/shared/standalone/uploads backup/UPLOADS-BACKUP-BUCKET
ثم أنشئ خدمة /etc/systemd/system/backup-uploads.service على هذا النحو
[Unit]
Description=Neartime remote backup sync of discourse uploads
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=600
User=root
ExecStart=/usr/local/bin/mc mirror --overwrite -a --watch /var/discourse/shared/app/uploads backup/UPLOADS-BACKUP-BUCKET
[Install]
WantedBy=multi-user.target
لاحظ أن UPLOADS-BACKUP-BUCKET هنا يجب أن يكون دلوًا مختلفًا عن s3_backup_bucket الذي تقوم بتكوين Discourse لرفع نسخ قواعد البيانات الاحتياطية إليه. أيضًا، لاحظ أن المسار سيكون /var/discourse/shared/web_only/uploads إذا استخدمت النشر متعدد الحاويات القياسي.
# systemctl enable backup-uploads
# systemctl start backup-uploads
# journalctl -fu backup-uploads
ارفع صورة اختبارية وتأكد من رؤية أسطر للنسخ الاحتياطي الناجح للصور الأصلية والمُحسّنة. سيؤدي Control-C إلى الخروج من وضع المتابعة في journalctl.
الاستعادة
لم أكن بحاجة إلى اختبار هذا الخطة حتى تاريخ كتابة هذا المقال. قد يفتقد هذا الملخص إلى شيء ما.
- استعادة جميع الملفات المحفوظة احتياطيًا بشكل عام
- ابدأ nginx (الآن ستظهر صفحة الصيانة الخاصة بك)
- قم بنشر Discourse طبيعي باستخدام الملفات المستعادة في /var/discourse/containers
- قم بتثبيت minio-client في /usr/local/bin/mc إذا لم تستعيده من النسخ الاحتياطية
- إذا لم تقم بحفظ
/root/mcاحتياطيًا، قم بتكوين اسم المستعار الاحتياطي# mc alias set backup https://s3.amazonaws.com ACCESSKEY SECRETKEY --api S3v4 # mc cp backup/UPLOADS-BACKUP-BUCKET /var/discourse/shared/app/uploads- استعادة أحدث نسخة احتياطية لقاعدة البيانات؛ أنصحك بـ Restore a backup from the command line
- فقط بعد أن تؤكد أن الموقع يعمل، أعد تكوين النسخ الاحتياطي للرفع إلى S3 كما هو موثق أعلاه.
نسخ postgresql الاحتياطية المتدفقة
في المستقبل، قد أقوم بإنشاء واختيار وتوفير تكوين لتمكين استخدام أرشفة WAL المستمرة لنسخ Postgres الاحتياطية الفورية تقريبًا باستخدام minio-client مع archive-command في postgresql، مشابهًا لنسخ الرفع الاحتياطية المتدفقة.
مراقبة الأداء
هناك نهجان على الأقل لمراقبة الأداء.
حاوية Prometheus
قم بتكوين prometheus، وضع سجلات prometheus في /var/discourse/shared/prometheus إذا كنت تشغله على نفس النظام. يمكن أن تنمو ملفات Prometheus بشكل كبير، وأنت لا تريد أن تمتلئ نظام الملفات الجذر؛ وأنت على الأرجح تريد إحضارها معك إذا انتقلت إلى نظام مضيف أحدث (إما الترقية إلى VM أكبر أو VM مع تثبيت نظام تشغيل أحدث).
إذا قمت بنشر prometheus على نظام discourse (أو في أي مكان آخر على الإنترنت العام)، فقم بتكوين الأمان أمامه. عند التثبيت بهذه الطريقة، ستكون إحدى الخيارات هي تكوين nginx على هذا النحو:
location /prometheus/ {
auth_basic "Prometheus";
auth_basic_user_file /etc/nginx/prometheus-htpasswd;
proxy_pass http://localhost:9090/;
}
Sysstat
إذا كان Prometheus كثيرًا، ففكر في استخدام sysstat بدلاً من ذلك.
dnf install sysstat(أوapt install sysstatعلى debian والمشتقات)systemctl enable --now sysstatsystemctl enable --now sysstat-collect.timersystemctl enable --now sysstat-summary.timersystemctl edit sysstat-collect.timerوقم بتغييرOnCalendar=*:00/10إلىOnCalendar=*:00/2- إذا كان /etc/default/sysstat موجودًا، قم بتغيير
falseإلىtrue
بعد ذلك، يمكن لأمر sar أن يخبرك عما إذا كنت تنفد من الموارد من وقت لآخر.
موارد أخرى
إليك مناقشة مكملة (وأكثر إحكامًا) لاستخدام Discourse داخليًا كشكل رئيسي من أشكال الاتصالات الداخلية.