SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor

اجرای 5 برنامه با Traefik v3 در یک Docker Compose

با Traefik v3 در Docker Compose پنج سرویس را روی یک IP میزبانی کنید. تنظیم Host rule، دریافت خودکار SSL و رفع خطای رایج acme.json که مانع صدور گواهی می‌شود را بیاموزید.

یک IP، پنج برنامه، یک پورت 443

سرور مجازی (VPS) شما دارای یک آدرس IPv4 عمومی و تنها یک پورت TCP 443 است. شما می‌خواهید Gitea، یک نسخه staging از برنامه خود، یک داشبورد داخلی، یک صفحه وضعیت و یک دریافت‌کننده webhook را روی آن اجرا کنید؛ پنج نام دامنه، یک سرور. یک reverse proxy فرآیندی است که پورت‌های 80 و 443 را در اختیار می‌گیرد، هدر Host را در هر درخواست می‌خواند و آن را به container صحیح هدایت می‌کند. Traefik این کار را انجام می‌دهد و برای هر نام دامنه، بدون اینکه نیاز باشد شخصاً certbot را اجرا کنید، گواهی دریافت و تمدید می‌کند. Nginx و Caddy نیز می‌توانند همین پنج نام دامنه را به‌خوبی مدیریت کنند؛ بنابراین اگر هنوز در انتخاب مردد هستید، ارزش دارد که پیش از اتصال همه چیز به یکی از آن‌ها، سه پروکسی را از نظر مدیریت گواهی و هزینه پیکربندی برای هر برنامه مقایسه کنید.

آنچه Traefik را از یک بلاک server {} در nginx متمایز می‌کند، منبع پیکربندی آن است. در nginx شما یک فایل را ویرایش و reload می‌کنید و چرخه حیات گواهی یک وظیفه جداگانه باقی می‌ماند؛ همان گردش کاری که هنگام صدور گواهی‌های Let's Encrypt با certbot روی nginx دنبال می‌کنید، جایی که زمان‌سنج تمدید کاملاً خارج از وب‌سرور قرار دارد. ارائه‌دهنده Docker در Traefik، جریان رویدادهای Docker را زیر نظر می‌گیرد و برچسب‌ها (labels) را از روی containerهای شما می‌خواند: containerای را با یک برچسب قانون Host() شروع کنید تا در کمتر از یک ثانیه قابل مسیریابی شود؛ آن را متوقف کنید تا مسیر ناپدید شود. این همان دام است. پیکربندی که در برچسب‌ها قرار دارد در پنج مکان مختلف پخش شده است و یک برچسب اشتباه، بی‌صدا می‌ماند؛ container به‌سادگی مسیریابی نمی‌شود و Traefik هیچ پیامی اعلام نمی‌کند.

چهار مفهوم اصلی

  • Entrypoints همان سوکت‌های در حال گوش دادن (listening sockets) هستند. شما دو مورد را تعریف خواهید کرد: web روی :80 و websecure روی :443.
  • Routers درخواست‌ها (Host(...)) را تطبیق داده و آن‌ها را به یک سرویس متصل می‌کنند. گواهی‌ها از طریق tls.certresolver برای هر router درخواست می‌شوند.
  • Services همان بک‌اند، کانتینر و پورتی هستند که داخل شبکه Docker روی آن گوش می‌دهد.
  • Middlewares بین router و service قرار می‌گیرند: احراز هویت پایه (basic auth)، لیست‌های مجاز IP، بازنویسی هدرها و تغییر مسیرها (redirects).

این چهار مفهوم، نام‌هایی هستند که Traefik برای کارهایی انتخاب کرده که در غیر این صورت باید به‌صورت دستی انجام می‌دادید: router همان server_name است، service همان هدف proxy_pass است و middlewares همان دستورالعمل‌های هدر و احراز هویتی هستند که هنگام ساخت خط‌به‌خط بلوک سرور reverse proxy در nginx خودتان تنظیم می‌کنید.

