Caddy كـ Reverse Proxy لـ Docker: إعداد Compose مع HTTPS تلقائي
شغّل Caddy كـ reverse proxy لـ Docker: حزمة compose واحدة، وشبكة مشتركة، وreverse_proxy إلى أسماء الخدمات، وHTTPS تلقائي، ومتى تفيد تسميات caddy-docker-proxy.
باختصار: شغّل Caddy في حاوية خاصة به تنشر المنفذين 80 و443، واربطه هو وحاويات تطبيقاتك بشبكة Docker مشتركة واحدة، ووجّه `reverse_proxy` إلى اسم كل خدمة ومنفذها الداخلي (مثلاً `reverse_proxy app:3000`). يحلّ Caddy الاسم عبر DNS المدمج في Docker ويحصل تلقائياً على شهادة TLS لكل عنوان موقع.
يعرض هذا الدليل أولاً طريقة Caddyfile العادية، ثم البديل caddy-docker-proxy المعتمد على التسميات، ويشرح متى يناسب كل منهما على VPS واحد. إن كنت تشغّل Caddy مباشرة على المضيف بدلاً من Docker، فراجع دليل Caddy كـ reverse proxy الأساسي.
كيف تترابط الأجزاء
حاوية Caddy وحدها تنشر منافذ إلى العالم الخارجي. كل حاوية خلفية تنضم إلى شبكة bridge معرّفة من المستخدم (تسمى هنا `web`) وتكشف منفذها على تلك الشبكة فقط. خادم DNS المدمج في Docker، المتاح على الشبكات المعرّفة من المستخدم، يتيح لـ Caddy الوصول إلى `app:3000` باسم الخدمة أو الحاوية، فلا تحتاج أبداً إلى كتابة عناوين IP للحاويات تتغير مع كل إعادة إنشاء.
إبقاء الخلفيات غير منشورة أهم مما يبدو: يكتب Docker قواعد iptables الخاصة به، لذا فإن منفذاً منشوراً بـ `ports:` قد يكون قابلاً للوصول من الإنترنت حتى لو قال ufw إنه محجوب. استخدم `expose:` أو لا تربط أي منفذ إطلاقاً لكل ما يجب أن يكون خلف البروكسي.
| المكوّن | الدور | منشور على المضيف؟ |
|---|---|---|
| حاوية caddy | إنهاء TLS، التوجيه حسب اسم المضيف، إعادة التوجيه من HTTP إلى HTTPS | نعم: 80/tcp و443/tcp و443/udp |
| شبكة web | شبكة bridge مشتركة مع DNS مدمج لأسماء الخدمات | لا |
| حاويات التطبيقات | خدماتك (تطبيقات ويب، واجهات API، لوحات تحكم) | لا، يمكن الوصول إليها عبر Caddy فقط |
| وحدة التخزين caddy_data | الشهادات، المفاتيح الخاصة، حساب ACME | لا، لكن يجب أن تبقى دائمة |
خطوة بخطوة: Caddyfile عادي مع docker compose
- 01.وجّه سجل A (وسجل AAAA إن كنت تستخدم IPv6) لكل اسم مضيف إلى الـ VPS قبل تشغيل Caddy، وإلا سيفشل إصدار الشهادة.
- 02.أنشئ الشبكة المشتركة مرة واحدة: `docker network create web`.
- 03.أنشئ `/opt/proxy/compose.yaml` و`/opt/proxy/Caddyfile` كما هو موضح أدناه، ثم شغّل `docker compose up -d` في `/opt/proxy`.
- 04.اربط كل حزمة تطبيق بالشبكة الخارجية `web` وشغّلها بالأمر `docker compose up -d`.
- 05.راقب إصدار الشهادة الأولى بالأمر `docker compose logs -f caddy` في `/opt/proxy`.
- 06.بعد تعديل Caddyfile، أعد التحميل من دون توقف: `docker compose exec -w /etc/caddy caddy caddy reload`.
# /opt/proxy/compose.yaml
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data # certificates and ACME account keys
- caddy_config:/config
networks:
- web
volumes:
caddy_data:
caddy_config:
networks:
web:
external: trueاربط تطبيقاً واكتب Caddyfile
كل حزمة تطبيق تعلن الشبكة الخارجية نفسها. يصبح اسم الخدمة هو اسم المضيف الذي يتصل به Caddy. وحدة التخزين `caddy_data` هي التي يجب ألا تفقدها أبداً: حذفها يجبر Caddy على طلب كل الشهادات من جديد، ما قد يصطدم بحدود معدل ACME.
# /opt/app/compose.yaml
services:
app:
image: ghcr.io/example/app:latest
restart: unless-stopped
expose:
- "3000" # reachable on the network, NOT published on the host
networks:
- web
networks:
web:
external: true
# /opt/proxy/Caddyfile
{
email [email protected]
}
app.example.com {
reverse_proxy app:3000
}
grafana.example.com {
reverse_proxy grafana:3000
}
api.example.com {
reverse_proxy api-1:8080 api-2:8080 {
lb_policy round_robin
health_uri /healthz
health_interval 10s
}
}خلفيات Caddy: الخوادم الخلفية وموازنة الحمل وفحوص السلامة
بمصطلحات Caddy، الخلفية هي upstream لتوجيه `reverse_proxy`. يمكنك إدراج عدة خوادم خلفية في توجيه واحد، واختيار `lb_policy` مثل `round_robin` أو `least_conn` أو `ip_hash`، وإضافة فحوص سلامة نشطة بـ `health_uri` بحيث تخرج الحاويات المعطلة من التناوب. والفحوص السلبية (`fail_duration`، `max_fails`) مفيدة أيضاً عندما لا يملك التطبيق نقطة نهاية للسلامة.
يضبط Caddy افتراضياً `X-Forwarded-For` و`X-Forwarded-Proto` و`X-Forwarded-Host` على الطلبات الممرَّرة. اضبط تطبيقك ليثق بنطاق شبكة البروكسي حتى يرى عنوان IP الحقيقي للعميل ويبني روابط `https://`. تعمل WebSockets وgRPC عبر `reverse_proxy` من دون إعدادات إضافية؛ ولـ gRPC بنص غير مشفر استخدم `reverse_proxy h2c://service:50051`.
تسميات بدلاً من Caddyfile: caddy-docker-proxy
من يبحث عن «مدير بروكسي لـ Caddy» يريد عادةً ما يقدمه Nginx Proxy Manager: تضيف حاوية فتحصل على اسم مضيف وشهادة من دون تعديل ملف مركزي. لا يملك Caddy واجهة رسومية رسمية، لكن المشروع المجتمعي caddy-docker-proxy (github.com/lucaslorentz/caddy-docker-proxy) يولّد Caddyfile من تسميات الحاويات ويعيد تحميل Caddy عند بدء الحاويات أو إيقافها.
يحتاج إلى صلاحية قراءة مقبس Docker، وهو ما يعادل فعلياً صلاحيات root على المضيف. اربطه للقراءة فقط، وأبقِ صورة البروكسي محدّثة، وفضّل Caddyfile العادي إن كنت تشغّل عدداً قليلاً من الخدمات.
services:
caddy:
image: lucaslorentz/caddy-docker-proxy:ci-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
- CADDY_INGRESS_NETWORKS=web
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- caddy_data:/data
networks:
- web
whoami:
image: traefik/whoami
networks:
- web
labels:
caddy: whoami.example.com
caddy.reverse_proxy: "{{upstreams 80}}"
volumes:
caddy_data:
networks:
web:
external: trueCaddyfile عادي مقابل caddy-docker-proxy
| Caddyfile عادي | تسميات caddy-docker-proxy | |
|---|---|---|
| مكان الإعدادات | ملف واحد تديره بالإصدارات في git | تسميات موزعة على ملفات compose |
| الوصول إلى مقبس Docker | غير مطلوب | مطلوب (حساس أمنياً) |
| خدمة جديدة | عدّل Caddyfile وشغّل `caddy reload` | أضف التسميات وشغّل الحاوية |
| الصورة | الصورة الرسمية `caddy:2` | صورة مجتمعية مبنية على Caddy |
| تصحيح الأخطاء | اقرأ الملف مباشرة | افحص الإعدادات المولّدة في السجلات |
| الأنسب لـ | إعدادات VPS صغيرة ومستقرة | خدمات كثيرة قصيرة العمر أو كثيرة التغيير |
تشغيله على VPS
على VPS من NoctisNode بتقنية KVM تحصل على صلاحيات root كاملة وعنوان IPv4 مخصص، لذا فإن نشر المنفذين 80 و443 من حاوية Caddy واحدة وإخفاء كل ما عداها أمر مباشر. خطة Wisp (1 vCPU، 1 GB RAM) تكفي لـ Caddy مع حاويتين خفيفتين؛ والحزم الأثقل تناسبها Pulse أو Umbra. تفاصيل إصدار الشهادات وأنماط الفشل مشروحة في كيف يعمل HTTPS التلقائي في Caddy، وتمرير TCP الخام أو SSH في تمرير TCP وSSH عبر Caddy. أحكم SSH على المضيف عبر دليل تحصين SSH.
الأسئلة الشائعة
Qكيف أجعل Caddy يعمل كـ reverse proxy لحاوية Docker؟
Aضع Caddy والحاوية على شبكة Docker واحدة معرّفة من المستخدم واستخدم `reverse_proxy service-name:port` في Caddyfile. لا تستخدم `localhost`، لأنه داخل حاوية Caddy يشير إلى Caddy نفسه.
Qلماذا يعيد Caddy الخطأ 502 Bad Gateway لحاويتي؟
Aعادةً لأن الحاويات ليست على شبكة مشتركة، أو المنفذ خاطئ (استخدم المنفذ الداخلي للحاوية، لا منفذاً منشوراً على المضيف)، أو التطبيق يستمع على 127.0.0.1 فقط داخل حاويته. اجعل التطبيق يرتبط بـ 0.0.0.0 وافحص `docker network inspect web`.
Qهل استخدام caddy-docker-proxy آمن؟
Aيعمل جيداً، لكنه يتطلب مقبس Docker الذي يمنح تحكماً يعادل root على المضيف. اربطه للقراءة فقط، وأبقِ الصورة محدّثة، وتجنب كشف نقطة نهاية الإدارة في Caddy.
Qأين يخزن Caddy الشهادات في Docker؟
Aفي `/data` داخل الصورة الرسمية، لذا اربط وحدة تخزين مسمّاة هناك. فقدانها يعني إعادة إصدار كل شهادة وربما الاصطدام بحدود معدل ACME.
Qهل يوجد مدير بروكسي لـ Caddy بواجهة ويب؟
Aلا يملك Caddy نفسه واجهة ويب رسمية؛ يُضبط عبر Caddyfile أو JSON أو واجهة API الإدارية. وتوفر أدوات معتمدة على التسميات مثل caddy-docker-proxy سير عمل مشابهاً: أضف حاوية وانطلق.