لماذا تنشر Keycloak على خادمك VPS
حيث تسعى بعض مزوّدات الهوية (IdP) إلى البساطة، يسعى Keycloak إلى الشمولية: عزل متعدد المستأجرين عبر realms، واتحاد أدلة LDAP/Active Directory، والوساطة (brokering) نحو مزوّدين خارجيين (Google وGitHub أو OIDC آخر)، وتخصيص كامل لمظهر صفحات تسجيل الدخول، وتفويض دقيق (fine-grained authorization). وبالنسبة إلى وكالة تدير عدة عملاء أو نظام معلومات ذي متطلبات امتثال، فإن هذا المستوى من التحكّم حاسم. تجنّبك الاستضافة الذاتية على خادم VPS التكاليف لكل مستخدم في عروض IdP المُدارة، وتُبقي قاعدة الهويات بأكملها ضمن نطاق سلطتك القضائية، وهي نقطة بالغة الأهمية للبيانات الحساسة التي لا ترغب في تسليمها إلى طرف ثالث.
مزايا Keycloak المستضاف ذاتيًا
- realms متعددة لعزل عدة عملاء أو بيئات عزلًا كاملًا على نفس النسخة (instance) الواحدة.
- دعم أصلي وكامل لـ OpenID Connect وOAuth2 وSAML 2.0.
- اتحاد LDAP / Active Directory لإعادة استخدام دليل قائم دون عملية ترحيل.
- الوساطة في الهوية (Identity brokering): تسجيل الدخول عبر Google أو GitHub أو أي IdP خارجي ببضع نقرات.
- صفحات تسجيل دخول قابلة للتخصيص بالكامل (السمات، اللغات، الهوية البصرية لكل realm).
- سياسات مصادقة دقيقة: مصادقة متعددة العوامل (MFA) مشروطة، ومدة الجلسة، وقيود حسب الدور.
المتطلبات المسبقة لهذا النشر
يعمل Keycloak على الآلة الافتراضية لجافا JVM (على Quarkus منذ الإصدار v17+) ويظل أكثر استهلاكًا للموارد من مزوّد هوية خفيف. خصّص خادم VPS بـ 2 vCPU و4 غيغابايت من RAM كحدّ أدنى، ويُفضَّل 6 غيغابايت إذا كنت تتوقّع حِملًا أو عدة realms نشطة. يُوصى بشدّة باستخدام قاعدة PostgreSQL خارجية في بيئة الإنتاج (لا تستخدم أبدًا قاعدة H2 المدمجة خارج نطاق الاختبارات). ويكتمل ما يلزم بوجود Docker وDocker Compose ونطاق مخصّص (sso.mydomain.com) ووكيل عكسي (reverse proxy) يتولّى SSL، لأن Keycloak يحتاج إلى إعلامه بأنه يُقدَّم خلف وكيل HTTPS.
نشر Keycloak مع PostgreSQL
تعريف Keycloak وPostgreSQL في Compose
في ملف
docker-compose.yml، عرّف خدمةpostgres(الصورةpostgres:16) وخدمةkeycloak(الصورةquay.io/keycloak/keycloak). اربط Keycloak بقاعدة البيانات عبرKC_DB=postgresوKC_DB_URLوKC_DB_USERNAMEوKC_DB_PASSWORD.تهيئة وضع الإنتاج والوكيل
شغّل باستخدام الأمر
start(وليسstart-dev). عيّنKC_HOSTNAME=sso.mydomain.comوKC_PROXY_HEADERS=xforwardedحتى يُنشئ Keycloak عناوين URL صحيحة خلف الوكيل العكسي. وحدّد المسؤول الأولي عبرKC_BOOTSTRAP_ADMIN_USERNAME/KC_BOOTSTRAP_ADMIN_PASSWORD.البدء وإتمام عملية البناء (build)
نفّذ
docker compose up -d. عند التشغيل الأول، يُجري Keycloak عملية بناء Quarkus مُحسّنة ثم يُرحّل مخطّط PostgreSQL. تابِعdocker compose logs -f keycloakحتى تظهر الرسالة التي تشير إلى أن الخادم في وضع الاستماع.إعداد الوكيل العكسي مع SSL
وجّه
sso.mydomain.comإلى المنفذ8080في حاوية Keycloak عبر Caddy أو Traefik أو Nginx، مع شهادة Let's Encrypt. واحرص على تمرير ترويساتX-Forwarded-*وإلا فستتعطّل عمليات إعادة التوجيه عند تسجيل الدخول.إنشاء realm وعميل (client)
سجّل الدخول إلى وحدة تحكّم المسؤول، وأنشئ realm مخصّصًا (لا تستخدم أبدًا realm
masterلتطبيقاتك)، ثم عميل OIDC. اضبط قيمةValid redirect URIsلتطبيقك، واحصل علىClient IDوالسرّ من تبويب Credentials.ربط تطبيق واختبار التدفّق (flow)
هيّئ تطبيقك باستخدام عنوان الاكتشاف
https://sso.mydomain.com/realms/mon-realm/.well-known/openid-configuration. أنشئ مستخدمًا تجريبيًا في الـ realm، وابدأ عملية تسجيل دخول، وتحقّق من إصدار الرمز (token) في قسم Sessions بوحدة التحكّم.
صورة مُحسَّنة مسبقًا: فصل البناء عن التشغيل
افتراضيًا يتحقق الأمر start عند التشغيل مما إذا كانت مرحلة بناء Quarkus لازمة وينفّذها عند الحاجة: وهذا ما يُطيل التشغيل الأول، وهو ما يكتب داخل شجرة ملفات التثبيت. توصي وثائق الجهة المطوّرة بعكس ذلك في الحاويات: تنفيذ kc.sh build أثناء بناء الصورة، ثم التشغيل بالأمر start --optimized. يُعلم المعامل --optimized برنامج Keycloak بأنه يعمل ضمن صورة مُحسَّنة مسبقًا وأن بإمكانه تخطي ذلك التحقق. أما خيارات البناء، مثل نوع قاعدة البيانات (db) أو تفعيل فحوص الصحة (health-enabled)، فتُثبَّت داخل الصورة: وإذا أُعيدت عند التشغيل بالقيمة نفسها تُتجاهل، وإذا أُعيدت بقيمة مختلفة تسبّبت في خطأ واستلزمت بناءً جديدًا. أما الأسرار، ومنها كلمة مرور القاعدة، فتنتمي إلى خيارات الإعداد وتبقى تُمرَّر وقت التشغيل.
بناء صورة مُحسَّنة مسبقًا وتشغيلها
كتابة Dockerfile على مرحلتين
تنطلق المرحلة الأولى من
quay.io/keycloak/keycloakوتُسمّىbuilder، وتضبطENV KC_DB=postgresوENV KC_HEALTH_ENABLED=true، ثم تنفّذ RUN /opt/keycloak/bin/kc.sh build. ثبّت رقم إصدار محددًا بدلlatestليبقى كل بناء جديد قابلًا للتكرار.نسخ الناتج إلى الصورة النهائية
تنطلق المرحلة الثانية من الصورة نفسها وتنفّذ
COPY --from=builder /opt/keycloak/ /opt/keycloak/. ضع القوالب والمزوّدات المخصّصة قبل البناء كي يأخذها التحسين في الحسبان. وإذا أضفت ملفات بالأمرCOPYفأضف--chown=keycloak:keycloakليتمكن Keycloak من الكتابة في المجلدات المعنية.التشغيل بالخيار المُحسَّن
في Compose استبدل الأمر بـ
start --optimized. وخلف وكيل عكسي ينهي TLS أضفKC_HTTP_ENABLED=true. تبقى المتغيراتKC_HOSTNAMEوKC_PROXY_HEADERSوبيانات الوصول إلى القاعدة إعدادًا وقت التشغيل.ربط فحوص الصحة
مع ضبط
KC_HEALTH_ENABLED=trueوقت البناء، تُقدَّم النقاط/health/startedو/health/liveو/health/readyعلى منفذ الإدارة9000المنفصل عن المنفذ8080الخاص بالتطبيق. لا تنشر هذا المنفذ على الإنترنت: استخدمه فقط فيhealthcheckالخاص بـ Compose أو في أدوات المراقبة لديك.
Keycloak أم Authentik: أيّهما تختار؟
مرّر الجدول أفقيًا
| المعيار | Keycloak | Authentik |
|---|---|---|
| حالة الاستخدام المستهدفة | تسجيل دخول موحّد للمؤسسات، متعدد المستأجرين، الامتثال | الاستضافة الذاتية، المختبر المنزلي (homelab)، الوكالات |
| البروتوكولات | OIDC, OAuth2, SAML, LDAP | OIDC, OAuth2, SAML, LDAP, forward auth |
| Forward auth (الوكيل) | غير أصلي (عبر إضافات) | أصلي ومحوري في الأداة |
| استهلاك الموارد | مرتفع (JVM، 4 غيغابايت+ RAM) | معتدل (2-4 غيغابايت RAM) |
| realms / المستأجرون المتعددون | ممتاز (realms معزولة) | المستأجرون مدعومون، لكن بشكل أقل تطوّرًا |
| تخصيص التدفّقات (flows) | السمات وواجهة SPI بجافا | تدفّقات مرئية على شكل خطوات |
| منحنى التعلّم | حادّ، وشامل جدًا | أيسر منالًا |
| اتحاد الأدلة | ناضج (LDAP/AD) | جيّد (LDAP) |
النسخ الاحتياطي والترحيل دون فقدان أي realm
تقع حالة Keycloak في مكانين: قاعدة PostgreSQL، وملفات الإعداد لديك (القوالب والمزوّدات وملفات الاستيراد). النسخة المرجعية هي pg_dump مجدول تُنسخ نتيجته خارج الـ VPS؛ جرّب الاستعادة على نسخة مؤقتة، لأن نسخة لم تُستعَد قط تبقى مجرد فرضية. ويكمّل تصدير الـ realm هذا الترتيب دون أن يحل محله: kc.sh export --dir <المجلد>، أو --realm my-realm لـ realm واحد، مع الخيار --users لاختيار استراتيجية تصدير المستخدمين. تنص الوثائق على أن الخادم يجب ألا يكون قيد التشغيل أثناء التصدير، وأن الاتساق لا يُضمن إلا مع إيقاف جميع العقد، وأن الأحداث والجلسات المحفوظة والرموز الملغاة لا تُصدَّر. وعند تجاوز 50 000 مستخدم صدّر إلى مجلد لا إلى ملف واحد. أما عند الاستيراد فيقرأ start --import-realm ملفات .json الموجودة في المجلد /opt/keycloak/data/import ويتجاهل أي realm موجود مسبقًا.
قائمة تحقق للتشغيل
- إصدار مثبَّت — ثبّت رقم إصدار الصورة، واقرأ ملاحظات الإصدار قبل تغيير الفرع الرئيسي، وأعد بناء الصورة المُحسَّنة عند كل ترقية.
- قاعدة منسوخة احتياطيًا —
pg_dumpمجدول، ونسخة خارج الـ VPS، واستعادة مُجرَّبة على نسخة مؤقتة. - ذاكرة محدودة — حدّد دائمًا سقفًا لذاكرة الحاوية: تحسب JVM حجم الكومة (heap) منه، بنسبة 70 % كحد أقصى و50 % كحجم ابتدائي افتراضيًا.
- فحوص مراقَبة — تابع
/health/readyعلى المنفذ9000غير المنشور من أدوات المراقبة لديك. - ترويسات الوكيل تحت السيطرة — يجب أن يستبدل الوكيل العكسي ترويسات
X-Forwarded-*الواردة من العميل لا أن يُضاف إليها، وألا يُتجاوز أبدًا. - الأحداث مفعَّلة — سجّل عمليات الدخول وإجراءات الإدارة في كل realm لمعرفة من دخل ومن عدّل ماذا.
استكشاف الأخطاء: فشل التشغيل مع نظام ملفات للقراءة فقط
غالبًا ما يمرّ تحصين الحاوية عبر read_only: true في Compose أو readOnlyRootFilesystem: true في Kubernetes. ومع Keycloak فالموضوع مفتوح منذ أبريل 2022 في المسألة رقم 11286 من المستودع keycloak/keycloak ("Keycloak does not work with Docker read_only: true")، وكانت لا تزال نشطة في نهاية أكتوبر 2026. المثبَت من جهة المشروع: أعاد أحد المساهمين في Keycloak إنتاج الفشل على الإصدار 19.0.2 في سبتمبر 2022، وصُنّفت المسألة تحسينًا بوسم "help wanted"، وأُضيفت إلى لوحة مشروع في المستودع في سبتمبر 2026. وغير المثبَت: لا تصف الوثائق الرسمية حتى اليوم أي وضع للقراءة فقط (صفحة الحاويات لا تذكره)، ولم يعتمد أي مشرف حلًّا بديلًا. الحلول أدناه صادرة عن مشاركين في النقاش؛ نجحت عندهم وفي إصداراتهم، دون ضمان بعد أي ترقية. وفي 26 أكتوبر 2026 عرض أحد المساهمين كتابة الوثائق الناقصة بعد التحقق بنفسه من هذه الحلول.
رسائل الخطأ التي ينبغي التعرف عليها
sed: couldn't open temporary file /opt/jboss/keycloak/bin/seduHoQM0: Read-only file system— رسالة التقرير الأول على صورة WildFly القديمة (الإصدار 16.1.1 في المسألة): الأمرsed -iفي سكربت التشغيل لا يستطيع إنشاء ملفه المؤقت. أما في توزيعة Quarkus فتختلف الأعراض، انظر الأسطر التالية.-
KC-SERVICES0075: Failed to get theme request: java.lang.RuntimeException: Temporary directory /opt/keycloak/bin/../data/tmp does not exist and it was not possible to create it.— أُبلغ عنها أثناء الترقية إلى 20.0.1: يبدأ الخادم ثم يفشل عند أول صفحة تخدم قالبًا. وأفاد أحد المشاركين بأن تركيب وحدة تخزين قابلة للكتابة على/opt/keycloak/data/tmpيعالج هذه الحالة. - تشغيل بطيء أو فشل كتابة في
/opt/keycloak/lib/quarkus— قارن أحد المشاركين الحاوية قبل التشغيل وبعده بالأمرdocker diff: تتغير ثلاثة مجلدات هي/tmpو/opt/keycloak/dataو/opt/keycloak/lib/quarkus. يحتوي الأخير على ناتج البناء الذي يعيدstartتوليده ما لم تكن الصورة مُحسَّنة مسبقًا. - مجلد
dataللقراءة فقط بعدCOPY— يذكر أحد المشاركين أن نسيان--chown=keycloak:keycloakعند نسخ ملف realm يترك/opt/keycloak/dataمملوكًا لـ root، فلا يستطيع Keycloak الكتابة فيه. - نسخ
/opt/keycloakإلى وحدة تخزين عند التشغيل — حل بحاوية تهيئة أُبلغ عنه في Kubernetes: يعمل، لكن عدة مشاركين يخشون اضطرارهم إلى إعادة اختباره عند كل ترقية.
الحل البديل المُبلَّغ عنه في Docker Compose
الانطلاق من الصورة المُحسَّنة مسبقًا
أعد استخدام الصورة المبنية أعلاه. يُنفَّذ
kc.sh buildوقت البناء: فلا يُعاد كتابة/opt/keycloak/lib/quarkusعند التشغيل، ويتم التشغيل بالأمرstart --optimized.تعريف نظام الملفات للقراءة فقط
أضف
read_only: trueإلى خدمةkeycloakفي ملف Compose. من دون أي تغيير آخر تفشل الحاوية: وهذا هو السلوك الذي تصفه المسألة.توفير المجلدات القابلة للكتابة
ركّب
tmpfsعلى/tmpووحدة تخزين مؤقتة على/opt/keycloak/data. في التقرير القائم على صورة مُحسَّنة مسبقًا كفى هذان المجلدان؛ وعلى صورة غير مُحسَّنة أضاف مشاركون آخرون/opt/keycloak/lib/quarkus.إعادة ما كان داخل data
تبدأ وحدة التخزين المؤقتة فارغة: فما كانت الصورة تضعه في هذا المجلد، ومنه
data/import، لم يعد ظاهرًا فيه. وإذا كنت تستورد realms بالخيار--import-realmفركّب مجلدها بشكل منفصل للقراءة فقط.التحقق بفتح صفحة تسجيل الدخول
نفّذ
docker compose up -dثمdocker compose logs -f keycloak، ثم افتح صفحة تسجيل الدخول: أول طلب لقالب هو ما أفشل بعض التركيبات. واختم بـdocker diffلسرد ما كتبته الحاوية فعلًا.
القراءة فقط: تحصين لا توثّقه الجهة المطوّرة
احتفظ بهذا الوضع للبيئات التي تفرضه فيها سياسة، كتدقيق أمني أو قاعدة في العنقود، وتقبّل كلفته: إعداد غير موثَّق يجب إعادة اختباره عند كل ترقية، وهو ما يخشاه عدة مشاركين في المسألة. وعلى VPS واحد تعطي إجراءات أخرى مكسبًا أوضح بصيانة أقل: إسقاط قدرات Linux (cap_drop: [ALL])، والخيار no-new-privileges، وعدم نشر منافذ الإدارة، ووضع قاعدة PostgreSQL على شبكة Docker داخلية.
في بيئة الإنتاج، لا تُشغّل Keycloak أبدًا بقاعدة H2 المدمجة ولا تُتِح realm master للعموم: أنشئ realm مخصّصًا لكل تطبيق أو لكل عميل، واحتفظ بـ master للإدارة فقط. ولتحصين النسخة، عطّل التسجيل الحرّ، وفعّل brute force detection في Realm Settings > Security Defenses، وهيّئ كل شيء عبر ملفات استيراد realm (--import-realm) كي تُخضع تهيئتك لإدارة الإصدارات بدلًا من النقر في واجهة المستخدم.