پیکربندی ایستا (entrypoints، providers، ACME) از طریق خط فرمان Traefik یا در traefik.yml ارسال می‌شود و تغییر آن مستلزم راه‌اندازی مجدد Traefik است. پیکربندی پویا (routers، services، middlewares) از طریق برچسب‌های کانتینر (container labels) دریافت شده و به‌صورت زنده (hot-reloaded) بارگذاری می‌شود. اشتباه گرفتن این دو، دلیل اصلی این است که می‌گویید "فلگ من هیچ کاری انجام نمی‌دهد".

فایل compose

یک شبکه اشتراکی Docker به نام proxy ستون فقرات این ساختار است. Traefik تنها زمانی به یک کانتینر دسترسی دارد که هر دو در آن شبکه حضور داشته باشند.

name: edge

networks:
  proxy:
    name: proxy

services:
  traefik:
    image: traefik:v3.7
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedByDefault=false
      - --providers.docker.network=proxy
      - --entryPoints.web.address=:80
      - --entryPoints.websecure.address=:443
      - --entryPoints.web.http.redirections.entryPoint.to=websecure
      - --entryPoints.web.http.redirections.entryPoint.scheme=https
      - --certificatesresolvers.le.acme.email=you@example.com
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true
      # while you iterate, point at staging so a mistake costs nothing:
      # - --certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
      - --api.dashboard=true
      - --log.level=INFO
      - --accesslog=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$$REPLACE$$THIS

  gitea:
    image: gitea/gitea:1  # major-only pin keeps this demo copy-pasteable; pin an exact release in production
    restart: unless-stopped
    volumes:
      - ./gitea:/data
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.gitea.rule=Host(`git.example.com`)
      - traefik.http.routers.gitea.entrypoints=websecure
      - traefik.http.routers.gitea.tls.certresolver=le
      - traefik.http.services.gitea.loadbalancer.server.port=3000

ابتدا docker compose up -d و سپس docker compose logs -f traefik را اجرا کنید. هر برنامه اضافی، یک کپی از بلوک gitea با نام router اختصاصی، Host() مخصوص به خود و پورت داخلی مربوطه است. یک نصب Nextcloud در Docker همراه با TLS و پشتیبان‌گیری نیز به همین روش جای‌گذاری می‌شود؛ کافی است پورت‌های published آن را حذف کنید، آن را به proxy متصل نمایید و اجازه دهید labelهای router، نام دامنه و گواهی را مدیریت کنند.

پنج نکته در اینجا اهمیت ویژه‌ای دارند.

exposedByDefault=false باعث می‌شود کانتینر تا زمانی که برچسب traefik.enable=true را نداشته باشد، برای Traefik نامرئی بماند. اگر این مورد را حذف کنید، برای هر کانتینری که اجرا می‌کنید—از جمله کانتینرهای موقت postgres که برای تست چیزی بالا آورده‌اید—یک مسیر (route) تولید می‌شود.

providers.docker.network=proxy به Traefik می‌گوید که وقتی یک کانتینر به چندین شبکه متصل است، از کدام شبکه استفاده کند. اگر این مورد را نادیده بگیرید، ممکن است Traefik آی‌پی اشتباهی را انتخاب کند که منجر به خطای 502 می‌شود؛ خطایی که در ظاهر شبیه به مشکل برنامه به نظر می‌رسد.

loadbalancer.server.port=3000 پورتی است که داخل کانتینر قرار دارد؛ برای مثال Gitea روی پورت 3000 گوش می‌دهد. توجه داشته باشید که هیچ‌کدام از کانتینرهای برنامه پورت خود را publish نمی‌کنند و فقط Traefik این کار را انجام می‌دهد.

