بله، Let's Encrypt برای دامنه‌ی .ir دقیقاً مثل هر دامنه‌ی دیگری گواهی SSL رایگان صادر می‌کند. شرطش هم مثل بقیه است: دامنه باید به سرور شما اشاره کند و سرورهای Let's Encrypt بتوانند از روی اینترنت ثابت کنند دامنه در اختیار شماست. روی سرور اوبونتو با nginx کل کار در دو فرمان خلاصه می‌شود: sudo apt install certbot python3-certbot-nginx و sudo certbot --nginx -d example.ir -d www.example.ir.

گواهی‌های Let's Encrypt فعلاً ۹۰ روز اعتبار دارند و این مؤسسه برنامه‌ی کوتاه‌تر کردن این مدت را هم اعلام کرده؛ پس مهم‌تر از گرفتن گواهی، تمدید خودکار آن است. در ادامه همین‌ها را قدم‌به‌قدم می‌بینیم، به‌علاوه‌ی فرق چالش HTTP-01 و DNS-01، گواهی wildcard و خطاهایی که بیشتر از همه پیش می‌آید.

پیش از شروع: سه پیش‌نیاز

  1. DNS به سرور اشاره کند. رکورد A (و اگر IPv6 دارید، AAAA) برای example.ir و www.example.ir باید روی IP همین سرور باشد. با dig example.ir +short و dig www.example.ir +short مطمئن شوید. اگر با رکوردها آشنا نیستید، رکوردهای DNS به زبان ساده را ببینید.
  2. پورت 80 و 443 باز باشد. چالش HTTP-01 فقط از پورت 80 انجام می‌شود، حتی اگر سایت قرار است فقط روی HTTPS کار کند. با ufw:
bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status
  1. وب‌سرور برای دامنه پیکربندی شده باشد. پلاگین nginx یا apache دنبال بلوکی می‌گردد که server_name (یا ServerName) آن با دامنه‌ی درخواستی یکی باشد و گواهی را همان‌جا نصب می‌کند.

اگر سرور تازه است، کارهای پایه مثل فایروال و کاربر غیر root در ساعت اول یک سرور لینوکس آمده است.

نصب certbot روی اوبونتو ۲۴.۰۴

certbot ابزار رسمی پیشنهادی Let's Encrypt است. نسخه‌ی مخزن اوبونتو برای بیشتر کاربردها کافی است:

bash
sudo apt update
# برای nginx
sudo apt install certbot python3-certbot-nginx
# یا برای apache
sudo apt install certbot python3-certbot-apache

گرفتن گواهی با پلاگین nginx

bash
sudo certbot --nginx -d example.ir -d www.example.ir

بار اول یک ایمیل و پذیرش شرایط استفاده را می‌پرسد. بعد چالش را انجام می‌دهد، گواهی را می‌گیرد، مسیرش را در پیکربندی nginx می‌نویسد و nginx را reload می‌کند. برای این‌که رفتار درباره‌ی هدایت درخواست‌های HTTP به HTTPS صریح باشد، می‌توانید --redirect یا --no-redirect را هم به فرمان اضافه کنید؛ برای بیشتر سایت‌ها هدایت به HTTPS انتخاب درست است.

هر نامی که می‌خواهید گواهی پوشش دهد باید با یک -d جدا بیاید. گواهی‌ای که فقط برای example.ir گرفته شده، www.example.ir را پوشش نمی‌دهد و مرورگر روی آن خطا می‌دهد.

با apache

bash
sudo certbot --apache -d example.ir -d www.example.ir

رفتارش همان است: VirtualHost مربوط را پیدا می‌کند، نسخه‌ی SSL آن را می‌سازد و apache را reload می‌کند.

فقط گرفتن گواهی، بدون دست‌زدن به پیکربندی

اگر ترجیح می‌دهید certbot به فایل‌های وب‌سرور دست نزند، از certonly با روش webroot استفاده کنید. certbot فایل چالش را در پوشه‌ی سایت می‌گذارد و شما خودتان گواهی را در پیکربندی معرفی می‌کنید:

