١ — الخادم
ماذا يعمل وأين
| المكوّن | الخادم | لماذا هناك |
|---|---|---|
لوحة PHP (onz.one) + الموقع | خادم بلِسك | معه بقيّة مواقع العملاء؛ لا داعي لتحريكه |
| حاويات المستأجرين | خادم الحاويات | يحتاج منفذي 80 و443 كاملين لنفسه |
| Traefik | خادم الحاويات | يملك 80 و443 |
| Portainer | خادم الحاويات | على شبكة خاصة، لا على الإنترنت |
الفصل مقصود: بلِسك يملك منفذي 80 و443 على خادمه، ولا يمكن لـ Traefik مشاركتهما معه. وخادم حاويات منفصل يحلّ ذلك دون لمس أي موقع عميل قائم.
معمارية المعالج
خادم أوراكل المجاني (4 OCPU / 24 GB) من فئة Ampere A1، أي ARM64:
uname -m
→ aarch64
هذا يعني إعادة بناء الصور — صورة مبنية على x86 لا تعمل هنا إطلاقًا. لا مانع تقني بعد تنظيف الاعتماديات:
- كل اعتمادية مستخدَمة لها عجلة جاهزة لـ aarch64 (Flask، cryptography، pandas، oracledb، openpyxl، flask_babel، requests).
pyzkوحده لا عجلة له — على أي معمارية — لكنه بايثون خالص بلا شيفرة أصلية، فيُبنى على ARM كما يُبنى على x86.- حُذفت
customtkinterوpystrayوPillow: لا يستوردها أي ملف، وكانت أعلى مصادر الخطر لأنها تعتمد على حزم واجهات نظام.
ابنِ على الخادم الجديد نفسه لا عبر QEMU من خادم x86 — البناء المتقاطع بطيء إلى حدّ مؤلم، وعندك أربعة أنوية Ampere حقيقية.
docker build -t hr_system:latest .
docker image inspect --format '{{.Architecture}}' hr_system:latest
يجب أن يطبع arm64.
صورة واحدة لا صورة لكل عميل
الخادم القديم يحمل ستّ صور منفصلة (hr_system_abj, hr_system_jwa, hr_system_modani, …) بنحو 700 ميجابايت لكل واحدة — لتطبيق متطابق بايت ببايت. هوية المستأجر في متغيّر البيئة COMPANY وفي وحدة التخزين، لا في الصورة.
فابنِ صورة واحدة hr_system:latest واجعل الـ stacks تختلف في البيئة والتخزين فقط. للإبقاء على السلوك القديم بدلًا من ذلك، اضبط HR_IMAGE إلى hr_system_<company>:latest عند وضع المهمة في الطابور؛ لا شيء آخر يتغيّر.
Portainer لا يبني — لا سياق بناء لديه. الصورة يجب أن تكون موجودة على المضيف قبل إنشاء أي stack.
المنافذ — المصيدة التي توقع الجميع
صور أوراكل تأتي بـ iptables مقفولة داخل الخادم، إضافةً إلى الـ Security List في لوحة التحكّم. لا بد من فتح 80 و443 في الاثنين معًا:
- لوحة أوراكل: Networking → Virtual Cloud Networks → Security Lists → أضف Ingress Rule لـ 80 و443 من
0.0.0.0/0. - داخل الخادم: عدّل iptables واحفظه (على Ubuntu:
netfilter-persistent save).
«فتحت المنفذ ولا يعمل» تعني في تسعة من كل عشر مرات أنّ واحدًا من الاثنين فقط فُتح.
Traefik يحتاج المنفذ 80 مفتوحًا حتى وإن كان يحوّل كل شيء إلى 443، لأن تحدّي Let's Encrypt من نوع HTTP-01 يصل عليه.
حساب أوراكل: حوّله إلى Pay As You Go
موارد Always Free تبقى مجانية كما هي، لكن الحساب المجاني يخضع لقاعدة استرجاع الخوادم الخاملة: استخدام منخفض لسبعة أيام قد يعني سحب الخادم.
هذا خادم يحمل بيانات حضور وانصراف لعملاء يدفعون. التحويل إلى Pay As You Go يُخرجه من تلك القاعدة دون أن يكلّف شيئًا على نفس الموارد. ومع ذلك لا يوجد SLA على الطبقة المجانية، فالنسخ الاحتياطي خارج الخادم ليس اختياريًّا — انظر الصيانة.
الشبكة بين الخادمين
لوحة PHP على خادم بلِسك تنادي Portainer على خادم الحاويات. لا تعرّض Portainer للإنترنت: مفتاحه يشغّل ويوقف كل الحاويات ويقرأ كل وحدات التخزين.
اربط الخادمين بـ WireGuard أو Tailscale (كلاهما مجاني)، واجعل Portainer يستمع على الشبكة الخاصة وحدها. ثم PORTAINER_HOST في اللوحة يشير إلى عنوانه على تلك الشبكة.
قائمة تحقّق قبل الانتقال إلى الملف التالي
uname -m → aarch64
docker --version → موجود
docker compose version → v2 (بمسافة لا شرطة)
docker image inspect hr_system:latest → موجودة، arm64
docker network ls | grep tenants → موجودة (تُنشأ في الملف ٢)
curl -I http://[عنوان-الخادم] → يصل من خارج الخادم
الأمر الأخير هو اختبار المنافذ الحقيقي: إن لم يصل من جهازك أنت، فالمشكلة في iptables أو Security List، لا في Traefik الذي لم يُنشر بعد.