تغییر مسیر (redirect) روی entrypoint به نام web به‌صورت پیش‌فرض دائمی است، بنابراین یک درخواست GET ساده (که مرورگر ارسال می‌کند) با کد 301 به HTTPS هدایت می‌شود؛ Traefik برای متدهای دیگر مانند POST از کد 308 استفاده می‌کند تا متد درخواست در طول انتقال حفظ شود. پورت 80 در هر صورت باز می‌ماند: چالش ACME HTTP به آن نیاز دارد و همچنین کاربرانی که نام دامنه را بدون پروتکل وارد می‌کنند، از این طریق هدایت می‌شوند.

تکرار $$ در هش basic-auth به دلیل escaping در Compose است و غلط تایپی نیست. آن را با htpasswd -nbB admin 'your-password' (از بسته apache2-utils) تولید کنید و سپس تمام علامت‌های $ را دوبرابر کنید.

گواهی و تله acme.json

tlschallenge=true از TLS-ALPN-01 استفاده می‌کند: Let's Encrypt به سرور شما روی پورت 443 متصل می‌شود و Traefik چالش را درون TLS handshake پاسخ می‌دهد. جایگزین آن HTTP-01 روی پورت 80 است؛ خط tlschallenge را در لیست command: مربوط به Traefik با این دو مورد جایگزین کنید:

      - --certificatesresolvers.le.acme.httpchallenge=true
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web

هر دو روش کار می‌کنند. هر دو مستلزم آن هستند که DNS عمومی برای نام میزبان از قبل به VPS شما اشاره کند تا مرجع صدور گواهی (CA) بتواند نام را resolve کرده و از خارج متصل شود. ابتدا رکورد A (و AAAA) را ایجاد کنید، با dig +short git.example.com آن را تأیید کنید و سپس Traefik را استارت بزنید.

حالا تله‌ای که وقت بسیاری از کاربران را می‌گیرد. Traefik کلید حساب ACME و تمام گواهی‌های صادر شده را در یک acme.json نگه می‌دارد. اگر این فایل برای گروه یا سایر کاربران قابل خواندن باشد، Traefik لاگی بسیار شبیه به این ثبت کرده و resolver را غیرفعال می‌کند. برنامه به اجرا و مسیریابی ادامه می‌دهد، اما هیچ گواهی‌ای درخواست نمی‌شود و در نتیجه هر نام میزبان با TRAEFIK DEFAULT CERT سرویس‌دهی می‌شود:

ERR The ACME resolve is skipped from the resolvers list error="unable to get ACME account: permissions 644 for /letsencrypt/acme.json are too open, please use 600" resolver=le

راه حل تمیز همان است که در بالا ذکر شد: دایرکتوری را bind-mount کنید و اجازه دهید Traefik فایل را خودش با مجوز صحیح ایجاد کند. اگر acme.json را با touch ایجاد کرده‌اید، umask شما آن را 644 قرار داده است. آن را روی میزبان اصلاح کنید:

chmod 600 ./letsencrypt/acme.json
docker compose restart traefik

از این دایرکتوری به همراه volumeهای برنامه خود نسخه پشتیبان تهیه کنید. از دست دادن آن برای یک بار قابل جبران است و گواهی‌ها دوباره صادر می‌شوند، اما پاک کردن آن در هر بار redeploy، شما را با محدودیت صدور 5 گواهی برای هر مجموعه دقیق از نام‌های میزبان در هر 7 روز مواجه می‌کند.

هنگام تست و توسعه از staging CA استفاده کنید. خط caserver را از حالت کامنت خارج کنید، تمام مسیرها را فعال کنید، سپس آن را دوباره کامنت کرده و acme.json را حذف کنید تا گواهی‌های production به‌صورت تازه درخواست شوند. Let's Encrypt در حالت production اجازه صدور 5 گواهی تکراری در هفته برای یک مجموعه یکسان از نام‌های میزبان را می‌دهد و درخواست‌های ناموفق مکرر برای یک نام را محدود (throttle) می‌کند. حالت staging گواهی‌های غیرقابل اعتماد صادر می‌کند، مرورگر شما هشدار می‌دهد و همین هشدار نشانه موفقیت‌آمیز بودن عملیات با محدودیت‌های بسیار منعطف‌تر است.

