لماذا تختار Caddy كـ reverse proxy على VPS؟
تُفوّض معظم الـ reverse proxies إدارة TLS إلى أداة خارجية — Certbot أو acme.sh أو سكريبت cron مكتوب يدويًا. يدمج Caddy هذه الآلية من الطرف إلى الطرف: حالما يُعلَن عن اسم نطاق في Caddyfile، يتواصل مع Let's Encrypt، ويحصل على الشهادة، ويجدّدها قبل انتهاء صلاحيتها، دون تدخل يدوي. النتيجة: إعداد يُقرأ في بضعة أسطر ويُنشر بشكل متطابق على جميع VPS دون حالة خارجية للمزامنة.
مزايا Caddy في الإنتاج
- HTTPS تلقائي: ACME HTTP-01 من Let's Encrypt ينشط فور تعريف اسم النطاق — لا cron ولا إضافات
- صياغة موجزة: كتلة من خمسة أسطر تحل محل vhost Nginx المكوّن من أربعين سطرًا مع ملف Certbot
- إعادة تحميل بلا انقطاع:
caddy reloadيطبّقCaddyfileالجديد دون قطع الاتصالات الجارية - HTTP/2 و HTTP/3 (QUIC) بشكل افتراضي: مفعّلان دون أي إعداد إضافي في جميع إصدارات 2.x
- JSON API: الإعداد قابل للتعديل مباشرةً عبر واجهة REST API، مفيد للبيئات الديناميكية أو المعتمدة على الحاويات
- صورة Docker رسمية خفيفة:
caddy:2-alpineتزن أقل من 20 ميغابايت وتغطي معظم حالات الإنتاج
المتطلبات المسبقة
قبل البدء، تحقق من استيفاء VPS للشروط التالية.
الحد الأدنى من الموارد: 512 ميغابايت RAM و1 vCPU تكفيان لـ Caddy وحده. خصّص 1 غيغابايت RAM و2 vCPU إذا كنت تستضيف عدة تطبيقات خلفه.
المنفذان 80 و 443 متاحان: Caddy يستخدمهما لـ ACME HTTP-01 (المنفذ 80) ولحركة HTTPS (المنفذ 443). تحقق من عدم احتلالهما بعملية أخرى:
ss -tlnp | grep -E ':80|:443'اسم نطاق يشير إلى VPS: يتحقق Let's Encrypt من ملكية النطاق باستعلام المنفذ 80 على عنوان IP الخاص بك. يجب أن يكون سجل DNS A نشطًا ومُنتشرًا قبل تشغيل Caddy.
نظام التشغيل: Debian 11/12 أو Ubuntu 22.04/24.04. الأوامر في هذا الدليل مُختبَرة على هذه التوزيعات.
Docker (اختياري): إذا نشرت Caddy في حاوية، فأنت بحاجة إلى Docker Engine 24+ وDocker Compose v2.
نشر Caddy كـ reverse proxy
الطريقة 1 — التثبيت عبر مستودع APT الرسمي
يوفر Caddy مستودع APT موقَّعًا. أضفه ثم ثبّت الحزمة:
apt install -y debian-keyring debian-archive-keyring apt-transport-https curl curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \ | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \ | tee /etc/apt/sources.list.d/caddy-stable.list apt update && apt install caddyتحقق من الإصدار المثبّت: يجب أن يعرض
caddy versionقيمة v2.9.x أو أحدث.الطريقة 2 — النشر عبر Docker Compose
إذا كانت تطبيقاتك تعمل بالفعل على Docker، فإضافة خدمة Caddy إلى نفس
compose.yml هي الطريقة الأبسط. أنشئ ملف compose.yml في جذر مشروعك:services: caddy: image: caddy:2-alpine restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" volumes: - ./Caddyfile:/etc/caddy/Caddyfile - caddy_data:/data - caddy_config:/config networks: - proxy volumes: caddy_data: caddy_config: networks: proxy: external: trueأنشئ الشبكة المشتركة مرة واحدة:
docker network create proxy. تنضم خدماتك الأخرى إلى هذه الشبكة لتصبح متاحة لـ Caddy.إنشاء Caddyfile الأساسي
Caddyfile هو ملف الإعداد المركزي. للتثبيت عبر APT يوجد في /etc/caddy/Caddyfile. لـ Docker ضعه بجانب compose.yml.مثال بسيط لعرض تطبيق على المنفذ 3000:
myapp.com { reverse_proxy localhost:3000 }هذا كل شيء. يكتشف Caddy أن
myapp.com اسم نطاق، يتواصل مع Let's Encrypt عبر ACME HTTP-01، يحصل على شهادة، ويعيد توجيه كل حركة HTTP إلى HTTPS تلقائيًا. تُخزَّن الشهادات في ~/.local/share/caddy/ (APT) أو في المجلد المنطقي caddy_data (Docker).إعداد تطبيقات متعددة (multi-vhost)
استضافة عدة تطبيقات على نفس VPS لا تتطلب سوى كتل إضافية في نفس الملف:
app1.yourdomain.com { reverse_proxy localhost:3000 } app2.yourdomain.com { reverse_proxy localhost:4000 } blog.yourdomain.com { reverse_proxy localhost:8080 }تحصل كل كتلة على شهادة Let's Encrypt خاصة بها. يُدير Caddy التجديدات بشكل مستقل لكل نطاق، بالتوازي، دون انقطاع في الخدمة.
تطبيق Caddyfile دون انقطاع
لـ APT، أعد تحميل الإعداد دون قطع الاتصالات:
systemctl reload caddy # أو إذا عدّلت الملف خارج /etc/caddy/: caddy reload --config /path/to/Caddyfileلـ Docker:
docker compose exec caddy caddy reload --config /etc/caddy/Caddyfileتحقق من صحة الصياغة قبل إعادة التحميل:
caddy validate --config /etc/caddy/Caddyfile.إضافة رؤوس الأمان وتحديد معدل الطلبات
يدعم Caddy رؤوس الأمان بشكل أصيل عبر التوجيه
header. إليك كتلة مُصلَّبة لتطبيق إنتاجي:myapp.com { reverse_proxy localhost:3000 header { Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" X-Content-Type-Options "nosniff" X-Frame-Options "SAMEORIGIN" Referrer-Policy "strict-origin-when-cross-origin" -Server } log { output file /var/log/caddy/myapp.log { roll_size 10mb roll_keep 5 } } }لتحديد معدل الطلبات، يُثبَّت الوحدة
caddy-ratelimit عبر xcaddy build وتُستخدم بالتوجيه rate_limit. الصورة الرسمية على Docker لا تتضمنها — ابنِ صورتك الخاصة أو استخدم جدار حماية تطبيقي من طبقة أعلى إن كانت الحاجة ماسّة.تفعيل خدمة systemd والتحقق منها (APT)
بعد التثبيت عبر APT، تُفعَّل الخدمة تلقائيًا. تحقق من حالتها والسجلات:
systemctl status caddy journalctl -u caddy -fللتأكد من التشغيل عند إعادة الإقلاع:
systemctl enable caddy(منجز بالفعل من الحزمة). اختبر نجاح إصدار شهادة Let's Encrypt:curl -sv https://myapp.com 2>&1 | grep -E 'subject|issuer|expire'
كيف يعمل HTTPS التلقائي في Caddy
ينفّذ Caddy بروتوكول ACME (Automated Certificate Management Environment) بشكل أصيل. حالما تحتوي كتلة Caddyfile على اسم نطاق مؤهّل، يُشغّل Caddy تلقائيًا تحدّي ACME HTTP-01: يضع Let's Encrypt رمزًا للتحقق في http://yourdomain.com/.well-known/acme-challenge/، يستجيب Caddy لهذا الطلب مثبتًا سيطرته على الخادم، فيُصدر Let's Encrypt شهادة صالحة لمدة 90 يومًا.
يجدد Caddy الشهادة مسبقًا (ابتداءً من 30 يومًا قبل انتهائها) ويعيد تحميل الإعداد دون انقطاع. تُخزَّن الشهادات وبيانات ACME محليًا — في ~/.local/share/caddy/ لتثبيت APT، وفي المجلد المنطقي caddy_data لـ Docker. لا تحذف هذا المجلد: يخزّن Caddy فيه أيضًا حالة ACME، وكثرة الطلبات إلى Let's Encrypt تُشغّل حدود الاستخدام وقد تحجب إصدار شهادات جديدة لساعات.
لـ شهادات wildcard (*.yourdomain.com)، لا يعمل ACME HTTP-01: يستلزم الأمر تحدّي DNS-01 الذي يحتاج إلى وصول API مزود DNS الخاص بك. يدعم Caddy عدة مزودين بشكل أصيل عبر وحدات (caddy-dns/cloudflare، caddy-dns/ovh…) تُجمَّع مع xcaddy.
Caddy مقابل Nginx: متى تختار أيًا منهما
مرّر الجدول أفقيًا
| المعيار | Caddy | Nginx |
|---|---|---|
| إعداد TLS | تلقائي، لا إعداد يدوي | يدوي (Certbot أو acme.sh مطلوب) |
| منحنى التعلم | منخفض — صياغة مقروءة وتوجيهات محدودة | معتدل — صياغة مطوّلة وسياقات متعددة |
| الأداء الخام (طلبات/ثانية) | ممتاز لمعظم الأحمال | أعلى قليلًا تحت الأحمال الثقيلة جدًا |
| الوحدات والنظام البيئي | متنامٍ، xcaddy لتجميع الوحدات | ضخم جدًا، وحدات طرف ثالث ناضجة وكثيرة |
| إعادة التحميل دون انقطاع | أصيل (`caddy reload`) | أصيل (`nginx -s reload`)، مشابه |
| حالة الاستخدام المثالية | VPS شخصي، مشاريع الفرق، microservices على Docker | منصات كبيرة، CDN أمامي، حالات متقدمة (GeoIP، Lua…) |
| دعم HTTP/3 (QUIC) | مُفعَّل افتراضيًا منذ Caddy 2.6 | تجريبي، يستلزم تجميعًا مع quiche أو ngx_http_v3 |
حل المشكلات: الأخطاء الشائعة
المنفذ 80 مشغول. يحتاج Caddy إلى المنفذ 80 لـ ACME HTTP-01. إذا كان Apache أو Nginx يعمل بالفعل، أوقفه قبل تشغيل Caddy: systemctl stop apache2 أو systemctl stop nginx. تحقق بعدها: ss -tlnp | grep :80.
فشل ACME / لم تُصدر الشهادة. Let's Encrypt لا يستطيع الوصول إلى خادمك. تحقق: (1) سجل DNS A يشير إلى IP الـ VPS — يجب أن يُرجع dig +short your-domain.com عنوان IP الصحيح؛ (2) المنفذ 80 متاح من الخارج — جدران الحماية في VPS (iptables، ufw) تحجب هذا المنفذ أحيانًا. راجع سجلات Caddy بـ journalctl -u caddy لقراءة رسالة خطأ ACME الدقيقة.
permission denied على المنفذين 80/443. المنافذ أقل من 1024 محجوزة في Linux. لتثبيت APT، تُعدّ الحزمة الإمكانية CAP_NET_BIND_SERVICE تلقائيًا. إذا جمّعت Caddy يدويًا، طبّقها: setcap cap_net_bind_service=+ep $(which caddy).
DNS غير محلول / no such host. يحلّ Caddy أسماء الـ backends المعلَنة في reverse_proxy. إذا كان تطبيقك يُسمّى app في Docker Compose، تأكد من أن Caddy والتطبيق يشتركان في نفس شبكة Docker. تحقق بـ: docker compose exec caddy nslookup app.
حذف المجلد المنطقي caddy_data عن طريق الخطأ. يجب على Caddy إعادة التفاوض على جميع الشهادات من الصفر. يفرض Let's Encrypt حدًا قدره 5 شهادات لكل نطاق خلال 7 أيام. إذا بلغت هذا الحد، استخدم بيئة التدريج ACME (acme_ca https://acme-staging-v02.api.letsencrypt.org/directory في Caddyfile) للاختبار، ثم عُد إلى الإنتاج بعد انتهاء النافزة الزمنية.
لاستضافة تطبيقات متعددة على نفس VPS
أنشئ شبكة Docker مشتركة (docker network create proxy) وصل كل خدمة بهذه الشبكة. يُشير Caddyfile حينئذٍ إلى الخدمات باسم الحاوية بدلًا من localhost:PORT — الإعداد لا يتغير عند إضافة تطبيقات أو حذفها. مثال: reverse_proxy my-service:3000 بدلًا من reverse_proxy localhost:3000.
التوثيق الرسمي
المرجع الكامل للتوجيهات والوحدات وJSON API متاح على <a href="https://caddyserver.com/docs/">caddyserver.com/docs</a>. منتدى المجتمع (<a href="https://caddy.community">caddy.community</a>) هو أفضل مورد للأسئلة المتقدمة — يرد عليه المطوّرون الأساسيون مباشرةً.