آموزش صدور گواهی Wildcard با Certbot و چالش DNS-01
برای صدور گواهی Wildcard با Certbot باید از چالش 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 را در زون دامنه یا در یک زون اعتبارسنجی جداگانه که _acme-challenge با یک CNAME به آن اشاره میکند (در ادامه توضیح داده شده)، ایجاد کنید؛ این کار یا بهصورت دستی یا از طریق 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 متصل میشود؛ این پلاگین نمیتواند Certbot نصبشده با apt را گسترش دهد، به همین دلیل است که این دو نصب نباید همزمان وجود داشته باشند. اگر میزبان DNS شما هیچ API ارائه نمیدهد، سه گزینه واقعبینانه دارید. میتوانید DNS دامنه را به ارائهدهندهای منتقل کنید که API دارد. میتوانید سرور نام (name server) خود را اجرا کنید و پلاگین rfc2136 را به آن اشاره دهید. یا میتوانید میزبان DNS فعلی خود را حفظ کرده و یک CNAME یکباره از _acme-challenge.example.com به یک زون اعتبارسنجی که دارای API است (مانند سرویس میزبانیشده acme-dns یا سرور acme-dns که خودتان اجرا میکنید) اضافه کنید. Let’s Encrypt در حین اعتبارسنجی آن CNAME را دنبال میکند، بنابراین رکوردهای TXT در زون تفویضشده باقی میمانند و زون اصلی شما دیگر تغییر نخواهد کرد.
تمدید: همین حالا آزمایش کنید، نه 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 میتواند با HTTP-01 گواهی wildcard صادر کند؟
خیر. HTTP-01 کنترل بر یک نام میزبان را اثبات میکند، زیرا سرور اعتبارسنجی یک فایل توکن را دقیقاً از همان نام دریافت میکند. یک wildcard تمام نامهای سطح اول زیر دامنه را پوشش میدهد، بنابراین Let’s Encrypt برای آن به چالش DNS-01 نیاز دارد و احرازکنندههای --nginx، --apache، --webroot و --standalone همگی مبتنی بر HTTP هستند. تنها راه، استفاده از یک رکورد TXT در _acme-challenge.example.com (یا در زونی که به آن CNAME تفویض شده است) است که بهصورت دستی یا توسط یک پلاگین DNS قرار داده میشود.
آیا گواهی wildcard دامنه ریشه (root domain) را پوشش میدهد؟
خیر. wildcard دقیقاً با یک برچسب (label) مطابقت دارد، بنابراین *.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 ارائهدهنده شما ویرایش کنند.
ظاهر شدن رکورد 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 صرفنظر کنید.