تنظیم SSL در Traefik با ابرآروان

این روزها با استفاده از ابزارهای متنوعی می‎توانیم گواهینامه های SSL برای دامنه هایمان صادر کنیم. در این پست به بررسی روش این کار با Traefik و ابرآروان می‎پردازیم.

تنظیم SSL در Traefik با ابرآروان

اگر پست های قبلی رو دنبال کرده باشید ، می‎دونید که Traefik یک reverse proxy و load balancer مدرن و کامله که به توسعه میکروسرویس ها خیلی کمک میکنه. از ویژگی های خوبش اینه که با Endpoint های مختلف سازگاری خوبی داره و میشه همه جا ازش استفاده کرد. برای مثال یک سرویس عادی رو باهاش مسیردهی کنید یا اینکه توی Docker یا Kubernetes ازش استفاده کنید.

پیاده سازی Load Balancer با استفاده از Traefik

نصب و استفاده از Traefik در Kubernetes

افزایش قابلیت های Traefik با Pilot


یکی از بهترین قابلیت هایی که در Traefik وجود داره ، مدیریت خودکار گواهینامه های SSL شامل ساخت ، تمدید و نگهداری اون هاست. شما به راحتی می‎توانید با استفاده از یک ACME Provider مانند Let's Encrypt برای دامنه های خودتون گواهینامه SSL بسازید.

نکته ای که اینجا باید در نظر داشته باشیم ، مدیریت این گواهینامه ها در DNS Provider هاست. برای مثال وقتی دامنه خودتون رو در پنل ابرآروان یا Cloudflare تنظیم می‎کنید ، صدور گواهینامه ها همونجا هم انجام میشه ، پس چطور باید این دو مورد رو باهم تطابق بدیم؟ مسلما گواهینامه ای که Traefik باهاش کار میکنه باید با DNS Provider یکسان باشه.

اول بیاید به سراغ ساخت گواهینامه بریم.

HTTPS در Traefik

Traefik از HTTPS و TLS پشتیبانی می کنه که به دو بخش پیکربندی تقسیم شده:

  • روترها
  • اتصال TLS

به فرض شما سرویس های مختلفی دارید که برای هر کدام از اونها یک زیر دامنه در نظر گرفتید مانند :

  • db.domain.ir
  • mail.domain.ir
  • git.domain.ir

حال باید یک گواهینامه Wildcard صادر کرده و اون رو برای تمام سرویس های خودتون اعمال کنید. در این مرحله Traefik سه انتخاب پیش روی شما قرار داده :

  • TLS Challenge : از چالش TLS-ALPN-01 برای تولید و تمدید گواهینامه های ACME با ارائه گواهی TLS استفاده میشه.
  • HTTP Challenge : از چالش HTTP-01 برای تولید و تمدید گواهینامه های ACME با ارائه یک منبع HTTP تحت یک URI معتبر استفاده میشه.
  • DNS Challenge : از چالش DNS-01 برای تولید و تمدید گواهینامه های ACME با ایجاد یک رکورد DNS استفاده میشه.

ساده ترین راه استفاده از گزینه DNS Challenge است. ما مسلما از یک DNS Provider استفاده می‎کنیم که بدون دردسر و تنظیم اضافه میشه گواهینامه هامون رو هم از همین طریق با چالش DNS-01 بسازیم.

از اونجایی که Traefik با زبان GO نوشته شده ، جهت انجام امور این بخش از کتابخانه LEGO استفاده می‎کنه.

LEGO : Let’s Encrypt client and ACME library written in Go 😉

تنظیم DNS Challenge

ابتدا روش کار رو بررسی کنیم. در اینجا ما به دو Entry Point نیاز داریم :

  • Web : برای مدیریت درخواست های ساده HTTP روی پورت 80
  • WebSecure : برای مدیریت درخواست های HTTPS روی پورت 443

پس ابتدا web را تعریف می‎کنیم :

version: "3.9"

services:
  traefik:
    image: traefik
    command:
      # Set up an insecure listener that redirects all traffic to TLS
      - "--entryPoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"

