تشغيل 3 حاويات لـ 3 نطاقات في تثبيت واحد مع SSL

بعد التعديل على Let’s Encrypt لعدة أيام، إليك هذا لمن يهتم بتشغيل عدة منتديات

1 الهدف

افترض أن لديك نطاقًا مثل هذا، وتريد 3 منتديات

bbs.antivte.com
cp.antivte.com
ytb.antivte.com

2 حاوية Discourse

2.1 التحضير

يجب أن يكون لديك 3 ملفات app.yml لمنتدياتك المختلفة، سمِّها كما تشاء مثل:
bbs.yml، cp.yml، ytb.yml.
محتواها يجب أن يكون كالتالي:
يرجى ملاحظة أننا نستخدم منفذ Unix Socket للاتصال بـ Nginx الخارجي وحاوية Discourse الخلفية بدلاً من الاستماع على المنفذ 80 أو 443، كما قمنا بإزالة إعدادات SSL من الحاوية الخلفية أيضًا.
يرجى الانتباه إلى أننا هنا نملك حاوية واحدة لكل منتدى، وليست حاويات منفصلة للبيانات والويب لكل منتدى.

## هذه هي قالب حاوية Docker لـ Discourse الشاملة والمستقلة
##
## بعد إجراء أي تعديلات على هذا الملف، يجب عليك إعادة البناء
## /var/discourse/launcher rebuild app
##
## كن حذرًا جدًا عند التعديل!
## ملفات YAML حساسة للغاية للأخطاء في المسافات البادئة أو المحاذاة!
## قم بزيارة http://www.yamllint.com/ للتحقق من صحة هذا الملف عند الحاجة

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## قم بإلغاء التعليق عن هذين السطرين إذا كنت ترغب في إضافة Let's Encrypt (https)
#  - "templates/web.ssl.template.yml"
#  - "templates/web.letsencrypt.ssl.template.yml"
  - "templates/web.socketed.template.yml"  # <-- تمت الإضافة
## ما هي منافذ TCP/IP التي يجب أن تعرضها هذه الحاوية؟
## إذا كنت ترغب في مشاركة منفذ مع خادم ويب آخر مثل Apache أو nginx،
## راجع https://meta.discourse.org/t/17247 للتفاصيل
**#expose:**
**#  - "8080:80"   # http**
**#  - "8443:443" # https**

params:
  db_default_text_search_config: "pg_catalog.english"

  ## قم بتعيين db_shared_buffers إلى أقصى 25% من إجمالي الذاكرة.
  ## سيتم تعيينها تلقائيًا بواسطة bootstrap بناءً على الذاكرة المكتشفة، أو يمكنك تجاوزها
  db_shared_buffers: "256MB"

  ## يمكن أن يحسن أداء الفرز، لكنه يزيد من استخدام الذاكرة لكل اتصال
  #db_work_mem: "40MB"

  ## أي إصدار Git يجب أن تستخدمه هذه الحاوية؟ (الافتراضي: tests-passed)
  #version: tests-passed

env:
  LANG: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## عدد طلبات الويب المتزامنة المدعومة؟ يعتمد على الذاكرة ونوى المعالج.
  ## سيتم تعيينها تلقائيًا بواسطة bootstrap بناءً على المعالجات المكتشفة، أو يمكنك تجاوزها
  UNICORN_WORKERS: 4

  ## TODO: اسم النطاق الذي ستستجيب له هذه النسخة من Discourse
  ## مطلوب. لن يعمل Discourse مع عنوان IP عاري.
  DISCOURSE_HOSTNAME: bbs.antivte.com

  ## قم بإلغاء التعليق إذا كنت تريد تشغيل الحاوية بنفس اسم النطاق
  ## (-h option) المحدد أعلاه (الافتراضي "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: قائمة عناوين البريد الإلكتروني المفصولة بفواصل ستُصبح مشرفين ومطورين
  ## عند التسجيل الأول مثال 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'techempower@163.com'

  ## TODO: خادم البريد SMTP المستخدم للتحقق من الحسابات الجديدة وإرسال الإشعارات
  ## عنوان SMTP واسم المستخدم وكلمة المرور مطلوبة
  ## تحذير: قد يسبب حرف '#' في كلمة مرور SMTP مشاكل!
  DISCOURSE_SMTP_ADDRESS: smtp.mailgun.org
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: postmaster@mail.antivte.com
  DISCOURSE_SMTP_PASSWORD: "67c9458eb7a6ff11b4db70f097b1b5c3-f7910792-0e7dbcc9"
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (اختياري، الافتراضي true)

  ## إذا أضفت قالب Let's Encrypt، قم بإلغاء التعليق أدناه للحصول على شهادة SSL مجانية
  LETSENCRYPT_ACCOUNT_EMAIL: techempower@163.com

  ## عنوان CDN http أو https لهذه النسخة من Discourse (مُعد للسحب)
  ## راجع https://meta.discourse.org/t/14857 للتفاصيل
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