داشبورد یک سطح کنترل است، نه یک دمو

بیشتر راهنماهای شروع سریع، --api.insecure=true را تنظیم می‌کنند که داشبورد را روی پورت 8080 بدون احراز هویت ارائه می‌دهد. روی سروری با IP عمومی، این کار توپولوژی مسیریابی، نام‌های میزبان، نام‌های میان‌افزار و پورت‌های backend شما را در اختیار هر کسی که آن را اسکن کند، قرار می‌دهد.

برچسب‌های موجود در سرویس traefik در بالا، جایگزین این وضعیت هستند: داشبورد مانند هر برنامه دیگری، روی یک نام میزبان واقعی، از طریق TLS و پشت basicauth مسیریابی می‌شود. service=api@internal همان چیزی است که مسیریاب را به API داخلی Traefik متصل می‌کند. با زنجیره‌سازی یک لیست مجاز IP که از چپ به راست اعمال می‌شود، امنیت آن را بیشتر کنید. اگر آدرس دفتر شما پویا است، محدوده را روی زیرشبکه‌ای تنظیم کنید که توسط یک WireGuard VPN که روی همان VPS میزبانی می‌کنید ارائه می‌شود و فقط از طریق تونل به داشبورد دسترسی پیدا کنید:

- traefik.http.middlewares.office.ipallowlist.sourcerange=10.0.0.7/32
- traefik.http.routers.dashboard.middlewares=office,dashboard-auth

یک رمز عبور مشترک basicauth زمانی که پنج برنامه به حساب‌های کاربری مجزا نیاز دارند، دیگر قابل دفاع نیست. همان جایگاه میان‌افزار می‌تواند یک forwardauth را بپذیرد که تصمیم‌گیری را به Authentik، یک سرور احراز هویت یکپارچه (SSO) خودمیزبان واگذار می‌کند؛ بنابراین داشبورد و تمام مسیرهای کنار آن، پشت یک ورود واحد قرار می‌گیرند که می‌توانید آن را از یک نقطه مرکزی ابطال کنید.

دسترسی root سوکت Docker

/var/run/docker.sock یک API است که می‌تواند containerای ایجاد کند که / را از میزبان mount می‌کند. دسترسی به آن معادل دسترسی root روی ماشین است و Traefik برای خواندن labelها به آن نیاز دارد.

:ro را روی mount حفظ کنید، اما شفاف باشید که این کار چه مزیتی دارد: این کار فقط فایل سوکت را به حالت read-only در می‌آورد. این کار مانع از ارسال درخواست‌های POST به API داکر از طریق آن نمی‌شود. راهکار واقعی این است که هرگز سوکت را مستقیماً به Traefik ندهید و یک proxy فیلترکننده در میان قرار دهید:

  dockerproxy:
    image: tecnativa/docker-socket-proxy   # pin the current tag
    restart: unless-stopped
    environment:
      CONTAINERS: 1
      NETWORKS: 1
      POST: 0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy

volume سوکت را از Traefik حذف کنید و provider را به سمت proxy هدایت کنید:

--providers.docker.endpoint=tcp://dockerproxy:2375

Traefik دسترسی خواندن به containerها و شبکه را حفظ می‌کند و قابلیت ایجاد هرگونه منبع جدید را از دست می‌دهد.

فایروال، پورت‌ها و قانونی که همه در آن اشتباه می‌کنند

دو پورت باز، به علاوه SSH:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