با استفاده از web تمامی درخواست های HTTP را دریافت کرده و اون ها رو به websecure با HTTPS منتقل ( Redirect ) می‎کنیم.

حال باید websecure را تعریف کنیم :

version: "3.9"

services:
  traefik:
    image: traefik
    command:
      # Set up an insecure listener that redirects all traffic to TLS
      - "--entryPoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      # Set up the TLS configuration for our websecure listener
      - "--entryPoints.websecure.address=:443"
      - "--entrypoints.websecure.http.tls=true"
      - "--entrypoints.websecure.http.tls.certResolver=letsencrypt"
      - "--entrypoints.websecure.http.tls.domains[0].main=domain.ir"
      - "--entrypoints.websecure.http.tls.domains[0].sans=*.domain.ir"

در اینجا موارد زیر اعمال شده :

  • درخواست ها روی پورت 443 دریافت می‎شه
  • برای این درخواست ها TLS اعمال می‎شه
  • برای TLS از letsencrypt استفاده شده
  • دامنه domain.ir و تمام زیردامنه های اون مورد قبوله

توجه کنید که اگر نیاز به مدیریت دامنه های متعدد دارید ، همه شون رو باید همینجا تعریف کنید. از اندیس 0 شروع میشه و همینطور ادامه پیدا میکنه

