Skip to Content

SSL برای سرویس‌های Docker چگونه تنظیم می‌شود؟ از صدور گواهی تا تمدید و آزمون

TLS سرویس‌های Docker را معمولاً روی reverse proxy terminate کنید؛ انتخاب ACME challenge، نگهداری کلید خصوصی، تمدید، reload و آزمون بیرونی را درست انجام دهید.

نویسنده مدیر کل تاریخ انتشار
این پست را به اشتراک بگذارید

سرویس داخل Docker برای داشتن HTTPS لزوماً نباید خودش گواهی بخواند. در معماری رایج، Nginx یا reverse proxy پورت 443 را می‌گیرد، گواهی دامنه را ارائه می‌کند و درخواست را از network داخلی به app می‌فرستد. سختی اصلی صدور اولیه نیست؛ تطبیق hostname، حفاظت private key، تمدید بدون قطعی، reload proxy و آزمون گواهی‌ای است که کاربر واقعاً از اینترنت می‌بیند.

پاسخ سریع: ابتدا DNS و مالکیت دامنه را روشن کنید. بسته به شرایط از ACME HTTP-01 یا DNS-01، یا گواهی معتبر تهیه‌شده استفاده کنید. full chain و private key را فقط‌خواندنی و محدود در اختیار proxy بگذارید؛ HTTP را طبق سیاست به HTTPS هدایت کنید؛ renewal را زمان‌بندی و با reload کنترل‌شده همراه کنید؛ expiry و chain را از بیرون مانیتور کنید.

TLS در کدام نقطه terminate شود؟

برای چند app روی یک host، termination در reverse proxy مدیریت دامنه، certificate و redirect را ساده می‌کند. ارتباط proxy تا app می‌تواند در network داخلی همان host HTTP باشد، اگر مدل تهدید آن را می‌پذیرد. اگر ترافیک بین hostها یا شبکه نامطمئن حرکت می‌کند، TLS داخلی یا مکانیزم محافظت معادل را جدا بررسی کنید. «داخل Docker است» به‌تنهایی به معنی امن بودن مسیر نیست.

دامنه و DNS را قبل از certificate بررسی کنید

گواهی باید hostname واقعی مرورگر را پوشش دهد. رکورد A/AAAA، CDN، load balancer و origin را با مسیر درخواست تطبیق دهید. اگر IPv6 به host دیگری می‌رود، کاربران ممکن است گواهی متفاوت ببینند. redirect از HTTP به HTTPS نیز تنها وقتی درست است که HTTPS برای همان hostname آماده باشد. گواهی wildcard زیر‌دامنه‌ها را پوشش می‌دهد، نه لزوماً دامنه ریشه؛ SAN گواهی را بررسی کنید.

HTTP-01 یا DNS-01؟

در ACME HTTP-01، اعتبارسنجی از مسیر HTTP دامنه انجام می‌شود؛ پورت و routing challenge باید به محل درست برسند. DNS-01 با رکورد TXT مالکیت دامنه را اثبات می‌کند و برای wildcard لازم است. انتخاب بین آن‌ها به DNS provider، دسترسی API، توپولوژی CDN و نیاز wildcard بستگی دارد. token DNS دامنه بسیار حساس است؛ scope حداقلی و نگهداری امن داشته باشد.

وقتی گواهی از قبل تهیه شده

ابتدا نام دامنه، زمان اعتبار، زنجیره صادرکننده و جفت‌بودن certificate و key را با ابزار مناسب بررسی کنید. فایل fullchain و private key را در image یا repository کپی نکنید. آن‌ها را روی host یا secret store با دسترسی محدود نگه دارید و فقط‌خواندنی به container proxy mount کنید. اگر گواهی wildcard از فروشنده گرفته‌اید، چرخه تمدیدش ممکن است با Certbot/ACME متفاوت باشد؛ فرض نکنید خودکار تمدید می‌شود.

مجوز private key و user کانتینر

