آموزش دریافت گواهی wildcard با Certbot و چالش DNS-01
برای صدور گواهی wildcard در Let’s Encrypt باید از چالش DNS-01 استفاده کنید. در این راهنما نحوه تنظیم رکورد TXT، انتخاب پلاگین مناسب و خودکارسازی تمدید بدون خطا را بررسی میکنیم.
چرا گواهی wildcard به چالش DNS-01 نیاز دارد
یک گواهی wildcard تمام زیردامنههای سطح اول یک دامنه را پوشش میدهد: *.example.com با app.example.com، blog.example.com و هر نام دیگری که در یک سطح قرار دارد، مطابقت میکند. سرویس Let’s Encrypt گواهیهای wildcard را تنها از طریق چالش DNS-01 صادر میکند؛ بنابراین Certbot باید با انتشار یک رکورد TXT در _acme-challenge.example.com، کنترل خود بر DNS دامنه را اثبات کند. چالش HTTP-01 برای این کار مناسب نیست، زیرا ارائه یک فایل توکن تنها کنترل بر یک نام میزبان (همان نامی که سرور اعتبارسنجی فایل را از آن دریافت کرده) را اثبات میکند. گواهی wildcard ادعایی درباره تمام نامهای ممکن در زیرمجموعه دامنه است و تنها رکورد عمومی که برای کل فضای نام معتبر است، خودِ DNS است.
همین یک الزام، تعیینکننده تمام موارد دیگر در این صفحه است. برای عبور از چالش DNS-01، شما باید قادر باشید رکوردهای TXT را در zone دامنه خود ایجاد کنید؛ این کار یا بهصورت دستی یا از طریق API (رابط برنامهنویسی اپلیکیشن) ارائهدهنده DNS شما انجام میشود. روش دستی برای یک بار کار میکند اما در زمان تمدید با شکست مواجه میشود، که دلیل مشخص آن در ادامه آمده است. روش API، که از طریق پلاگین DNS در Certbot انجام میشود، تمدید را بهصورت خودکار و بدون نیاز به دخالت انجام میدهد و این همان پیکربندی نهایی است که باید به آن برسید.
این فصل مربوط به wildcard در راهنماهای Certbot ما است. گواهیهای معمولی تکنام، پیکربندی وبسرور و قوانین پورت 80 در Certbot با nginx روی Ubuntu 24.04 و Certbot با Apache روی Ubuntu 24.04 پوشش داده شدهاند.
نحوه عملکرد رکورد TXT در _acme-challenge
هنگامی که Certbot درخواست *.example.com را ارسال میکند، Let's Encrypt با یک توکن تصادفی پاسخ میدهد. Certbot آن توکن را با کلید حساب ACME (محیط مدیریت خودکار گواهی) شما ترکیب کرده، نتیجه را با SHA-256 هش میکند و یک مقدار متنی کوتاه تولید مینماید. آن مقدار باید به عنوان یک رکورد TXT در _acme-challenge.example.com ظاهر شود. سپس Let's Encrypt از زیرساخت خود، سرورهای نام معتبر (authoritative name servers) دامنه شما را پرسوجو میکند. اگر رکوردی که میخواند با مقدار مورد انتظار مطابقت داشته باشد، شما ثابت کردهاید که کنترل zone را در اختیار دارید و کنترل zone به عنوان کنترل تمام نامهای زیرمجموعه آن پذیرفته میشود.
دو جزئیات باعث بروز اکثر خطاها میشوند:
- درخواست
example.comو*.example.comدر یک گواهی واحد به معنای دو چالش جداگانه است و هر دو رکورد TXT در یک نام واحد یعنی_acme-challenge.example.comقرار میگیرند. هر دو باید همزمان وجود داشته باشند. افزودن رکورد دوم صحیح است؛ جایگزین کردن رکورد اول با رکورد دوم باعث شکست چالش اول میشود. - اعتبارسنجی، سرورهای معتبر شما را میخواند، اما پنلهای کنترل ارائهدهنده ممکن است یک دقیقه یا بیشتر زمان نیاز داشته باشند تا رکورد جدید را به آنها منتقل کنند. پیش از آنکه اجازه دهید اعتبارسنجی اجرا شود، از بیرون بررسی کنید:
dig +short TXT _acme-challenge.example.com @1.1.1.1هنگامی که این دستور مقداری را که Certbot درخواست کرده چاپ کند، اعتبارسنجی میتواند با موفقیت انجام شود. اگر چیزی چاپ نکرد، صبر کنید و دوباره آن را اجرا کنید.
مشاهده عملکرد در حالت دستی
حالت دستی (manual mode) شما را ملزم میکند که ویرایش DNS را شخصاً انجام دهید؛ این بهترین روش برای درک مکانیزم پیش از خودکارسازی آن است:
sudo certbot certonly --manual --preferred-challenges dns -d example.com -d '*.example.com'استفاده از کوتیشن در اطراف wildcard مانع از آن میشود که shell شما * را به عنوان یک الگوی نام فایل در نظر بگیرد. Certbot با ارائه دستورالعملها متوقف میشود:
Please deploy a DNS TXT record under the name:
_acme-challenge.example.com.
with the following value:
Jx9mQ2wLr8vTn5cKp0aYdG3hB7fZs4eN1oiRuXqMk6Eآن رکورد TXT را در پنل ارائهدهنده DNS خود ایجاد کنید، با استفاده از دستور dig در بالا تأیید کنید که قابل مشاهده است و تنها پس از آن کلید Enter را فشار دهید. از آنجا که این اجرا هم دامنه اصلی و هم wildcard را درخواست میکند، Certbot دو بار از شما میخواهد که این کار را انجام دهید؛ هر دو رکورد را تا پایان صدور گواهی در جای خود نگه دارید. موفقیت با خطوط آشنای زیر به پایان میرسد:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pemچرا حالت manual نمیتواند بهطور خودکار تمدید شود
هر تمدید، یک چالش جدید با یک توکن جدید است، بنابراین مقدار TXT هر بار تغییر میکند. رکوردی که امروز وارد کردهاید، پس از 60 روز دیگر کاربردی ندارد. تایمر تمدید، Certbot را بهصورت خودکار دو بار در روز اجرا میکند و کسی پشت سیستم نیست تا مقدار جدید را وارد کند؛ به همین دلیل، گواهیهایی که بهصورت دستی صادر شدهاند، در زمان تمدید با این خطای مشخص مواجه میشوند:
Failed to renew certificate example.com with error: The manual plugin is not
working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with
--manual-auth-hook when using the manual plugin non-interactively.')شما میتوانید با نوشتن اسکریپتهای --manual-auth-hook که API ارائهدهنده DNS شما را فراخوانی میکنند، این نیاز را برطرف کنید، اما در آن مرحله، عملاً در حال بازسازی دستی یک پلاگین DNS هستید. از حالت manual برای یادگیری روند کار یا برای یک مورد خاص و یکباره روی دامنهای که هنوز امکان خودکارسازی DNS آن را ندارید استفاده کنید و حتماً پیش از روز 90 یک یادآور تنظیم کنید، زیرا Let’s Encrypt دیگر ایمیلهای انقضا ارسال نمیکند. برای سایر موارد، از یک پلاگین استفاده کنید.
مسیر افزونه: certbot-dns-cloudflare در Ubuntu 24.04
یک افزونه DNS، اعتبارنامههای API ارائهدهنده DNS شما را ذخیره میکند و تمامی مراحل مربوط به رکورد TXT را در زمان صدور و هر بار تمدید، بهصورت خودکار انجام میدهد. در اینجا Cloudflare به عنوان نمونه انتخاب شده است، زیرا افزونهای است که اکثر کاربران به آن نیاز دارند و در مخازن Ubuntu نیز بستهبندی شده است.
راهنماهای Certbot ما استفاده از بستههای apt را در Ubuntu 24.04 توصیه میکنند و این رویکرد برای Cloudflare نیز صادق است:
sudo apt update
sudo apt install certbot python3-certbot-dns-cloudflareیک نکته صادقانه درباره نسخهها: مخازن 24.04 این افزونه را در نسخه 2.0.0 در کنار Certbot 2.9.0 ارائه میدهند؛ apt policy python3-certbot-dns-cloudflare نسخه شما را نشان میدهد. این عدم تطابق بیخطر است و توکنهای API محدود (scoped) بهدرستی کار میکنند، زیرا کتابخانه زیرساختی python3-cloudflare در 24.04 نسخه 2.11.1 است که بالاتر از نسخه 2.3.1 مورد نیاز افزونه برای پشتیبانی از توکن میباشد. در نسخههای قدیمیتر Ubuntu، آن کتابخانه برای توکنها بسیار قدیمی بود و هشدارهایی که ممکن است بهصورت آنلاین درباره اجبار افزونه apt به استفاده از Global API Key بیابید، از همانجا ناشی میشوند. در 24.04 این موارد دیگر موضوعیت ندارند.
در داشبورد Cloudflare، یک API token محدود ایجاد کنید، نه Global API Key: به بخش My Profile، سپس API Tokens و بعد Create Token بروید و تنها مجوز Zone / DNS / Edit را انتخاب کنید که به همان دامنهای که برای آن گواهی صادر میکنید، محدود شده باشد. آن را در فایلی قرار دهید که فقط root بتواند آن را بخواند:
sudo mkdir -p /root/.secrets
sudo tee /root/.secrets/cloudflare.ini > /dev/null <<'EOF'
dns_cloudflare_api_token = paste_your_scoped_token_here
EOF
sudo chmod 600 /root/.secrets/cloudflare.iniCertbot حالت فایل را بررسی میکند و اگر فایل برای دیگران قابل خواندن باشد، درباره Unsafe permissions on credentials configuration file هشدار میدهد. اکنون دستور صدور را اجرا کنید:
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d '*.example.com'این افزونه رکوردهای TXT را از طریق API ایجاد میکند، مدت کوتاهی برای انتشار (propagation) منتظر میماند، اجازه میدهد اعتبارسنجی انجام شود و سپس رکوردها را حذف میکند. اگر سرورهای نام (name servers) دامنه شما در اعمال تغییرات کند هستند، زمان انتظار را با --dns-cloudflare-propagation-seconds 60 افزایش دهید. گواهی در /etc/letsencrypt/live/example.com/ قرار میگیرد و شما باید nginx یا Apache را دقیقاً همانطور که در راهنماهای پایه نشان داده شده است، به fullchain.pem و privkey.pem ارجاع دهید؛ این شامل deploy hook نیز میشود.
اگر پلاگین ارائهدهنده شما در apt موجود نیست
آرشیو 24.04 تنها پلاگینهای مربوط به تعداد محدودی از ارائهدهندگان را بستهبندی کرده است که Cloudflare، Route 53، DigitalOcean و رابط عمومی RFC 2136 از آن جملهاند. برای مشاهده لیست، دستور apt search certbot-dns را اجرا کنید. اگر ارائهدهنده شما در این لیست نیست، این تنها موردی است که توصیه ما مبنی بر اولویت استفاده از apt در آن تغییر میکند: Certbot و پلاگین مربوطه را از طریق snap نصب کنید و ابتدا Certbot نصبشده با apt را حذف کنید تا دو تایمر تمدید گواهی هرگز بر سر /etc/letsencrypt با یکدیگر تداخل نداشته باشند:
sudo apt remove certbot python3-certbot-dns-cloudflare
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-yourproviderیک پلاگین snap فقط به Certbot نسخه snap متصل میشود؛ این پلاگین نمیتواند قابلیتهای نسخه apt را گسترش دهد و به همین دلیل است که این دو نصب نباید همزمان وجود داشته باشند. اگر میزبان DNS شما هیچ API ارائه نمیدهد، گزینههای واقعبینانه شما انتقال DNS دامنه به ارائهدهندهای است که دارای API باشد، یا راهاندازی name server اختصاصی خودتان و هدایت پلاگین rfc2136 به سمت آن است.
تمدید: همین حالا آزمایش کنید، نه 60 روز دیگر
ابزار Certbot نحوه صدور هر گواهی را در /etc/letsencrypt/renewal/example.com.conf ثبت میکند که شامل authenticator = dns-cloudflare و مسیر اعتبارنامهها (credentials) است؛ بنابراین تایمر استاندارد که دو بار در روز اجرا میشود، تمدید را بدون نیاز به دخالت شما انجام میدهد. کل فرآیند را در محیط staging آزمایش کنید:
sudo certbot renew --dry-runموفقیت در این مرحله به این معناست که اعتبارنامه بهدرستی کار میکند و اعتبارسنجی بهصورت کامل انجام میشود؛ تمدید واقعی در 60 روز آینده نیز همین مسیر را طی خواهد کرد. انجام دو اقدام تکمیلی در امروز توصیه میشود. نخست، تمدید گواهی روی دیسک تا زمانی که وبسرور آن را مجدداً بارگذاری (reload) نکند، تغییری ایجاد نمیکند؛ بنابراین از deploy hook که در راهنماهای nginx و Apache توضیح داده شده است، استفاده کنید. دوم، با فایل اعتبارنامهها با دقت رفتار کنید: هر کسی که بتواند آن را بخواند، میتواند DNS zone شما را ویرایش کند که برای تغییر مسیر ایمیلها یا عبور از چالشهای DNS-01 توسط مهاجم کافی است. دسترسی فایل را در حالت 600 تحت /root نگه دارید، دامنه دسترسی توکن را به یک zone محدود کنید و در صورت شک به نشت اطلاعات، آن را تغییر دهید (rotate).
زمانی که به wildcard نیاز ندارید
استفاده از wildcard برای بسیاری از زیردامنهها یا زیردامنههایی که قابل پیشبینی نیستند، ابزار مناسبی است. اما برای سایر موارد، انتخاب پیشفرض اشتباهی محسوب میشود.
- برای یک زیردامنه یا تعداد محدودی از آنها: یک گواهی SAN (مخفف Subject Alternative Name) معمولی سادهتر است.
certbot --nginx -d example.com -d www.example.com -d app.example.comتا 100 نام را از طریق HTTP-01 ساده پوشش میدهد و هیچگونه اعتبارنامه API مربوط به DNS روی سرور قرار نمیگیرد. - یک wildcard دقیقاً با یک برچسب (label) مطابقت دارد.
*.example.comدامنه اصلیexample.comرا پوشش نمیدهد (به همین دلیل دستورات بالا هر دو را درخواست میکنند) و همچنینa.b.example.comرا نیز شامل نمیشود؛ برای این مورد به*.b.example.comنیاز است. - یک کلید خصوصی (private key) پشت تمام زیردامنهها قرار دارد. اگر ماشینی که این کلید را نگه میدارد مورد نفوذ قرار گیرد، تمام نامهایی که توسط wildcard پوشش داده میشوند، همزمان در معرض خطر قرار میگیرند.
- اگر Traefik مسئولیت TLS (مخفف Transport Layer Security) را برای کانتینرهای شما بر عهده دارد، اصلاً نیازی به Certbot ندارید: Traefik خود بهصورت خودکار گواهیهای wildcard را از طریق DNS-01 درخواست میکند و از همان نوع توکن ارائهدهنده استفاده میکند.
جایی که wildcard واقعاً کاربرد دارد: برای زیردامنههای اختصاصی هر مشتری یا هر برنامه که سریعتر از آنچه بخواهید گواهیها را بازنشر کنید ایجاد میشوند، و همچنین برای میزبانهای داخلی که پورت 80 عمومی ندارند، مانند سرویسهایی که فقط از طریق یک WireGuard VPN قابل دسترسی هستند. DNS-01 هرگز به میزبانی که گواهی برای آن صادر میشود متصل نمیشود، بنابراین حتی یک ماشین کاملاً خصوصی نیز میتواند یک گواهی با اعتبار عمومی داشته باشد.
FAQ
آیا Certbot میتواند گواهی wildcard را با چالش HTTP-01 صادر کند؟
خیر. چالش HTTP-01 کنترل بر یک نام میزبان (hostname) خاص را اثبات میکند، زیرا سرور اعتبارسنجی، یک فایل توکن را دقیقاً از همان نام دریافت میکند. گواهی wildcard تمام نامهای زیرمجموعه یک دامنه را پوشش میدهد، بنابراین Let's Encrypt برای آن به چالش DNS-01 نیاز دارد و احرازکنندههای --nginx، --apache، --webroot و --standalone همگی مبتنی بر HTTP هستند. تنها راه، ایجاد یک رکورد TXT در _acme-challenge.example.com است که باید بهصورت دستی یا توسط یک افزونه DNS قرار داده شود.
آیا گواهی wildcard دامنه اصلی (root domain) را پوشش میدهد؟
خیر. wildcard دقیقاً با یک سطح از نام مطابقت دارد، بنابراین *.example.com نام www.example.com را پوشش میدهد اما دامنه اصلی example.com و همچنین a.b.example.com را شامل نمیشود. هر دو نام را در یک گواهی با استفاده از -d example.com -d '*.example.com' درخواست کنید. این کار دو چالش ایجاد میکند و هر دو رکورد TXT در همان نام _acme-challenge.example.com قرار میگیرند، بنابراین رکورد دوم را بدون حذف رکورد اول اضافه کنید.
چرا گواهی wildcard من بهطور خودکار تمدید نمیشود؟
زیرا این گواهی با استفاده از --manual صادر شده است. هر تمدید به یک مقدار TXT کاملاً جدید نیاز دارد و تایمر خودکار راهی برای درج آن ندارد، بنابراین تمدید با خطای An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively متوقف میشود. گواهی را با یک افزونه DNS مانند certbot-dns-cloudflare مجدداً صادر کنید، یا اسکریپتهای --manual-auth-hook و --manual-cleanup-hook را ارائه دهید که رکورد را از طریق API ارائهدهنده DNS شما ویرایش کنند.
ظاهر شدن رکورد TXT با نام _acme-challenge چقدر طول میکشد؟
این زمان به ارائهدهنده DNS شما بستگی دارد: از چند ثانیه تا چندین دقیقه. اعتبارسنجی، سرورهای معتبر (authoritative) منطقه شما را میخواند، بنابراین با استفاده از dig +short TXT _acme-challenge.example.com @1.1.1.1 بررسی کنید و پیش از ادامه اجرای دستی، منتظر بمانید تا مقدار مورد انتظار ظاهر شود. در صورت استفاده از افزونه، زمان انتظار داخلی را از طریق گزینه propagation افزونه افزایش دهید؛ برای مثال --dns-cloudflare-propagation-seconds 60، اگر اعتبارسنجی گزارش میدهد که رکورد پیدا نشده است.
آیا امنیت گواهی wildcard کمتر از گواهی معمولی است؟
رمزنگاری هر دو یکسان است. تفاوتها عملیاتی هستند: یک کلید خصوصی تمام زیردامنهها را پوشش میدهد، بنابراین در صورت نفوذ، دامنه آسیب گستردهتر است؛ همچنین اعتبارنامه API مربوط به DNS که برای اتوماسیون مورد نیاز است، خود یک راز حساس محسوب میشود که روی سرور ذخیره شده است. اگر فقط تعداد کمی زیردامنه مشخص را اجرا میکنید، گواهی SAN هر دو نگرانی را برطرف میکند؛ دقیقاً به همین دلیل است که این راهنما توصیه میکند در آن شرایط از wildcard استفاده نکنید.