تا به اینجا ، هر دو Entry Point ما حاضر شده و حالا باید اصل کاری یعنی خود Certificates Resolver تنظیم بشه ( همون Let's Encrypt ). خوشبختانه کتابخانه LEGO از ابرآروان هم پشتیبانی می‎کنه و می‎تونیم به راحتی ازش استفاده کنیم.

version: "3.9"

services:
  traefik:
    image: traefik
    command:
      # Set up an insecure listener that redirects all traffic to TLS
      - "--entryPoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      # Set up the TLS configuration for our websecure listener
      - "--entryPoints.websecure.address=:443"
      - "--entrypoints.websecure.http.tls=true"
      - "--entrypoints.websecure.http.tls.certResolver=letsencrypt"
      - "--entrypoints.websecure.http.tls.domains[0].main=domain.ir"
      - "--entrypoints.websecure.http.tls.domains[0].sans=*.domain.ir"
      # Set up LetsEncrypt
      - "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=arvancloud"
      - "--certificatesresolvers.letsencrypt.acme.email=<YOUR EMAIL ADDRESS>"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme-arvan.json"

در اینجا dnschallenge رو فعال کرده و arvancloud رو به عنوان Provider انتخاب می‎کنیم. سپس آدرس ایمیل مورد نظر که باید گواهینامه ها برای اون صادر بشه رو هم معرفی کرده و در نهایت یک فایل JSON برای ذخیره سازی گواهینامه های صادر شده در نظر می‎گیریم.

توجه داشته باشید که اسامی عمومی DNS Provider ها با alias اونها که در اینجا استفاده می‎شه ممکنه متفاوت باشه برای مثال : G-Core -> gcore. جهت مشاهده لیست کامل Provider های پشتیبانی شده توسط LEGO به این لینک مراجعه کنید

تا اینجا همه چیز انجام شده و فقط اعتبارسنجی باقی مونده. این مورد از طریق تعریف یک متغیر ENV با عنوان ARVANCLOUD_API_KEY صورت می‎پذیره. شما نیاز به تعریف یک کلید API در پنل ابرآروان دارید که دسترسی شبکه توزیع محتوا برای اون وجود داشته باشه. سپس این کلید رو به صورت ENV تعریف می‎کنیم :

کلید API در پنل ابرآروان

تنظیمات به این شکل خواهد بود

version: "3.9"

services:
  traefik:
    image: traefik
    command:
      # Set up an insecure listener that redirects all traffic to TLS
      - "--entryPoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      # Set up the TLS configuration for our websecure listener
      - "--entryPoints.websecure.address=:443"
      - "--entrypoints.websecure.http.tls=true"
      - "--entrypoints.websecure.http.tls.certResolver=letsencrypt"
      - "--entrypoints.websecure.http.tls.domains[0].main=domain.ir"
      - "--entrypoints.websecure.http.tls.domains[0].sans=*.domain.ir"
      # Set up LetsEncrypt
      - "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=arvancloud"
      - "--certificatesresolvers.letsencrypt.acme.email=<YOUR EMAIL ADDRESS>"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme-arvan.json"
    environment:
      - "ARVANCLOUD_API_KEY=Apikey 1a4a4634-9413-5d67-f4a0-3526b893ab"

به همین راحتی تنظیمات Traefik انجام شد و برای دامنه شما یک گواهینامه WildCard صادر و تعریف می‎شه که در ادامه با فعال شدن و شناسایی هرکدام از سرویس ها ، به دامنه اون سرویس اختصاص پیدا می‎کنه ، برای مثال :

version: "3.7"

services:
  nikas:
    image: nikasproject/server:1.1.9
    labels:
      - "traefik.http.routers.nikas.rule=Host(`nikas.domain.ir`)"
      - "traefik.http.routers.nikas.entrypoints=websecure"

فقط کافیه یک Rule برای روتر سرویس تعریف کنید و دامنه/زیردامنه مورد نظر رو براش تنظیم کنید. Traefik خودکار سرویس رو شناسایی کرده ، برای اون گواهینامه صادر و ذخیره می‎کنه.

چند نکته

  1. متغیر های دیگه ای برای کار با ابرآروان وجود داره ، لیست کامل اون ها :

    • ARVANCLOUD_HTTP_TIMEOUT : API request timeout
    • ARVANCLOUD_POLLING_INTERVAL : Time between DNS propagation check
    • ARVANCLOUD_PROPAGATION_TIMEOUT : Maximum waiting time for DNS propagation
    • ARVANCLOUD_TTL : The TTL of the TXT record used for the DNS challenge

    جهت اطلاعات بیشتر به مستندات CDN API ابرآروان مراجعه کنید

  2. مسلما Let's Encrypt از Rate Limit بهره می‎بره. اطلاعات بیشتر. برای تست و آزمون و خطای خودتون در ابتدا از سرور Staging اونها استفاده کنید تا به مشکل نخورید.

  3. جهت جلوگیری از بروز خطا در معرفی گواهینامه به DNS Provider می‎تونید از یک تاخیر کوچیک در کار استفاده کنید. به صورت پیشفرض رکورد TXT ساخته شده باید تایید بشه و ممکنه این مورد زمان بر باشه ( برای ابرآروان همینطوره و مشکل وجود داره ). پس خیلی راحت با استفاده از گزینه delaybeforecheck میشه این کار رو انجام داد و برای مثال 1 ثانیه تاخیر ایجاد کنیم.

  4. تنظیمات بیشتر و کامل تری برای TLS و Let's Encrypt وجود داره. موارد توضیح داده شده در این پست ، بخش های ضروری و اصلی کار بود. با توجه به نیازهای خودتون از تنظیمات کامل تری بهره ببرید.

  5. اگر سرویس های متعددی تحت زیردامنه های مختلف اجرا می‎کنید حتما باید از WildCard و DNS-Challenge استفاده کنید وگرنه Traefik با ابرآروان مشکلات اساسی پیدا می‎کنه و باهم کنار نمیان 😂

  6. هر سوال داشتید ، اول نگاهی به مستندات بندازید و اگر راه حلی پیدا نکردید ، راحت باشید و بپرسید


با توجه به اینکه آروان اخیرا دامنه خودش رو عوض کرده حین صدور گواهینامه ها به مشکل میخورین. به روزرسانی دامنه در LEGO انجام شده ولی خب انتشار نسخه توسط اونها و پس از اون خود Traefik زمانبر خواهد بود.

برای رفع این مشکل من یک نسخه کاستوم از Traefik منتشر کردم که از آخرین نسخه استفاده بشه و API نهایی رو استفاده کنه. جهت رفع مشکل میتونید یک بار با این ایمیج پروژه خودتون رو بالا بیارید تا گواهینامه ها ساخته بشه ٬ سپس به نسخه رسمی برگردید.

version: "3.9"

services:
  traefik:
    image: hatamiarash7/traefik-r1c
    ...

اگر مشکل یا سوالی داشتید ٬ تعارف نکنید و پیام بدین 😁