کلید خصوصی باید فقط برای فرایندی که TLS را ارائه می‌کند خواندنی باشد. مجوز بیش‌ازحد باز برای «رفع خطا» راه‌حل نیست. اگر proxy با کاربر non-root اجرا می‌شود، مالکیت، گروه یا مکانیزم secret را طوری تنظیم کنید که همان process حق خواندن داشته باشد، نه همه کاربران host. backup کلید نیز باید رمزگذاری و دسترسی‌اش کنترل شود؛ log و خروجی CI جای نمایش محتوای key نیست.

نمونه مسیر منطقی Compose

یک volume یا bind mount فقط‌خواندنی برای certificate در سرویس Nginx تعریف کنید؛ app فقط network داخلی را ببیند و کلید را دریافت نکند. پورت‌های 80 و 443 تنها برای proxy publish شوند. اگر ACME HTTP-01 دارید، مسیر challenge باید در routing proxy و فرایند صدور مشترک و قابل‌نوشتن در محل لازم باشد. نوع mount و سطح دسترسی را با ابزار صدور گواهی هماهنگ کنید؛ این راهنما نسخه آماده YAML برای همه providerها نیست.

Headerهای مربوط به HTTPS

بعد از termination، proxy باید scheme اصلی را به app منتقل کند؛ معمولاً با headerهایی مثل X-Forwarded-Proto. برنامه باید فقط به proxy مورداعتماد اعتماد کند، وگرنه client می‌تواند header را جعل کند. اگر برنامه redirect loop دارد یا URLها HTTP ساخته می‌شوند، علاوه بر Nginx تنظیمات proxy-awareness خود framework را بررسی کنید. راهنمای Nginx برای Docker این مرز اعتماد را توضیح می‌دهد.

HTTP به HTTPS و HSTS

redirect را پس از اطمینان از صحت گواهی و مسیر 443 فعال کنید. HSTS مرورگر را برای مدت تعیین‌شده به HTTPS محدود می‌کند؛ اعمال اشتباه یا preload عجولانه می‌تواند بازگشت از خطای TLS را دشوار کند. ابتدا دامنه‌ها و زیر‌دامنه‌ها، سرویس‌های قدیمی و پنل‌های دیگر را بررسی کنید. صرف داشتن redirect، محتوای mixed content در HTML و asset را اصلاح نمی‌کند.

تمدید فقط نوشتن فایل تازه نیست

فرایند renew باید خطا را گزارش کند، فایل معتبر جدید را در مسیر موردانتظار قرار دهد و proxy آن را بدون قطع غیرضروری بارگذاری کند. بسیاری proxyها پس از تعویض فایل، certificate تازه را تا reload ارائه نمی‌کنند. قبل از reload config را تست کنید و سپس certificate ارائه‌شده از بیرون را ببینید. اگر deployment شما symlink یا volume خاص دارد، مطمئن شوید container پس از renewal فایل تازه را واقعاً می‌بیند.

چطور renewal را آزمون کنیم؟

  1. روش صدور و مالکیت فرایند renew را مستند کنید.
  2. در محیط امن، dry-run یا آزمون معادل provider را انجام دهید.
  3. خطای DNS، بسته بودن port یا کمبود مجوز فایل را شبیه‌سازی/بررسی کنید.
  4. نتیجه آزمون config و reload proxy را ثبت کنید.
  5. گواهی ارائه‌شده از بیرون را پس از reload با hostname درست بررسی کنید.
  6. هشدار expiry را مستقل از job renewal تنظیم کنید.

dry-run صدور گواهی جای آزمون deployment واقعی نیست؛ ممکن است renewal موفق باشد اما proxy هنوز فایل قدیمی را بخواند. expiry را با فاصله‌ای هشدار دهید که برای اصلاح DNS یا اعتبارنامه فرصت کافی باشد.

CDN و دو اتصال TLS

