لماذا تستضيف Cal.com ذاتيًا على خادم VPS
Cal.com تطبيق Next.js يعتمد على PostgreSQL يتولّى جدولة المواعيد وأنواع الأحداث وأوقات التوفّر والمزامنة مع التقاويم (Google وCalDAV وOffice 365). تلبّي الاستضافة الذاتية حاجة محدّدة: التحكم في بيانات توفّر عملائك وحجز مواعيدهم، التي تمرّ عادةً عبر خدمة أمريكية طرف ثالث. على خادم VPS، تلغي قيود الخطة المجانية (نوع حدث واحد، علامة تجارية مفروضة)، وتربط مفاتيح API الخاصة بك لـGoogle/الاجتماعات المرئية، وتضمّن أداة الحجز مباشرةً في موقعك تحت نطاقك. وبما أن Cal.com تطبيق Node دائم مع قاعدة بيانات وبناء إنتاجي، فإنه يتطلّب خادم VPS — إذ لا تستطيع الاستضافة المشتركة تشغيل العملية ولا استضافة PostgreSQL.
فوائد ملموسة لـCal.com المُستضاف ذاتيًا
- أنواع أحداث غير محدودة: مقابلات 15 دقيقة، وعروض توضيحية 30 دقيقة، وورش جماعية، دون حاجز مدفوع (paywall).
- بيانات الحجز لديك: دون أي تسريب لبيانات اتصال العملاء ومواعيدهم إلى خدمة SaaS طرف ثالث.
- علامة بيضاء (white-label) كاملة: يحمل رابط الحجز نطاقك، لا نطاق مطوّر.
- Webhooks وAPI: شغّل الأتمتة (CRM، الفوترة) عند كل موعد يُحجَز.
- تكاملات Google Agenda وCalDAV والاجتماعات المرئية (Jitsi وGoogle Meet) مضبوطة بمفاتيحك الخاصة.
- حجوزات الفريق والتوزيع الدوري (round-robin) لتوزيع المواعيد بين عدة متعاونين.
المتطلبات التقنية
Cal.com أكثر تطلّبًا من متوسط الاستضافة الذاتية بسبب أساسه Next.js وخطوة البناء. خصّص 2 vCPU و4 غيغابايت من RAM و20 غيغابايت من القرص لنسخة فريق مريحة؛ وقد يكفي 2 غيغابايت من RAM للاستخدام الفردي لكن البناء الأولي يكون أضيق. تحتاج إلى Docker وDocker Compose، وقاعدة بيانات PostgreSQL (مشمولة في ملف compose الرسمي)، ونطاق rdv.yourdomain.com موجَّه إلى الخادم VPS، وعدة متغيرات بيئة إلزامية: NEXTAUTH_SECRET وCALENDSO_ENCRYPTION_KEY (مفاتيح مولَّدة عشوائيًا) وNEXT_PUBLIC_WEBAPP_URL مضبوطًا على عنوان HTTPS النهائي. وللمزامنة مع التقويم والاجتماعات المرئية، جهّز معرّفات OAuth الخاصة بـGoogle.
نشر Cal.com خطوة بخطوة
استنساخ مستودع نشر Docker
على الخادم VPS: git clone https://github.com/calcom/docker.git cal-docker && cd cal-docker. يوفّر هذا المستودع ملف docker-compose.yml وملف .env.example لتكييفه.
توليد الأسرار وإعداد البيئة
انسخ .env.example إلى .env، ثم ولّد المفاتيح: openssl rand -base64 32 لـNEXTAUTH_SECRET ولـCALENDSO_ENCRYPTION_KEY. عيّن NEXT_PUBLIC_WEBAPP_URL=https://rdv.yourdomain.com ومعرّفات PostgreSQL. احفظ هذه القيم الثلاث فورًا في مدير الأسرار — لن تتمكن من تغييرها بعد أول تشغيل دون فقدان جميع تكاملاتك.
بناء المكدّس وتشغيله
ابدأ بـdocker compose up -d. يبني التشغيل الأول صورة Next.js ويطبّق عمليات ترحيل Prisma على PostgreSQL — وهي الخطوة الأطول، تابِعها بـdocker compose logs -f.
وضع الوكيل العكسي وSSL
ضع Cal.com (المنفذ الداخلي 3000) خلف وكيل عكسي بـHTTPS. باستخدام Caddy: rdv.yourdomain.com { reverse_proxy calcom:3000 }. تُحصَّل الشهادة تلقائيًا. يجب أن يطابق العنوان NEXT_PUBLIC_WEBAPP_URL تمامًا، وإلا فستفشل المصادقة.
إنشاء الحساب وإعداد أوقات التوفّر
افتح https://rdv.yourdomain.com، وأنشئ حساب المالك، وحدّد فتراتك الزمنية ونوع حدث أول. اختبر حجزًا من البداية إلى النهاية للتحقق من السلسلة.
توصيل التقويم والاجتماعات المرئية
في التكاملات، أضف معرّفات OAuth الخاصة بـGoogle للمزامنة ثنائية الاتجاه للتقويم، وفعّل Jitsi أو Google Meet لتوليد رابط اجتماع مرئي تلقائيًا عند كل حجز.
أول تسجيل دخول
افتح الرابط: يوجّهك Cal.com إلى معالج الإعداد الأول حيث تنشئ حساب المسؤول الخاص بك، على المسار /auth/setup. قم بذلك فور انتهاء التثبيت: فهذا المعالج غير محمي بأي شيء ما دام الحساب الأول غير موجود.
قد يفشل بناء Cal.com في الذاكرة على خادم VPS بسعة 2 غيغابايت أثناء ترجمة Next.js. إذا رأيت خطأ «JavaScript heap out of memory»، أضِف مؤقتًا ملف swap بسعة 2 غيغابايت (fallocate -l 2G /swapfile && mkswap /swapfile && swapon /swapfile) طوال مدة البناء، ثم أزِله. وبالنسبة للتحديثات، انسخ دائمًا قاعدة بيانات PostgreSQL احتياطيًا قبل docker compose pull لأن عمليات ترحيل Prisma غير قابلة للتراجع.
ثوابت التشغيل الأول الحرجة
ثلاثة متغيرات بيئة مُقيَّدة نهائيًا عند أول تشغيل لـCal.com. تغييرها لاحقًا يُفسد صامتًا جميع التكاملات المخزّنة: يُعيد التطبيق تشغيله بصورة طبيعية ولا يُظهر أي خطأ، لكن Google Calendar وZoom وجميع اتصالات OAuth تتوقف عن العمل — إذ خُزِّنت رموزها المشفَّرة بالمفتاح الأصلي غير المتوافق الآن. هذا السلوك موثَّق في calcom/docker issue #333 وcalcom/cal.diy issue #13290: فقد مستخدمون جميع تكاملاتهم إثر تحديث أعاد إنشاء ملف .env.
CALENDSO_ENCRYPTION_KEY — يشفّر رموز OAuth المخزّنة في قاعدة البيانات. أي تعديل يُلغي صامتًا جميع التكاملات القائمة.
NEXTAUTH_URL — يثبّت ملفات تعريف الارتباط للجلسة. أي تغيير يُعطل المصادقة لجميع المستخدمين النشطين.
NEXT_PUBLIC_WEBAPP_URL — مضمَّن في بناء Next.js وقت الترجمة. تغيير هذه القيمة يستلزم إعادة بناء كاملة وإعادة توصيل جميع التكاملات.
أفضل الممارسات: انسخ هذه القيم الثلاث فورًا إلى مدير الأسرار (Bitwarden، HashiCorp Vault، Ansible Vault). وإن كنت تدير خادمك بنهج البنية التحتية كرمز (infrastructure-as-code)، خزّنها في قبو مشفَّر — لا تجعل ملف .env موضعها الوحيد.
تحديث Cal.com بأمان
نسخ قاعدة بيانات PostgreSQL احتياطيًا
قبل أي تحديث: docker exec cal-docker-db-1 pg_dump -U calcom calcom | gzip > /opt/backup/calcom-$(date +%Y%m%d).sql.gz. عمليات ترحيل Prisma غير قابلة للتراجع — هذه النسخة الاحتياطية هي شبكة الأمان الوحيدة لديك.
التحقق من أن CALENDSO_ENCRYPTION_KEY لم تتغيّر
قارن القيمة الموجودة في ملف .env بتلك المحفوظة في مدير الأسرار. إن اختلفتا، توقّف هنا: استعِد القيمة الأصلية قبل المتابعة. مفتاح مختلف سيُدمّر صامتًا جميع تكاملات OAuth عند إعادة التشغيل.
تنزيل الصورة الجديدة وإعادة التشغيل
حدِّث بـdocker compose pull && docker compose up -d. تابِع بدء التشغيل بـdocker compose logs -f calcom — انتظر رسالة تأكيد جاهزية الخادم قبل الاختبار.
التحقق من التكاملات بعد التحديث
افتح الإعدادات → التكاملات وتأكد من أن كل اتصال قائم (Google Calendar، Zoom، إلخ) لا يزال نشطًا. حالة «غير متصل» تعني تغيُّر المفتاح بين تشغيلَين — استعِد النسخة الاحتياطية وملف .env الأصلي.
تشخيص الأخطاء الشائعة
ضياع التكاملات بعد تحديث — السبب في الغالب CALENDSO_ENCRYPTION_KEY مختلفة بين تشغيلَين. تحقق من أن ملف .env لم يُستبدَل بـ.env.example أثناء التنزيل. قارن القيمة الحالية بتلك المحفوظة في مدير الأسرار. إن اختلفتا: استعِد قاعدة بيانات PostgreSQL، أعِد المفتاح الأصلي إلى .env، وأعِد التشغيل بـdocker compose up -d.
خطأ «JavaScript heap out of memory» أثناء البناء — المُجمِّع Next.js يعاني من نقص RAM. الحل: fallocate -l 2G /swapfile && mkswap /swapfile && swapon /swapfile، ثم أعِد تشغيل docker compose build. على خادم VPS بسعة 2 غيغابايت، الـswap ضروري غالبًا للبناء الأول والتحديثات الكبرى. أزِل ملف الـswap بعد اكتمال البناء.
حلقة إعادة توجيه أو خطأ «Unable to find valid origin» — NEXT_PUBLIC_WEBAPP_URL لا يطابق الرابط الفعلي. تحقق من أن هذا المتغير يساوي بالضبط https://rdv.yourdomain.com (بدون شرطة مائلة في النهاية، بالنطاق الصحيح وبروتوكول HTTPS)، وأن الوكيل العكسي لا يُعدِّل رأس Host، ثم أعِد التشغيل بـdocker compose up -d --build لإجبار إعادة البناء بالرابط الصحيح.
أتمِت نسخ قاعدة بيانات PostgreSQL احتياطيًا بمهمة cron يومية. مثال على الأمر المجدوَل: docker exec cal-docker-db-1 pg_dump -U calcom calcom | gzip > /opt/backup/calcom-$(date +%Y%m%d-%H%M).sql.gz. احتفظ بسبعة أيام على الأقل من النسخ الاحتياطية الدورية وأرسِلها إلى تخزين كائنات خارجي (S3-متوافق، Backblaze B2): في حال فقدان الخادم VPS، قاعدة بيانات PostgreSQL هي الجزء الوحيد غير القابل للاستعادة تلقائيًا في نسختك من Cal.com.