## حاوية Docker عديمة الحالة؛ تُخزن جميع البيانات في /shared
volumes:
  - volume:
      **host: /var/discourse/shared/bbs**
      guest: /shared
  - volume:
      **host: /var/discourse/shared/bbs/log/var-log**
      guest: /var/log

## تذهب الإضافات هنا
## راجع https://meta.discourse.org/t/19157 للتفاصيل
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/procourse/procourse-installer

## أي أوامر مخصصة للتشغيل بعد البناء
run:
  - exec: echo "بداية الأوامر المخصصة"
  ## إذا كنت تريد تعيين عنوان البريد الإلكتروني 'من' للتسجيل الأول، قم بإلغاء التعليق وتغيير:
  ## بعد الحصول على أول بريد تسجيل، قم بإعادة التعليق على السطر. يجب تشغيله مرة واحدة فقط.
  #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
  - exec: echo "نهاية الأوامر المخصصة"

2.2 الإعداد

لديك سكريبت إعداد مثل هذا

#!/usr/bin/env bash
./launcher bootstrap bbs
./launcher bootstrap test
./launcher bootstrap cp
./launcher bootstrap ytb
./launcher start bbs
./launcher  start test
./launcher  start  cp
./launcher  start  ytb

وإذا كنت قد استخدمت هذا السكريبت سابقًا وقمت بتشغيل كل حاوية مرة واحدة، فعند تعديل أي محتوى في app.yml، يجب عليك إعادة بناء الحاوية لتطبيق التغييرات.

./launcher rebuild bbs

2.3 التحقق

سترى 3 حاويات تعمل بنجاح وتحقق من منفذ Unix Socket للتأكد من صحته

root@docker-s-1vcpu-2gb-sgp1-01:~# docker ps
CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS              PORTS               NAMES
9702f94ea9b4        local_discourse/bbs   "/sbin/boot"        9 hours ago         Up 9 hours                              bbs
dc13c303c38e        local_discourse/cp    "/sbin/boot"        9 hours ago         Up 9 hours                              cp
dafa592ee16f        local_discourse/ytb   "/sbin/boot"        9 hours ago         Up 9 hours                              ytb
root@docker-s-1vcpu-2gb-sgp1-01:~#  curl --unix-socket /var/discourse/shared/bbs/nginx.http.sock http:/images/json
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>血栓之家</title>

3 Nginx الخارجي

قم بتثبيت nginx/openresty على خادمك وأنشئ ملف nginx.conf في أي مجلد تفضله، المجلد يؤثر فقط على أمر تشغيل nginx، ومحتوى nginx.conf يكون كالتالي:
لدي هنا شهادة ومفتاح Cloudflare ووضعهما في مجلد المضيف كما يلي:

3.1 nginx.conf

    ssl_certificate      /var/discourse/shared/ssl/antivte.com.cert.pem;
    ssl_certificate_key  /var/discourse/shared/ssl/antivte.com.key.pem;

في المستقبل سأشرح لك كيفية استخدام شهادات ومفاتيح Let’s Encrypt التلقائية في Nginx الخارجي.

events {
  worker_connections 1024;
}