اگر CDN جلوی proxy است، TLS مرورگر تا CDN و TLS CDN تا origin دو مسیر جدا هستند. گواهی‌ای که کاربر می‌بیند ممکن است با گواهی origin فرق کند. حالت‌های «flexible» یا HTTP از CDN به origin می‌توانند امنیت و redirect را پیچیده کنند؛ سیاست اتصال end-to-end متناسب انتخاب کنید. برای تشخیص، هر مسیر را جدا آزمون کنید و secret مربوط به CDN را بی‌دلیل در app قرار ندهید.

چرا هنوز خطای certificate می‌بینم؟

  • گواهی hostname را پوشش نمی‌دهد یا دامنه ریشه از wildcard جا مانده است.
  • full chain ناقص است.
  • ساعت سرور/کلاینت یا زمان اعتبار مشکل دارد.
  • DNS به proxy دیگری می‌رسد؛ IPv4 و IPv6 را جدا بررسی کنید.
  • proxy پس از تمدید reload نشده است.
  • CDN گواهی قدیمی یا origin نامعتبر ارائه می‌کند.

پیش از جایگزین‌کردن گواهی، مقصد DNS و SNI را بررسی کنید. تعویض فایل درست روی host اشتباه هیچ اثری برای کاربر ندارد. لاگ Nginx و ابزار آزمون بیرونی را در یک زمان مقایسه کنید.

مانیتورینگ مستقل

سنجه مهم تاریخ انقضای گواهی ارائه‌شده از اینترنت، صحت hostname/chain و نتیجه آخرین renewal است. وجود فایل تازه روی disk کافی نیست. هشدار باید برای دامنه‌های مهم، زیر‌دامنه‌ها و مسیر CDN/origin مناسب تنظیم شود. راهنمای مانیتورینگ سرور این کار را کنار DNS و سلامت HTTP قرار می‌دهد.

اشتباه‌های پرهزینه

قرار دادن private key در image، بازکردن مجوز آن برای همه، اتکا به renew بدون reload، فرض پوشش دامنه ریشه توسط wildcard، افزودن HSTS قبل از آماده‌بودن همه زیر‌دامنه‌ها و نادیده‌گرفتن IPv6 از خطاهای رایج‌اند. همچنین renew کردن با چند فرایند مستقل روی یک مسیر می‌تواند race و limit provider ایجاد کند؛ یک مالک مشخص برای چرخه گواهی تعیین کنید.

چه زمانی کمک تخصصی لازم است؟

اگر چند دامنه، wildcard، CDN، proxy و سرویس داخلی دارید، پیش از تغییر certificate در production نقشه مسیر TLS و برنامه rollback تهیه کنید. داکرایز اپلیکیشن می‌تواند termination، secret، renew و آزمون بیرونی را با طراحی network و deployment هماهنگ کند.

پرسش‌های متداول

آیا هر container به گواهی جدا نیاز دارد؟

نه؛ اغلب proxy مشترک TLS عمومی را terminate می‌کند. TLS داخلی به مدل تهدید و مسیر شبکه بستگی دارد.

آیا wildcard دامنه اصلی را هم پوشش می‌دهد؟

نه به‌طور خودکار؛ نام‌های SAN گواهی را بررسی کنید و برای دامنه ریشه پوشش جدا داشته باشید.

چرا Certbot موفق است اما مرورگر گواهی قبلی را می‌بیند؟

ممکن است proxy reload نشده، mount فایل تازه را نبیند یا ترافیک به CDN/host دیگری برسد.

آیا می‌توان private key را در image گذاشت؟

خیر؛ image و لایه‌های آن قابل‌توزیع و نگهداری‌اند. کلید را خارج image با دسترسی محدود مدیریت کنید.

تنظیم Nginx به‌عنوان Reverse Proxy برای Docker؛ شبکه، Header، WebSocket و عیب‌یابی
برای اتصال Nginx به سرویس Docker، شبکه مشترک، نام سرویس، Host و Forwarded Header، WebSocket، timeout، سلامت upstream و مرز اعتماد IP را درست تنظیم کنید.