دریافت گواهی wildcard با Certbot و DNS-01
آموزش کامل صدور گواهی wildcard با استفاده از چالش DNS-01 در Certbot. یادگیری نحوه استفاده از TXT record و تنظیم پلاگین برای تمدید خودکار گواهیها.
چرا یک گواهی wildcard به DNS-01 نیاز دارد
یک گواهی wildcard تمام زیردامنه های سطح اول یک دامنه را پوشش میدهد: *.example.com شامل app.example.com، blog.example.com و هر نام دیگری که تنها یک سطح (label) داشته باشد میشود. Let's Encrypt گواهیهای wildcard را فقط از طریق چالش DNS-01 صادر میکند؛ بنابراین Certbot باید با انتشار یک رکورد TXT در _acme-challenge.example.com، مالکیت DNS دامنه را اثبات کند. چالش HTTP-01 نمیتواند برای این کار استفاده شود، زیرا ارائه یک فایل توکن فقط مالکیت یک hostname خاص را اثبات میکند؛ یعنی همان hostnamهای که سرور اعتبارسنجی فایل را از آن دریافت کرده است. یک wildcard ادعای مالکیت بر تمام نامهای ممکن زیر مجموعه دامنه است و تنها رکورد عمومی که برای کل فضای نام (namespace) صحبت میکند، خودِ DNS است.
این تنها الزام، تمام موارد دیگر در این صفحه را تعیین میکند. برای عبور از چالش DNS-01، شما باید بتوانید در منطقه (zone) دامنه خود رکوردهای TXT ایجاد کنید؛ این کار یا به صورت دستی و یا از طریق API (رابط برنامهنویسی اپلیکیشن) ارائهدهنده DNS شما انجام میشود. روش دستی فقط برای بار اول کار میکند و در مرحله تمدید با شکست مواجه میشود؛ دلیل این اتفاق در ادامه توضیح داده شده است. روش API که از طریق یک افزونه DNS در Certbot انجام میشود، به صورت خودکار تمدید میشود و این همان تنظیماتی است که باید در نهایت به آن برسید.
این بخش، فصل مربوط به wildcard در راهنماهای Certbot ما است. گواهیهای معمولی برای تکhostname، پیکربندی وبسرور و قوانین port 80 در Certbot with nginx on Ubuntu 24.04 و Certbot with Apache on 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) را در اختیار دارید؛ کنترل منطقه به معنای کنترل بر تمام زیرنامههای زیر آن تلقی میشود.
دو مورد باعث بیشتر خطاها میشوند:
- درخواست
example.comو*.example.comبرای یک گواهینامه واحد به معنای دو چالش مجزا است و هر دو رکورد TXT در یک نام یکسان یعنی_acme-challenge.example.comقرار میگیرند. هر دو باید همزمان وجود داشته باشند. اضافه کردن رکورد دوم روش صحیح است؛ اما جایگزین کردن رکورد اول با رکورد دوم باعث شکست چالش اول میشود. - فرآیند اعتبارسنجی (validation) سرورهای مرجع شما را میخواند، اما پنلهای مدیریتی ارائهدهنده ممکن است یک دقیقه یا بیشتر زمان ببرد تا رکورد جدید را به آنها منتقل کنند. پیش از شروع فرآیند اعتبارسنجی، وضعیت را از بیرون بررسی کنید:
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'قرار دادن علامت نقلقول (quotes) در اطراف wildcard باعث میشود shell عبارت * را به عنوان یک الگوی نام فایل (filename pattern) در نظر نگیرد. Certbot با ارائه دستورالعملها متوقف میشود:
Please deploy a DNS TXT record under the name:
_acme-challenge.example.com.
with the following value:
Jx9mQ2wLr8vTn5cKp0aYdG3hB7fZs4eN1oiRuXqMk6Eآن رکورد TXT را در پنل ارائهدهنده DNS خود ایجاد کنید، با استفاده از دستور dig که در بالا آمده تایید کنید که رکورد قابل مشاهده است، و تنها پس از آن Enter را فشار دهید. از آنجایی که این اجرا شامل bare domain و wildcard است، Certbot دو بار درخواست میدهد؛ هر دو رکورد را تا پایان فرآیند صدور (issuance) حفظ کنید. موفقیت با خطوط آشنای زیر پایان مییابد:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pemچرا حالت دستی (manual mode) نمیتواند خودش را تمدید کند
هر تمدید، یک چالش جدید با یک توکن جدید است؛ بنابراین مقدار 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 plugin هستید. از حالت manual برای یادگیری روند کار، یا برای یک مورد استثنایی و یکباره روی دامنهای که هنوز نمیتوانید DNS آن را خودکار کنید، استفاده کنید. همچنین بسیار قبل از روز 90 یک یادآور تنظیم کنید، زیرا Let's Encrypt دیگر ایمیلهای انقضا ارسال نمیکند. برای هر مورد دیگری، از یک plugin استفاده کنید.
مسیر افزونه: 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 نسخه شما را نشان میدهد. این عدم تطابق بیخطر است و توکنهای محدود شده (scoped API tokens) کار میکنند، زیرا کتابخانهی python3-cloudflare زیرساختی در 24.04 نسخه 2.11.1 است که بالاتر از نسخه 2.3.1 مورد نیاز افزونه برای پشتیبانی از توکن است. در نسخههای قدیمیتر Ubuntu، آن کتابخانه برای توکنها بسیار قدیمی بود؛ این همان دلیلی است که باعث ایجاد هشدارهای آنلاین مبنی بر اجبار افزونه apt به استفاده از Global API Key میشود. در 24.04 این هشدارها دیگر صدق نمیکنند.
در داشبورد Cloudflare، یک توکن API محدود شده (scoped API token) بسازید، نه Global API Key را: به My Profile، سپس API Tokens و سپس Create Token بروید. تنها یک دسترسی Zone / DNS / Edit را انتخاب کنید و آن را فقط به همان Zone ای که برای آن گواهی صادر میکنید، محدود کنید. آن را در فایلی قرار دهید که فقط کاربر 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 را اجرا کنید. اگر ارائهدهنده شما در لیست نیست، در این مورد خاص توصیه ما تغییر میکند: به جای آن، Certbot و پلاگین مربوطه را از طریق snap نصب کنید و ابتدا نسخه apt را حذف کنید تا دو زمانبند (timer) تمدید با هم بر سر /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 path)؛ بنابراین تایمر استاندارد که هر 12 ساعت یکبار اجرا میشود، بدون نیاز به دخالت شما، گواهی را تمدید میکند. کل این فرآیند را در محیط staging تمرین کنید:
sudo certbot renew --dry-runموفقیت در این مرحله یعنی اعتبارنامهها درست هستند و فرآیند اعتبارسنجی (validation) بهطور کامل انجام میشود؛ تمدید واقعی در 60 روز آینده نیز دقیقاً همین مسیر را طی میکند. انجام دو اقدام زیر از امروز توصیه میشود. اول، گواهی تمدید شده روی دیسک هیچ تغییری ایجاد نمیکند مگر اینکه وبسرور آن را مجدداً بارگذاری (reload) کند؛ بنابراین از deploy hook توضیح داده شده در راهنماهای nginx و Apache استفاده کنید. دوم، با فایل اعتبارنامهها با احتیاط برخورد کنید: هر کسی که بتواند آن را بخواند، میتواند منطقه DNS شما را ویرایش کند، که برای تغییر مسیر ایمیلها یا انجام چالشهای DNS-01 توسط آنها کافی است. فایل را در مسیر /root با mode 600 نگه دارید، دسترسی توکن را فقط به یک zone محدود کنید، و در صورت مشکوک شدن به لو رفتن اطلاعات، آن را تغییر دهید (rotate).
زمانی که به wildcard نیاز ندارید
wildcard ابزار مناسبی برای تعداد زیادی زیردامنه (subdomain) یا زیردامنههایی است که نمیتوانید پیشبینی کنید. برای سایر موارد، استفاده از wildcard به عنوان پیشفرض، انتخاب اشتباهی است.
- یک زیردامنه، یا تعداد محدودی زیردامنه مشخص: استفاده از یک گواهی SAN (subject alternative name) معمولی سادهتر است.
certbot --nginx -d example.com -d www.example.com -d app.example.comتا 100 نام را از طریق HTTP-01 پوشش میدهد و نیازی نیست هیچ اعتبارنامهی DNS API روی سرور باقی بماند. - یک wildcard دقیقاً با یک label مطابقت دارد.
*.example.comشاملexample.comخالی نمیشود، به همین دلیل دستورات بالا درخواست هر دو را دارند؛ همچنین*.example.comشاملa.b.example.comنیز نمیشود؛ برای آن مورد به*.b.example.comنیاز است. - هر زیردامنه دارای یک کلید خصوصی (private key) مجزا است. اگر دستگاه نگهدارندهی کلید مورد حمله قرار گیرد، تمام نامهایی که wildcard پوشش میدهد، همزمان تحت تأثیر قرار میگیرند.
- اگر Traefik وظیفهی پایان دادن TLS (transport layer security) را برای کانتینرهای شما بر عهده دارد، اصلاً نیازی به Certbot ندارید: Traefik خودش گواهیهای wildcard را از طریق DNS-01 درخواست میکند و از همان نوع توکنِ provider استفاده میکند.
مواردی که wildcard واقعاً ارزش استفاده دارد: زیردامنه های مربوط به هر مشتری یا هر اپلیکیشن که سریعتر از زمان مورد نظر شما برای صدور مجدد گواهیها، ایجاد میشوند؛ و میزبانهای داخلی که پورت 80 عمومی ندارند، مانند سرویسهایی که فقط از طریق یک WireGuard VPN قابل دسترسی هستند. روش DNS-01 هرگز به میزبان مورد گواهیگذاری متصل نمیشود، بنابراین حتی یک ماشین کاملاً خصوصی میتواند یک گواهی با اعتماد عمومی داشته باشد.
FAQ
آیا Certbot میتواند با استفاده از HTTP-01 یک گواهی wildcard صادر کند؟
خیر. روش HTTP-01 مالکیت یک hostname خاص را اثبات میکند، زیرا سرور اعتبارسنجی یک فایل token را از همان نام دریافت میکند. یک wildcard تمام نامهای زیرمجموعه دامنه را پوشش میدهد، بنابراین Let's Encrypt برای آن به چالش DNS-01 نیاز دارد. همچنین authenticators مدل --nginx، --apache، --webroot و --standalone همگی مبتنی بر HTTP هستند. تنها راه استفاده از یک رکورد TXT در _acme-challenge.example.com است که باید به صورت دستی یا توسط یک DNS plugin قرار گیرد.
آیا یک گواهی 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 کاملاً جدید نیاز دارد و timer خودکار راهی برای درج آن ندارد، بنابراین تمدید با خطای An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively متوقف میشود. گواهی را با یک DNS plugin مانند certbot-dns-cloudflare مجدداً صادر کنید، یا از اسکریپتهای --manual-auth-hook و --manual-cleanup-hook که رکورد را از طریق API ارائهدهنده شما ویرایش میکنند، استفاده کنید.
چقدر زمان میبرد تا رکورد TXT مربوط به _acme-challenge ظاهر شود؟
این زمان به DNS provider شما بستگی دارد و میتواند از چند ثانیه تا چندین دقیقه متغیر باشد. فرآیند اعتبارسنجی، authoritative servers منطقه شما را میخواند؛ بنابراین با استفاده از dig +short TXT _acme-challenge.example.com @1.1.1.1 بررسی کنید و قبل از ادامه اجرای دستی، منتظر بمانید تا مقدار مورد نظر ظاهر شود. اگر در هنگام اعتبارسنجی با خطای عدم یافت شدن رکورد مواجه شدید، با استفاده از یک plugin، زمان انتظار داخلی را از طریق گزینه propagation افزایش دهید، مانند --dns-cloudflare-propagation-seconds 60.
آیا امنیت گواهی wildcard کمتر از یک گواهی معمولی است؟
رمزنگاری (cryptography) کاملاً یکسان است. تفاوتها عملیاتی هستند: یک کلید خصوصی (private key) تمام زیردامنهها را پوشش میدهد، بنابراین در صورت لو رفتن، دامنه آسیب بیشتری میبیند. همچنین، اعتبارنامههای DNS API که اتوماسیون به آنها نیاز دارد، خود یک رمز حساس هستند که روی سرور ذخیره میشوند. اگر فقط از چند زیردامنه مشخص استفاده میکنید، یک گواهی SAN از هر دو مشکل جلوگیری میکند؛ دقیقاً به همین دلیل است که این راهنما استفاده از wildcard را توصیه نمیکند.