پورت‌های منتشر شده توسط Docker، فایروال ufw را دور می‌زنند. داکر قوانین iptables اختصاصی خود را تزریق می‌کند که پیش از زنجیره‌های ufw ارزیابی می‌شوند؛ بنابراین کانتینری که با ports: ["3000:3000"] اجرا شده باشد، حتی با وجود قانون deny در ufw، از اینترنت قابل دسترس است. دفاع در برابر این مسئله ساختاری است، نه پیکربندی فایروال: پورت‌ها را فقط از طریق Traefik منتشر کنید و به سایر کانتینرها فقط networks: [proxy] اختصاص دهید و هیچ پورت دیگری باز نکنید. اگر سرویسی واقعاً باید به میزبان دسترسی داشته باشد، آن را به loopback متصل کنید: "127.0.0.1:3000:3000".

عیب‌یابی: خطاهایی که واقعاً با آن‌ها مواجه می‌شوید

خطای 404 page not found، که توسط Traefik ارائه می‌شود. هیچ مسیری (router) با درخواست مطابقت ندارد. به ترتیب احتمال: کانتینر فاقد traefik.enable=true است (در حالی که exposedByDefault=false تنظیم شده است)؛ قانون Host() با نامی که تایپ کرده‌اید مطابقت ندارد؛ نام router در یک label با نام router در label دیگر متفاوت است (routers.gitea.rule و routers.gitea.entrypoints باید دقیقاً یک کلمه باشند)؛ یا نام میزبان (hostname) را داخل کوتیشن تکی قرار داده‌اید. Traefik v3 در داخل matchers از backtick یا دابل کوتیشنِ escape شده (\") استفاده می‌کند و کوتیشن تکی را نمی‌پذیرد.

خطای 502 Bad Gateway. یک router مطابقت داشته اما backend در دسترس نبوده است. تقریباً همیشه به این دلیل است که کانتینر در شبکه proxy قرار ندارد، docker inspect -f '{{json .NetworkSettings.Networks}}' gitea را بررسی کنید. گزینه دیگر، loadbalancer.server.port اشتباه است: شما پورتی را داده‌اید که منتشر (publish) شده است، یا برنامه روی پورت دیگری گوش می‌دهد. لاگ‌ها تلاش انجام شده را نام می‌برند: dial tcp 172.18.0.5:8080: connect: connection refused.

مرورگر هشدار می‌دهد و گواهی برای TRAEFIK DEFAULT CERT صادر شده است. هیچ گواهی برای آن نام میزبان وجود ندارد و Traefik گواهی پیش‌فرض خود (self-signed) را ارائه کرده است. خطوط ACME را بخوانید:

unable to obtain ACME certificate for domains "git.example.com" ...
acme: error: 400 ... DNS problem: NXDOMAIN looking up A for git.example.com

DNS هنوز به سرور اشاره نمی‌کند. رکورد را اصلاح کنید، منتظر پایان TTL بمانید و Traefik را ری‌استارت کنید.

خطای Invalid response from http://git.example.com/.well-known/acme-challenge/... در چالش HTTP: پورت 80 از خارج به Traefik نمی‌رسد، که معمولاً به دلیل فایروال سطح ارائه‌دهنده (provider-level) در مقابل VPS است، نه ufw.

گواهی‌ها هرگز صادر نمی‌شوند و DNS شما روی Cloudflare با ابر نارنجی فعال است. Cloudflare در لبه شبکه خود TLS را خاتمه می‌دهد و TLS-ALPN-01 نمی‌تواند از طریق آن تکمیل شود. هنگام صدور گواهی، رکورد را روی DNS-only قرار دهید یا از چالش DNS-01 با یک API token استفاده کنید. DNS-01 همچنین تنها چالشی است که گواهی‌های wildcard صادر می‌کند.

حلقه تغییر مسیر (Redirect loop). چیزی در مقابل Traefik قبلاً TLS را خاتمه داده و ترافیک را به صورت متن ساده (plaintext) به پورت 80 می‌فرستد؛ تغییر مسیرِ entrypoint آن را دوباره به HTTPS می‌فرستد. یکی از این دو تغییر مسیر را حذف کنید.

تداوم اجرا

Unit مربوط به Docker باید برای شروع خودکار در زمان بوت فعال باشد (systemctl is-enabled docker)، و restart: unless-stopped پشته سرویس‌ها را پس از reboot دوباره بالا می‌آورد. برای مدیریت دقیق‌تر، یک unit کوچک systemd که docker compose -f /srv/edge/compose.yml up -d را با RemainAfterExit=yes اجرا می‌کند، به شما systemctl status edge و کنترل ترتیب راه‌اندازی می‌دهد.

تگ Traefik را ثابت نگه دارید (traefik:v3.7، هرگز از latest استفاده نکنید) و روی شاخه‌ای بمانید که همچنان نسخه جدید ارائه می‌دهد. تا تاریخ 2026-10-12، Traefik نسخه v3.7 را به عنوان تنها شاخه v3 تحت پشتیبانی معرفی کرده است. نسخه v3.5 آخرین release خود یعنی v3.5.6 را در 7 نوامبر 2025 منتشر کرد. provider داکر در آن نسخه به صورت hardcode روی API نسخه 1.24 تنظیم شده است که Docker Engine 29 و نسخه‌های پس از آن، این نسخه را با خطای client version 1.24 is too old رد می‌کنند؛ در نتیجه هیچ containerای مسیریابی نمی‌شود. نسخه Traefik 3.6.1 قابلیت مذاکره نسخه Docker API را اضافه کرد و به همین دلیل است که فایل compose بالا از v3.7 استفاده می‌کند. ارتقا از v2 به v3 نحو (syntax) قوانین و نام providerها را تغییر داده است و یک latest خودکار، با خوشحالی پیکربندی‌ای را reload می‌کند که دیگر آن را نمی‌فهمد. ارتقا را آگاهانه انجام دهید: یادداشت‌های مهاجرت را بخوانید، تگ را تغییر دهید، docker compose up -d traefik را اجرا کنید و لاگ را زیر نظر بگیرید. اگر هنوز از تگ v2 استفاده می‌کنید، راهنمای مهاجرت Traefik از v2 به v3 تمام تغییر نام‌ها، حالت سازگاری و نحوه بازگشت به نسخه قبل (rollback) که گواهی‌های شما را حفظ می‌کند، توضیح می‌دهد.

از ./letsencrypt و volume داده‌های هر برنامه نسخه پشتیبان تهیه کنید. Traefik وضعیت دیگری که نتوانید از روی فایل compose بازسازی کنید، ذخیره نمی‌کند.

چه چیزی در مقیاس بزرگ دچار اختلال می‌شود

اولین محدودیت، توان عملیاتی نیست، بلکه محدودیت یک سرور واحد است: یک Traefik روی یک VPS، نقطه شکست واحد برای پنج برنامه است و از آنجا که acme.json یک ذخیره‌ساز فایل‌محور (flat-file) است، نوشتن همزمان دو نمونه Traefik روی آن باعث خرابی داده‌ها می‌شود. مقیاس‌پذیری افقی به معنای انتقال ذخیره‌سازی گواهی‌ها به خارج از فایل، یا خاتمه دادن TLS در جای دیگری است.

دومین مورد، اتصالات طولانی‌مدت است. رویدادهای ارسالی از سمت سرور (SSE)، آپلودهای حجیم و کلاینت‌های کند با تایم‌اوت‌های پاسخ‌دهی نقطه ورود (entrypoint) برخورد می‌کنند؛ --entryPoints.websecure.transport.respondingTimeouts.readTimeout و همتایان آن یعنی writeTimeout و idleTimeout، ابزارهای تنظیم این موارد هستند. WebSockets بدون نیاز به پیکربندی اضافی عبور می‌کنند.

سومین مورد، دیسک است. --accesslog=true لاگ‌ها را در stdout می‌نویسد و درایور json-file در Docker، آن‌ها را تا زمانی که محدود نشوند برای همیشه نگه می‌دارد. برای سرویس Traefik گزینه logging.options.max-size را تنظیم کنید، یا لاگ دسترسی را در یک فایل بنویسید و آن را چرخش (rotate) دهید.

هیچ‌کدام از این موارد به ارکستراتور نیاز ندارند. این تنظیمات به سروری نیاز دارند که تحت کنترل شما باشد، دارای IP واقعی بوده و پورت‌های 80 و 443 آن برای دسترسی جهانی باز باشند؛ یک VPS کوچک تنها وابستگی مورد نیاز است.

FAQ

آیا در صورت استفاده از Traefik همچنان به certbot نیاز دارم؟

خیر. ACME resolver در Traefik برای هر نام دامنه‌ای که مسیریابی می‌کند، گواهی درخواست و تمدید کرده و همه آن‌ها را در acme.json ذخیره می‌کند. Certbot زمانی ابزار مناسبی است که Nginx یا سرور دیگری خود وظیفه TLS termination را بر عهده داشته باشد؛ اجرای همزمان هر دو برای دامنه‌های یکسان، تنها باعث هدر رفتن سهمیه (rate limit) در Let’s Encrypt می‌شود.

چرا کانتینر من از طریق Traefik خطای 404 برمی‌گرداند؟

خطای 404 که توسط Traefik ارسال می‌شود به این معناست که هیچ مسیریابی (router) با درخواست مطابقت نداشته است. بررسی کنید که کانتینر دارای traefik.enable=true باشد (هنگامی که exposedByDefault=false تنظیم شده، این مورد الزامی است)، مقدار Host() با نامی که وارد کرده‌اید مطابقت داشته باشد و نام router در تمام labelهای مربوط به آن برنامه یکسان باشد. در Traefik v3، داخل matcher باید از backtick یا دابل‌کوتیشنِ escape شده استفاده کنید؛ کوتیشن تکی (single quote) پذیرفته نمی‌شود.

تفاوت بین خطای 404 و 502 در اینجا چیست؟

خطای 404 به این معناست که مسیریابی هرگز انجام نشده است؛ خطای 502 به این معناست که مسیریابی انجام شده اما backend اتصال را رد کرده است. دلایل معمول برای خطای 502 عبارتند از: کانتینری که به شبکه proxy متصل نیست، و loadbalancer.server.port که به جای پورتی که برنامه داخل کانتینر روی آن گوش می‌دهد، به یک پورت منتشر شده (published port) اشاره دارد. لاگ دسترسی (access log)، آدرس دقیقی که Traefik به آن متصل شده را نشان می‌دهد.

آیا mount کردن Docker socket به صورت read-only کافی است؟

فلگ :ro فقط فایل socket را به صورت read-only در می‌آورد، نه API پشت آن را. درخواست‌های POST همچنان از طریق آن ارسال می‌شوند و دسترسی به Docker API معادل دسترسی root روی میزبان است. راهکار امن‌تر، استفاده از کانتینر docker-socket-proxy است که در بالا نشان داده شد؛ این کانتینر فقط دسترسی خواندن کانتینرها و شبکه را به Traefik می‌دهد و دسترسی‌های نوشتن را کاملاً مسدود می‌کند.

آیا Traefik می‌تواند گواهی wildcard صادر کند؟

فقط از طریق چالش DNS-01 و با استفاده از API token مربوط به ارائه‌دهنده DNS شما. چالش‌های TLS-ALPN-01 و HTTP-01 هر کدام فقط یک نام دامنه را تایید می‌کنند و قادر به تولید گواهی wildcard نیستند. همچنین زمانی که یک CDN مانند Cloudflare وظیفه TLS termination را در مقابل VPS شما بر عهده دارد و دو چالش دیگر تکمیل نمی‌شوند، DNS-01 پاسخ نهایی است.