٢ — التوجيه والشهادات
لماذا Traefik ولماذا لا يوجد ملف nginx هنا
كل مستأجر يحتاج ثلاثة أشياء: اسم نطاق، وشهادة، وتوجيهًا إلى حاويته. جرّبنا إنجازها عبر بلِسك فسقطت ثلاثة افتراضات عند التنفيذ:
| الافتراض | ما ردّه الخادم فعلًا | ||
|---|---|---|---|
| قواعد Docker Proxy لها API | Hook ApiCli is not implemented in docker | ||
-seo-redirect true يفرض HTTPS | يأخذ `non-www\ | www\ | none` — شأنه www لا التشفير |
plesk bin site يقبل توجيهات nginx | لا خيار له؛ و--update-web-server-settings أمر غير معروف |
Traefik يلغي فئة المشكلة كلها: يقرأ إعداده من labels على الحاوية نفسها. لا نداء API يُخطئ، ولا أمر تختلف أعلامه بين الإصدارات، ولا ملف يُكتب على مضيف بعيد. الحاوية تقوم — والتوجيه يوجد معها.
وما يختفي بالتبعية:
- تخصيص منافذ المضيف. الحاويات لا تنشر منافذ إطلاقًا. لا تصادم، ولا جدول منافذ يُصان، ولا مسار غير مشفّر يلتفّ حول الشهادة.
- إنشاء نطاق فرعي لكل عميل. سجل DNS واحد بـ wildcard يكفي للجميع.
- إصدار الشهادات يدويًّا. Traefik يصدر ويجدّد من الـ labels.
ما تحتاجه مرة واحدة
أ) سجل DNS واحد
*.onz.one A [عنوان-خادم-الحاويات]
هذا كل عمل الـ DNS — لا سجل لكل مستأجر، الآن ولا لاحقًا.
ب) شبكة Docker
docker network create tenants
الاسم tenants مستعمل حرفيًّا في قالب Traefik وفي قالب المستأجر؛ تغييره يعني تغييره في الاثنين.
ج) stack الـ Traefik
القالب في config/templates/traefik-stack.yml داخل مشروع اللوحة. ارفعه في Portainer مرة واحدة ولا تلمسه بعدها، واضبط LETSENCRYPT_EMAIL.
شغّل أول تجربة على شهادة اختبارية. في القالب سطر معلَّق:
# - --certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
أزل التعليق عنه في أول نشر. سلطة الإصدار الحقيقية تحدّ عدد الشهادات لكل نطاق مسجَّل أسبوعيًّا — وبضع محاولات فاشلة على *.onz.one تقفل الإصدار على المستأجرين الحقيقيين لا على تجربتك. أعد التعليق بعد نجاح دورة كاملة.
كيف يعرف Traefik إلى أين يوجّه
من labels على حاويات المستأجر. هذا ما يصير إليه القالب لمستأجر عنوانه jwa.onz.one:
traefik.http.routers.jwahr-web.rule = Host(`jwa.onz.one`)
traefik.http.services.jwahr-web...port = 5000
traefik.http.routers.jwahr-adms.rule = Host(`jwa.onz.one`) && PathPrefix(`/iclock`)
traefik.http.services.jwahr-adms...port= 8081
فالعنوان نفسه يخدم وجهتين: التطبيق على / وخادم البصمة على /iclock. Traefik يرتّب الموجّهات حسب دقّة القاعدة، فقاعدة PathPrefix تغلب القاعدة المجرّدة تلقائيًّا دون أولوية صريحة.
hr_sync بلا labels عمدًا: لا منفذ له، ويجب ألّا يكون قابلًا للتوجيه.
نقطتان أمنيّتان في القالب
١. مقبس Docker للقراءة فقط.
- /var/run/docker.sock:/var/run/docker.sock:ro
Traefik يحتاج أن يرى الحاويات لا أن يتحكّم بها. المقبس القابل للكتابة يساوي صلاحية الجذر على المضيف لأي شيء يصل إلى تلك الحاوية.
٢. لا نشر تلقائي.
- --providers.docker.exposedByDefault=false
بدونها تُنشر كل حاوية على المضيف لحظة إقلاعها. على خادم متعدّد المستأجرين هذا يعني كشف أشياء بالخطأ. الحاوية تُعلن رغبتها صراحةً بـ traefik.enable=true.
بقاء بلِسك ممكن
لا شيء يجبرك على إزالة بلِسك. مواقع عملائك القائمة (al-shuhada.com, brilliant-kw.com, crm.onz.one, …) تبقى عليه كما هي. الذي ينتقل هو *.onz.one — نطاقات المستأجرين وحدها — إلى خادم الحاويات.
كما يبقى مسار بلِسك القديم قابلًا للتشغيل في اللوحة عبر PROVISION_MODE=plesk، للاختبار دون لمس ما يعمل اليوم.
إن لم يعمل
| العرض | الفحص أولًا |
|---|---|
| المتصفّح لا يصل أصلًا | المنفذان 80/443 في iptables و Security List |
| «شهادة غير موثوقة» | هل ما زال سطر الشهادة الاختبارية مفعَّلًا؟ هذا متوقَّع حينها |
| 404 من Traefik | الحاوية ليست على شبكة tenants، أو traefik.enable غائب |
| الشهادة لا تصدر | المنفذ 80 محجوب — تحدّي HTTP-01 يصل عليه لا على 443 |
| كل النطاقات تعطي نفس الموقع | سجل الـ wildcard غير منتشر بعد، أو يشير لخادم آخر |
خطوة verify في التجهيز التلقائي تلتقط أغلب هذه الحالات وتفشل برسالة تسمّي السبب — انظر التجهيز التلقائي.