bash
sudo certbot certonly --webroot -w /var/www/example.ir -d example.ir -d www.example.ir

گواهی‌ها در هر حالت در /etc/letsencrypt/live/example.ir/ قرار می‌گیرند: fullchain.pem گواهی همراه با زنجیره و privkey.pem کلید خصوصی است. این پوشه را کپی نکنید؛ همیشه به همین مسیر ارجاع بدهید، چون بعد از تمدید فایل‌ها همین‌جا به‌روز می‌شوند.

HTTP-01 یا DNS-01؟

Let's Encrypt برای اثبات مالکیت از شما یک «چالش» می‌خواهد. دو چالش اصلی این‌هاست:

HTTP-01 DNS-01
روش فایلی در /.well-known/acme-challenge/ روی پورت 80 رکورد TXT روی _acme-challenge.example.ir
نیاز به پورت 80 باز دارد ندارد
گواهی wildcard (*.example.ir) ممکن نیست تنها راه
تمدید خودکار ساده نیاز به API سرویس DNS
مناسب برای بیشتر سایت‌ها wildcard، سرورهای داخلی، وقتی پورت 80 در دسترس نیست

پلاگین‌های nginx و apache و روش webroot همه از HTTP-01 استفاده می‌کنند. اگر گواهی wildcard لازم دارید، یا سروری دارید که از اینترنت روی پورت 80 در دسترس نیست، سراغ DNS-01 بروید.

DNS-01 دستی

bash
sudo certbot certonly --manual --preferred-challenges dns \
  -d 'example.ir' -d '*.example.ir'

certbot یک مقدار به شما نشان می‌دهد و صبر می‌کند تا آن را به‌عنوان رکورد TXT روی _acme-challenge.example.ir بسازید. قبل از Enter زدن با dig مطمئن شوید رکورد دیده می‌شود:

bash
dig _acme-challenge.example.ir TXT +short

ایراد روش دستی این است که خودکار تمدید نمی‌شود؛ هر ۹۰ روز باید همین کار را تکرار کنید. برای DNS-01 خودکار، certbot برای سرویس‌دهنده‌های رایج DNS پلاگین دارد (مثلاً python3-certbot-dns-cloudflare) که با توکن API رکورد را خودش می‌سازد و پاک می‌کند. اگر سرویس DNS شما API ندارد، wildcard را فقط وقتی بگیرید که واقعاً لازمش دارید؛ بیشتر سایت‌ها با چند نام مشخص کارشان راه می‌افتد.

تمدید خودکار

بسته‌ی certbot در اوبونتو یک systemd timer نصب می‌کند که روزی دو بار گواهی‌ها را بررسی می‌کند و هر کدام که کمتر از ۳۰ روز به انقضایش مانده باشد را تمدید می‌کند. وجودش را بررسی کنید:

bash
systemctl list-timers | grep certbot
systemctl status certbot.timer

بعد یک تمدید آزمایشی بزنید. این فرمان از سرور آزمایشی Let's Encrypt استفاده می‌کند و گواهی واقعی را عوض نمی‌کند:

bash
sudo certbot renew --dry-run

اگر این فرمان بدون خطا تمام شد، تمدید واقعی هم کار می‌کند. هر بار که پیکربندی وب‌سرور، فایروال یا DNS را تغییر دادید، دوباره اجرایش کنید.

با پلاگین nginx یا apache، وب‌سرور بعد از تمدید خودبه‌خود reload می‌شود. در حالت certonly، اسکریپتی که بعد از هر تمدید موفق باید اجرا شود را در /etc/letsencrypt/renewal-hooks/deploy/ بگذارید و اجرایی‌اش کنید.

فهرست گواهی‌ها و تاریخ انقضایشان:

bash
sudo certbot certificates

خطاهای رایج و راه‌حلشان

پورت 80 بسته است

پیام‌هایی مثل Timeout during connect یا Connection refused معمولاً یعنی سرورهای Let's Encrypt به پورت 80 شما نرسیده‌اند. فایروال سرور، فایروال پنل دیتاسنتر (که جدا از ufw است) و این‌که وب‌سرور واقعاً روی پورت 80 گوش می‌دهد را بررسی کنید:

bash
sudo ss -tlnp | grep ':80 '

Let's Encrypt چالش را از چند نقطه‌ی مختلف در اینترنت بررسی می‌کند، پس سرور باید از بیرون از شبکه‌ی خودش هم در دسترس باشد؛ این‌که خودتان از داخل همان شبکه سایت را باز می‌کنید کافی نیست.

DNS هنوز به سرور اشاره نمی‌کند

اگر تازه رکورد A را ساخته یا عوض کرده‌اید، ممکن است جواب قدیمی هنوز در کش resolverها باشد. پیام خطا معمولاً IPی را نشان می‌دهد که Let's Encrypt به آن رسیده؛ اگر IP سرور قبلی است، تا پایان TTL صبر کنید. یک AAAA قدیمی هم دلیل رایجی است: Let's Encrypt اگر AAAA ببیند، IPv6 را ترجیح می‌دهد.

محدودیت نرخ (rate limit)

Let's Encrypt برای جلوگیری از سوءاستفاده محدودیت دارد. دو موردی که بیشتر به آن برمی‌خوریم: تعداد محدود گواهی تکراری (دقیقاً همان مجموعه‌ی نام‌ها) در هفته، و تعداد محدود تلاش ناموفق در ساعت. اعداد دقیق در صفحه‌ی Rate Limits مستندات Let's Encrypt آمده است.

راه پیشگیری ساده است: تا وقتی پیکربندی را تست می‌کنید از سرور staging استفاده کنید. گواهی‌اش در مرورگر معتبر نیست، اما محدودیت‌هایش بسیار بالاتر است:

bash
sudo certbot --nginx --test-cert -d example.ir -d www.example.ir

وقتی همه‌چیز درست کار کرد، همان فرمان را بدون --test-cert اجرا کنید.

رکورد CAA

اگر دامنه رکورد CAA دارد و letsencrypt.org در آن نیست، صدور گواهی رد می‌شود. یا رکورد را اضافه کنید یا CAA را بردارید.

بررسی تاریخ انقضا با openssl

certbot certificates چیزی را نشان می‌دهد که روی دیسک است؛ openssl نشان می‌دهد سایت واقعاً چه گواهی‌ای به بازدیدکننده تحویل می‌دهد. این دو همیشه یکی نیستند، مثلاً وقتی تمدید انجام شده ولی وب‌سرور reload نشده:

bash
echo | openssl s_client -connect example.ir:443 -servername example.ir 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

notAfter تاریخ انقضاست. برای یک بررسی ساده در اسکریپت یا cron، گزینه‌ی -checkend اگر گواهی تا n ثانیه‌ی دیگر منقضی شود کد خروج غیر صفر برمی‌گرداند:

bash
echo | openssl s_client -connect example.ir:443 -servername example.ir 2>/dev/null \
  | openssl x509 -noout -checkend 1209600 \
  || echo "certificate for example.ir expires within 14 days"

Let's Encrypt از سال ۲۰۲۵ ایمیل یادآوری انقضا نمی‌فرستد، پس اگر پایشی ندارید، همین چند خط در cron ارزش اضافه‌کردن دارد. برای زمان‌بندی، cron در لینوکس را ببینید.

جمع‌بندی

گواهی SSL رایگان برای دامنه‌ی ir فرقی با هر دامنه‌ی دیگری ندارد: DNS را به سرور اشاره دهید، پورت 80 را باز کنید و certbot --nginx یا certbot --apache را با همه‌ی نام‌ها اجرا کنید. برای wildcard سراغ DNS-01 بروید و اگر می‌شود، با پلاگین API سرویس DNS خودکارش کنید. بعد از نصب، certbot renew --dry-run را اجرا کنید، مطمئن شوید timer فعال است و یک بررسی ساده‌ی انقضا با openssl کنار بگذارید. تا وقتی در حال تست هستید، --test-cert شما را از محدودیت نرخ دور نگه می‌دارد.