◀ العودة إلى المدونة
Docker

Traefik وDocker: وكيل عكسي وHTTPS تلقائي

نشر في 25 Aug 2026· 5 min قراءة
#Docker#Traefik#HTTPS#Reverse proxy

لماذا Traefik؟

بمجرد أن يستضيف خادمٌ عدة تطبيقات داخل حاويات، تحتاج إلى وكيل عكسي (reverse proxy) أمامها: نقطة دخول واحدة على المنفذين 80 و443، توجّه كل نطاق إلى الحاوية المناسبة وتتولى HTTPS. يؤدي Nginx هذه المهمة جيداً، لكن كل تطبيق جديد يتطلب كتابة مضيف افتراضي وإعادة تحميل الإعدادات وتوليد شهادة.

أما Traefik فيعكس المنطق: يقرأ واجهة Docker البرمجية، ويكتشف الحاويات، ويضبطها انطلاقاً من الوسوم (labels) الخاصة بها. يكفي تشغيل حاوية لنشرها عبر HTTPS بشهادة Let's Encrypt يُحصل عليها وتُجدَّد تلقائياً.

الشبكة المشتركة

يجب أن يتشارك Traefik والتطبيقات التي يعرضها شبكة Docker واحدة. أنشئها مرة واحدة:

docker network create proxy

Traefik نفسه

ملف /opt/traefik/compose.yaml:

services:
  traefik:
    image: traefik:v3.5
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --providers.docker.network=proxy
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.le.acme.email=contact@example.com
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
      - --api.dashboard=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)
      - traefik.http.routers.dashboard.entrypoints=websecure
      - traefik.http.routers.dashboard.tls.certresolver=le
      - traefik.http.routers.dashboard.service=api@internal
      - traefik.http.routers.dashboard.middlewares=dashboard-auth
      - traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$Hq3vN2kS$$exempleDeHashAremplacer

networks:
  proxy:
    external: true

بعض النقاط المهمة:

  • exposedbydefault=false: لا تُنشر أي حاوية دون الوسم traefik.enable=true. بدون هذا الخيار قد تُكشف قاعدة بيانات شُغّلت عن طريق الخطأ.
  • إعادة التوجيه من HTTP إلى HTTPS مصرَّح بها مرة واحدة على مستوى نقطة الدخول web.
  • مقبس Docker مركَّب للقراءة فقط، لكنه يمنح مع ذلك صلاحيات واسعة على المضيف: لتأمين إضافي، ضع وكيلاً للمقبس (مثل tecnativa/docker-socket-proxy) بين Traefik وDocker.
  • في ملف Compose يجب مضاعفة علامات $ في التجزئة ($$). ولّد التجزئة بالأمر htpasswd -nb admin password (من الحزمة apache2-utils).
cd /opt/traefik && docker compose up -d
docker compose logs -f traefik

نشر تطبيق

من جهة التطبيق، يكفي الانضمام إلى الشبكة proxy ووصف التوجيه بالوسوم. مثال بحاوية Symfony (PHP-FPM وNginx داخل الصورة، على المنفذ 8080):

services:
  app:
    image: ghcr.io/moi/app:latest
    restart: unless-stopped
    env_file: .env.prod
    networks:
      - proxy
      - internal
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=Host(`app.example.com`) || Host(`www.app.example.com`)
      - traefik.http.routers.app.entrypoints=websecure
      - traefik.http.routers.app.tls.certresolver=le
      - traefik.http.routers.app.middlewares=secure-headers,rate-limit
      - traefik.http.services.app.loadbalancer.server.port=8080
      - traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000
      - traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true
      - traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true
      - traefik.http.middlewares.secure-headers.headers.frameDeny=true
      - traefik.http.middlewares.rate-limit.ratelimit.average=50
      - traefik.http.middlewares.rate-limit.ratelimit.burst=100

  database:
    image: mysql:8.4
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: app
      MYSQL_USER: app
      MYSQL_PASSWORD_FILE: /run/secrets/db_password
      MYSQL_RANDOM_ROOT_PASSWORD: "yes"
    secrets:
      - db_password
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - internal

networks:
  proxy:
    external: true
  internal:

volumes:
  db-data:

secrets:
  db_password:
    file: ./secrets/db_password.txt

قاعدة البيانات مرتبطة بالشبكة internal فقط: لا يستطيع Traefik الوصول إليها، ولا تنشر أي منفذ. عند أول تنفيذ للأمر docker compose up -d يكتشف Traefik الحاوية، ويحصل على الشهادة للنطاقين، ويبدأ توجيه الحركة خلال ثوانٍ ودون أي إعادة تشغيل.

قراءة وسم توجيه

تتبع كل الوسوم القواعد نفسها: traefik.http.<type>.<name>.<option>.

  • routers: أي طلب (قاعدة Host أو PathPrefix…) يصل إلى أي نقطة دخول، مع أي إعدادات TLS وأي طبقات وسيطة
  • services: إلى أي منفذ في الحاوية تُرسَل الحركة (ضروري إذا كانت الصورة تعرض عدة منافذ)
  • middlewares: التحويلات المطبَّقة في الطريق (الترويسات، المصادقة، تحديد معدل الطلبات، إعادة التوجيه، الضغط)

يمكن إعادة استخدام طبقة وسيطة معرَّفة على حاوية ما في الحاويات الأخرى: عرّف ترويسات الأمان مرة واحدة على حاوية Traefik، ثم أشر إليها باللاحقة @docker، مثل secure-headers@docker.

شهادات wildcard عبر تحدي DNS

يتطلب تحدي HTTP أن يكون الخادم متاحاً على المنفذ 80. وللحصول على شهادة *.example.com، أو لخادم غير مكشوف، استخدم تحدي DNS. مع Cloudflare مثلاً:

      - --certificatesresolvers.le.acme.dnschallenge=true
      - --certificatesresolvers.le.acme.dnschallenge.provider=cloudflare
    environment:
      CF_DNS_API_TOKEN_FILE: /run/secrets/cf_token

لا يحتاج رمز Cloudflare إلا إلى صلاحية Zone ← DNS ← Edit على النطاق المعني.

استكشاف الأخطاء

  • الخطأ 404 "page not found": الموجِّه غير موجود. تحقق من traefik.enable=true ومن قاعدة Host (علامات backtick إلزامية).
  • الخطأ 502 Bad Gateway: يجد Traefik الحاوية لكنه لا يصل إليها. هل الحاوية على الشبكة proxy؟ وهل منفذ loadbalancer صحيح؟
  • شهادة موقَّعة ذاتياً "TRAEFIK DEFAULT CERT": فشل تحدي ACME. راجع سجلات Traefik: هل يشير DNS إلى الخادم، وهل المنفذ 80 مفتوح؟
  • حدود Let's Encrypt: أثناء التجارب استخدم خادم الاختبار (--certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory) حتى لا تستنفد الحصص.

بعد الإعداد، تصبح إضافة تطبيق جديد مسألة ثلاثة أو أربعة وسوم. وهذا ما يجعل Traefik مريحاً جداً لخادم شخصي أو بنية تحتية صغيرة تستضيف خدمات كثيرة.