http {
  # يجب تعريف القاموس المشترك "auto_ssl" بمساحة تخزين كافية
  # لاستيعاب بيانات شهادتك. 1 ميجابايت من التخزين تكفي لشهادات
  # حوالي 100 نطاق منفصل.
  lua_shared_dict auto_ssl 1m;
  # يُستخدم القاموس المشترك "auto_ssl_settings" لتخزين مؤقت لإعدادات مختلفة
  # مثل السر المستخدم من قبل خادم الربط على المنفذ 8999. لا تقم بتغييره أو حذفه.
  lua_shared_dict auto_ssl_settings 64k;

  # يجب تعريف محل أسماء DNS لتعمل وظيفة OCSP stapling.
  #
  # هذا المثال يستخدم خادم DNS الخاص بـ Google. قد ترغب في استخدام خوادم DNS الافتراضية لنظامك،
  # والتي يمكن العثور عليها في /etc/resolv.conf. إذا كانت شبكتك غير متوافقة مع IPv6،
  # فقد ترغب في تعطيل نتائج IPv6 باستخدام العلم "ipv6=off" (مثل "resolver 8.8.8.8 ipv6=off").
  resolver 8.8.8.8;
server {
    listen 80; listen [::]:80;
    server_name bbs.antivte.com;  # <-- غيّر هذا

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;  listen [::]:443 ssl http2;
    server_name bbs.antivte.com;  # <-- غيّر هذا

    ssl_certificate      /var/discourse/shared/ssl/antivte.com.cert.pem;
    ssl_certificate_key  /var/discourse/shared/ssl/antivte.com.key.pem;
#    ssl_dhparam          /var/discourse/shared/standalone/ssl/dhparams.pem;
    ssl_session_tickets off;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;

    http2_idle_timeout 5m; # زيادة من الافتراضي 3m

    location / {
        proxy_pass http://unix:/var/discourse/shared/bbs/nginx.http.sock;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

server {
    listen 80; listen [::]:80;
    server_name cp.antivte.com;  # <-- غيّر هذا

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;  listen [::]:443 ssl http2;
    server_name cp.antivte.com;  # <-- غيّر هذا

    ssl_certificate      /var/discourse/shared/ssl/antivte.com.cert.pem;
    ssl_certificate_key  /var/discourse/shared/ssl/antivte.com.key.pem;
#    ssl_dhparam          /var/discourse/shared/standalone/ssl/dhparams.pem;
    ssl_session_tickets off;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;

    http2_idle_timeout 5m; # زيادة من الافتراضي 3m

    location / {
        proxy_pass http://unix:/var/discourse/shared/cp/nginx.http.sock;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
    }
}



server {
    listen 80; listen [::]:80;
    server_name ytb.antivte.com;  # <-- غيّر هذا

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;  listen [::]:443 ssl http2;
    server_name ytb.antivte.com;  # <-- غيّر هذا

    ssl_certificate      /var/discourse/shared/ssl/antivte.com.cert.pem;
    ssl_certificate_key  /var/discourse/shared/ssl/antivte.com.key.pem;
#    ssl_dhparam          /var/discourse/shared/standalone/ssl/dhparams.pem;
    ssl_session_tickets off;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;

    http2_idle_timeout 5m; # زيادة من الافتراضي 3m

    location / {
        proxy_pass http://unix:/var/discourse/shared/ytb/nginx.http.sock;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
    }
}



}

3.2 بدء تشغيل nginx

اذهب إلى المجلد الذي وضعت فيه nginx.conf، وقم بتشغيل الأمر التالي:

 nginx -p `pwd`/ -c nginx.conf

4. ستحصل على ما تريد بعد ذلك

وولا!

يبدو أن هذا إصدار أكثر تعقيدًا من نظام discourse متعدد المواقع المتاح بالفعل. أتساءل عن الميزة التي يوفرها تشغيل ثلاث حاويات منفصلة تتنافس جميعها على نفس الموارد بدلاً من تشغيل حاوية واحدة (أو حاويتين في حال فصل الويب والبيانات)؟

هذا كل ما يتعلق بالميزانية. ويمكنك اعتباره مرحلة تمهيدية عند تشغيل اختبار النموذج الأولي لعملائك وتسويقك.

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

كل هذا ناتج عن رغبتي في إجراء الاختبار والإنتاج على خادمي الفردي. إذا كان المنفذ 80 و443 على المضيف مشغولين، فلا أملك أي طرق أخرى لتحقيق ذلك.

شكرًا جزيلًا على المشاركة، لكنني أشعر أن هذا الموضوع يحتاج إلى المزيد من التفاصيل قبل أن يصبح دليلًا عمليًا (howto)، لذا سأقوم بإعادة تصنيفه.