أحاول إعداد Discourse خلف وكيل عكسي خاص بـ Apache، لكنني لا أستطيع جعله يعمل بشكل صحيح مع HTTPS.
واجهتُ العديد من المشاكل للوصول إلى هذه المرحلة. حاليًا، لدي Discourse على خادم، وخادم Apache أمامه يعمل كوكيل عكسي. واجهتُ في البداية العديد من المشاكل لتشغيله خلف وكيل عكسي، حيث كان Discourse يريد دائمًا إعادة التوجيه إلى اسم المضيف المحدد في ملف app.yaml.
على الرغم من ذلك، تمكنتُ من جعله يعمل الآن، لكنني أحصل على تحذيرات حول محتوى مختلط (Mixed-content) في متصفحي.
لدي إعادة توجيه في Apache من HTTP إلى HTTPS، وهذا يعمل بشكل جيد. لكن Discourse لا يزال يقدم بعض المحتوى عبر HTTP، ولا أستطيع معرفة كيفية إجباره على تغيير ذلك إلى HTTPS.
على سبيل المثال، يتم تقديم أيقونة الموقع (favicon) عبر HTTP، ولا أستطيع معرفة كيفية تغيير ذلك.
هل يمكنني جعل Discourse يغير جميع الروابط إلى HTTPS دون أن يتعامل Discourse نفسه مع حركة مرور HTTPS؟
لقد حاولت تعيين:
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
في Apache، لكن يبدو أن هذا لا يساعد.
تفعيل خيار “فرض HTTPS” في Discourse لا يساعد أيضًا، بل سيؤدي إلى تعطيل الموقع لأنه سيتجاهل ببساطة كل ما يأتي عبر HTTP.
نجحت في تشغيل Apache2 “بدون أي مشكلة” في بيئة اختبارية باستخدام Apache2 كوكيل عكسي (reverse proxy) لملف socket في حاوية يونكس:
الفرق الوحيد الذي وجدته (ملاحظة: اختبار لمدة بضع ساعات فقط، وليس شاملًا) هو:
لن يعمل Apache2 مع رابط رمزي (symlink) إلى ملف socket في المجلد المشترك داخل الحاوية؛
كان Apache2 أبطأ قليلًا في اختبار تقريبي، لكن الفرق لم يكن كبيرًا.
شخصيًا، لستُ من محبي الحروب الدينية حول التقنيات؛ لذا أختلف مع القول بأن “Apache2 سيسبب لك الكثير من المشاكل.” لم أواجه أي مشاكل سلبية مع Apache2 خلال اختباراتي.
إليك الإعداد الأساسي الذي استخدمته مع Apache2 (HTTP، وعمل بشكل ممتاز مع LETSENCRYPT، بالمناسبة):
ملاحظة: المرة الوحيدة التي واجهنا فيها مشاكل في تقديم المحتوى عبر HTTP حتى مع تعيين force_https كانت عندما كانت الملفات مفقودة في مجلد /uploads. ولكن هذا (طبعًا) لا علاقة له بـ Apache2 مقابل nginx كوكيل عكسي.
شكرًا لك على الردود، لكنني لا أستخدم Apache على نفس الخادم الذي يعمل عليه Discourse. ربما لم أكن واضحًا بما يكفي في ذلك.
لدي خادم Apache موجود مسبقًا يستضيف مجموعة من المواقع الإلكترونية، وأحتاج إلى إعداده كوكيل عكسي (reverse proxy) لـ Discourse الذي يستضيف على خادم مختلف، لذا لا يمكنني استخدام الـ sockets.
لم أجرب هذه الطريقة، لكن يمكنك التفكير في تركيب نظام الملفات البعيد ومحاولة الوصول إلى مقبس Unix بهذه الطريقة، خاصة إذا كانت الخوادم في نفس مركز البيانات ولم تكن هناك مشكلة في أداء الشبكة عبر شبكة واسعة النطاق.
بدون نشر أي تفاصيل حول البنية التحتية أو نظام التشغيل أو إعدادات الشبكة، إلخ، من الصعب الرد، وربما يكون هذا خارج نطاق النقاش هنا في Meta Discourse.
آخر مرة حاولت فيها استخدام هذا الإعداد مع Apache2، كنت أواجه فشلًا في الاتصال بحافلة رسائل Discourse. كان ذلك منذ أكثر من عام تقريبًا. يبدو أن الموقع يعمل بشكل صحيح، لكن في وحدة تحكم المطور F12، كان واضحًا أن اتصالات wss انتهت مهلة انتظارها بعد بضع محاولات أولية.
يمكنك أن ترى بوضوح في مثال التكوين الذي نشرته أننا لم نستخدم wss
wss ≠ عكس وكيل apache2 (إنه مجرد طريقة واحدة للقيام بذلك، ونحن لا نستخدم wss)
في الواقع، نستخدم فقط تكوينات عكس الوكيل لـ nginx و apache2 باستخدام مآخذ النطاق يونكس لأن:
أنا كسول وأحب التكوينات البسيطة وسهلة التصحيح.
مآخذ النطاق يونكس بسيطة وسهلة التصحيح.
في nginx, يمكننا التبديل بين عكس الوكيل وأي حاوية باستخدام رابط رمزي.
apache2 (عكس الوكيل إلى حاوية) لا يعمل مع رابط رمزي، لذا يتطلب إعادة تشغيل خادم الويب.
ومع ذلك، سأل @Grunskin عن شيء لم نقم بتكوينه بعد؛ وهو إجراء عكس الوكيل على مضيف واحد وتشغيل الحاوية على مضيف آخر.
عندما أجد وقتًا، سأختبر هذا لكل من nginx و apache2 في نفس مركز البيانات وأرى ما إذا كان بإمكاني جعل هذا يعمل عن طريق تثبيت نظام الملفات البعيد واستخدام مقبس يونكس.
إلى أن يحدث ذلك…
ملاحظة: برأيي، هذه القضية ليست ذات صلة بـ nginx أو apache2 اللذين يعملان فقط كعكس للوكلاء (ولكن كما ذُكر، لم نختبر بعد إعداد الوصول عن بُعد، لذا لا يمكنني التعليق بشكل أكبر).
ديسكورد هو تطبيق وليس موقع ويب. بمجرد تسليم حمولة جافا سكريبت الأولية إلى متصفحك، تعتمد العديد من الميزات على اتصال سريع بخادم ديسكورد. التوجيه عبر نظام آخر سيؤدي إلى إدخال تأخير وإضعاف تجربة المستخدم بشكل كبير.
هناك أسباب عديدة لاستخدام وكيل عكسي.
على سبيل المثال، إذا كان لدي عنوان IP عام واحد فقط وأحتاج إلى جعل عدة خوادم ويب متاحة للعامة على المنفذ 80/443، ولا يمكنني تشغيل Discourse في هذا المثال على خادم الويب المحدد.
استخدمه لإزالة تحميل SSL (SSL Offloading) حتى لا يضطر الخادم النهائي إلى التعامل مع التشفير.
يتم تقليل سطح الهجوم على الخادم النهائي من خلال وضعه خلف وكيل عكسي.
هناك العديد من الأسباب المشروعة لذلك، ولا أستطيع أن أفهم لماذا لا يكون هذا ممكنًا.
بعد مرور بعض الوقت، تذكرت أنني أملك خادمًا آخر يعمل فيه Discourse خلف خادم Apache الخاص بي، وقد عمل بشكل جيد لمدة عامين على الأقل. قمت بتكوين Discourse الجديد بنفس الطريقة، لكنني لا أستطيع إيقاف تقديم بعض العناصر عبر HTTP. الاختلاف الوحيد بين خوادم Discourse هو أن الخادم القديم يعمل بإصدار 2.4 والجديد بإصدار 2.5، لذا لا أعرف ما إذا كان هناك أي اختلافات هناك؟
كما قلت في المنشور الأول، فإن force_https يكسر الموقع، مما يجعل تسجيل الدخول وقبول الدعوات وغيرها مستحيلًا. يبدو أن هناك بعض ملفات الجافا سكريبت التي لا تعمل لأنها تُقدّم على الأرجح عبر HTTP.
ألا يكون من المنطقي أكثر أن تقوم force_https بإعادة كتابة جميع روابط HTTP إلى HTTPS بدلاً من تجاهلها؟ على الأقل اجعل ذلك خيارًا.
ما هي الطريقة الموصى بها لإعداد Discourse بشكل عام؟ هل هو إعداد خادم في منطقة منزوعة السلاح (DMZ) مع عنوان IP خارجي خاص به؟
هناك العديد من الأسباب لتشغيل عكسي للوكيل. أنا متأكد جدًا من أن بنية Discourse.org تعمل خلف HAproxy.
أستخدم Traefik و Caddyserver، وقد نجحت في تشغيل nginx و HAproxy وحتى Apache في الماضي (لتثبيت ووردبريس في مجلد فرعي).
هذه هي مشكلتك. تحتاج إلى تمكين force_https وتحديد سبب كسره. إيقاف تشغيله ليس خيارًا. لقد طلبت دعمًا مجانيًا، ولم يجد أولئك الذين ردوا حلاً لـ Apache، لذا سيكون عليك أن تكون قائد فرقة Apache.
نستخدم حاليًا إعداد “حاويتين مع وكيل عكسي” في جميع مواقعنا، سواء كانت بيئات إنتاج أو اختبار أو تجريبية، باستثناء الخادم الذي نستخدمه لتجهيز عملية الترحيل الرئيسية.
والسبب في ذلك هو أن تشغيل جميع نصوص الترحيل المختلفة يكون أسهل عندما تكون قاعدة بيانات PostgreSQL و MySQL وكود تطبيق Discourse جميعها في حاوية واحدة. هذا الإعداد غير مخصص للإنتاج ويُسهّل عملية استكشاف الأخطاء وإصلاحها. ولكن عندما نكون راضين عن النتائج، ننقل النسخة الاحتياطية إلى بيئة الإنتاج ونستعيدها.
إحدى المشكلات في هذا الإعداد هي أن إعداد الحاويتين الفائق حتى مع الوكيل العكسي لا يمكنه تعويض وقت التوقف أثناء استعادة قاعدة البيانات، نظرًا لوجود قاعدة بيانات واحدة فقط.
ربما في المستقبل، سنحاول إعدادًا يحتوي على حاويتين لقاعدة البيانات، مما يسمح لنا باستعادة إحداهما والتبديل بينهما… على مستوى البيانات أيضًا.
أو الأفضل من ذلك، سنقوم بالاستعادة إلى قاعدة بيانات باسم مختلف ونقوم بالتبديل في الوقت الفعلي، لكننا لا نعرف كيفية القيام بذلك بعد. إذا كنت تعرف أين في الكود يمكننا تغيير اسم قاعدة بيانات الإنتاج من discourse إلى discourse2 دون إعادة بناء التطبيق بالكامل، فسيكون ذلك رائعًا ربما يعرف المستشار الفائق الإبداع والابتكار @pfaffman الحل؟
تحديث: إنه موجود هنا في templates/postgres.template.yml
(أرى بعض الأمور المثيرة للاهتمام المتعلقة بـ mv لمجلد postgres هنا بالتأكيد :). )
كل من الإعداد المستقل وإعداد الحاويات المتعددة له مزايا وعيوب؛ ولكن للإنتاج، نحن ملتزمون تمامًا بإعداد الحاويتين مع الوكيل العكسي. أما بالنسبة لاختبار الترحيل والبيئة التجريبية، فإن الإعداد المستقل هو الأفضل بالنسبة لنا.
بخصوص Apache2، أتمنى لو كان لدي الوقت لإعداده واختباره مع الوكيل العكسي على خادم واحد، والحاويات على خادم آخر. آسف على ذلك…
أيضًا، أحتاج إلى إيجاد طريقة للحفاظ على استمرار الموقع أثناء استخدام إعداد الحاويتين وإجراء استعادة لقاعدة البيانات. أرى (الآن) أن قالب templates/postgres.template.yml موجه نحو إعداد حاوية مستقلة واحدة.
يجب عليك تعيين اسم المضيف هذا إلى اسم المضيف الذي سيتم الوصول إليه عبر Discourse. إذا لم يكن اسم النطاق في app.yml هو الاسم الذي يكتبه الناس في متصفحهم للوصول إلى موقعك، فلن يعمل.
أليس لديك قوالب ssl أو letsencrypt في ملف app.yml الخاص بك؟
نعم، تحتاج إلى تفعيل خيار force_https.
كما يجب عليك تخطي بعض العقبات لجعل الاستجواب الطويل يعمل. لا أتذكر ما هي تلك العقبات.
فإن هذا ليس “المشكلة”. كما ذكر @pfaffman أعلاه (مرتين على الأقل، وهو أحد خبراء الهجرة البارزين في منصة Meta):
يجب عليك “إبقاء” force_https = true ثم تحديد “المشكلة الحقيقية”.
لو كنتُ مكانك، بناءً على ما قرأته:
أولاً، سأقوم بإعداد وكيل عكسي (reverse proxy) على نفس الخادم الذي يحتوي على حاويات discourse لتبسيط المشكلة، وذلك فقط لأغراض الاختبار واستكشاف الأخطاء وإصلاحها. تأكد من أن هذه الحالة البسيطة من الاختبار تعمل بشكل مثالي. ثم، عندما تعمل على نفس المضيف، قم بإيقاف ذلك الوكيل العكسي التجريبي، وانتقل إلى إعداد الخادم المزدوج المطلوب.
هذه مشكلة مثيرة للاهتمام. يمكنك حلها إذا أبقيت على force_https = true واتبعت طريقة منهجية خطوة بخطوة لاستكشاف الأخطاء وإصلاحها. إن أنواع هذه المشاكل مجرد ألغاز تقنية تنتظر الحل.
أنت قادر على ذلك.
ملاحظة جانبية: إذا شعرت بالإحباط أو الملل من هذا اللغز، يمكنك دائمًا دفع بعض المال لـ @pfaffman أو أي شخص آخر خبير في منصة Meta لدفعهم لمساعدتك على تجاوز هذه العقبة والانتقال إلى آفاق أكثر إشراقًا.
ملاحظة: لم نواجه أي مشاكل في جعل Apache2 يعمل كوكيل عكسي باستخدام منفذ نطاق يونكس (unix domain socket) على نفس الخادم. أعتذر بصدق عن عدم امتلاكي الوقت الكافي شخصيًا لإعداد تكوين الخادم المزدوج وجعل طريقة الوكيل العكسي لـ Apache2 تعمل على خادمين مختلفين. نحن مشغولون بمهام الهجرة النهائية المتعلقة بتنظيف إساءة استخدام “bbcode” بشكل غير منطقي وتحديثها إلى مشاكل في التنسيق باستخدام Markdown، وهذا يستغرق وقتًا أطول مما توقعنا في الأصل.
قررت اتباع نهج تثبيت Discourse على localhost في المنفذ 8443 باستخدام SSL، وقفل المنفذ 8443 باستخدام UFW (جدار الحماية)، ثم عمل وكيل (proxy) للمنفذ 443 إلى 8443 عبر Apache2. أحاول الآن.
لقد قمت بترحيل discourse الخاص بنا إلى إعداد جديد والآن لدي مشاكل مع http 403 على جلسة POST أثناء تسجيل الدخول. أظن أنها مشكلة CSRF، ولكن في الوقت الحالي ليس لدي فكرة عن مكان بدء التصحيح، وملفات production.log و production_error.log في /var/log/discourse-var-log/ كلها بحجم 0 بايت…
لست على دراية بأمور csrf وأيضًا ليس nginx (خادم الويب الخارجي هو Apache 2.4)، ولكني متأكد تمامًا من أن CSRF هي مشكلتي هنا حيث أن discourse يعمل بشكل جيد بدون تسجيل دخول وفقط طلبات POST التي تُستخدم لتسجيل الدخول تفشل هنا. عنوان IP الداخلي لخادم haproxy المركزي الخاص بي هو 10.10.10.21، لذلك وضعت
set_real_ip_from 10.10.10.21/24;
في ملف yml الخاص بـ discourse.conf في حاوية web_only. لقد جربت أيضًا باستخدام الإعداد الافتراضي 127.0.0.1/24؛ ولكن كلاهما يؤدي إلى نفس خطأ 403 عند تسجيل الدخول.