امنیت وب

نصب گواهی SSL رایگان با Certbot — فعال‌سازی HTTPS در ۱۰ دقیقه

نصب SSL رایگان با Certbot و فعال‌سازی HTTPS روی سرور لینوکس با گواهی Let's Encrypt

نصب SSL رایگان امروز نه پول می‌خواهد، نه تماس با پشتیبانی و نه دانش عمیق رمزنگاری؛ با Certbot و Let's Encrypt در حدود ۱۰ دقیقه برای دامنه‌ی خود گواهی SSL معتبر می‌گیرید، قفل کنار نوار آدرس روشن می‌شود و تمدیدش هم برای همیشه به یک تایمر خودکار سپرده می‌شود. در این راهنما کل مسیر را قدم‌به‌قدم می‌رویم: نصب Certbot روی اوبونتو، دبیان و آلمالینوکس، صدور گواهی با پلاگین Nginx، روش webroot و wildcard، آزمون تمدید خودکار، ری‌دایرکت ۳۰۱ و جدول خطاهایی که معمولاً کار را نیمه‌تمام می‌گذارند.

SSL/TLS دقیقاً چه کاری انجام می‌دهد؟

وقتی سایت روی HTTPS است، بین مرورگر بازدیدکننده و سرور شما یک کانال رمزنگاری‌شده با پروتکل TLS برقرار می‌شود — SSL نام نسل قدیمی همین پروتکل است که هنوز سر زبان‌ها مانده و اصطلاح «گواهی SSL» هم از همان‌جا آمده. این کانال هم‌زمان سه ضمانت می‌دهد: محرمانگی (هیچ‌کس در مسیر — نه اپراتور، نه وای‌فای کافه — محتوای ردوبدل‌شده را نمی‌خواند)، یکپارچگی (کسی نمی‌تواند وسط راه به صفحه‌ی شما اسکریپت یا تبلیغ تزریق کند) و احراز هویت (بازدیدکننده مطمئن است واقعاً با سرور شما حرف می‌زند، نه با یک واسطه‌ی جعلی).

اما ماجرا فقط امنیت نیست؛ فعال کردن HTTPS سه پیامد عملی و قابل‌اندازه‌گیری هم دارد:

  • اعتماد کاربر. مرورگرها صفحه‌های HTTP را با برچسب «Not Secure» نشان می‌دهند و روی فرم رمز عبورِ بدون HTTPS صریحاً هشدار می‌گذارند. برای فروشگاه یا هر سایتی که فرم ورود دارد، این هشدار یعنی خداحافظی با بخشی از بازدیدکننده‌ها پیش از اولین کلیک.
  • سیگنال رتبه‌بندی. گوگل از سال ۲۰۱۴ رسماً HTTPS را جزو سیگنال‌های رتبه‌بندی اعلام کرده است؛ وزنش بزرگ نیست، ولی بین دو نتیجه‌ی هم‌سطح به نفع نسخه‌ی امن تمام می‌شود.
  • HTTP/2 و قابلیت‌های مدرن. مرورگرها HTTP/2 را فقط روی اتصال TLS پیاده کرده‌اند؛ سایت HTTP عملاً از multiplexing و فشرده‌سازی هدر محروم می‌ماند. سرویس‌ورکر، PWA، اعلان وب و خیلی از APIهای دیگر هم فقط در بستر امن (secure context) کار می‌کنند.

چرا Let's Encrypt رایگان است — و چرا می‌شود به آن اعتماد کرد

Let's Encrypt یک مرجع صدور گواهی (CA) غیرانتفاعی است که از سال ۲۰۱۵ با پشتیبانی مالی سازمان‌هایی مثل موزیلا، سیسکو، کروم و بنیاد EFF کار می‌کند و امروز از نظر تعداد گواهی فعال، بزرگ‌ترین CA دنیاست. ریشه‌ی آن (ISRG Root X1) در همه‌ی مرورگرها و سیستم‌عامل‌های مطرح به‌صورت پیش‌فرض معتبر است؛ یعنی گواهی SSL آن از نظر رمزنگاری و اعتبار مرورگر هیچ فرقی با گواهی پولی ندارد و بازدیدکننده هم هیچ تفاوتی نمی‌بیند.

رایگان‌بودنش هم ترفند بازاریابی نیست؛ نتیجه‌ی حذف کامل نیروی انسانی از فرایند صدور است. همه‌چیز با پروتکل استاندارد ACME (مصوب RFC 8555) خودکار شده: کلاینت ACME — که محبوب‌ترینش همین Certbot ساخته‌ی EFF است — به‌جای شما به CA ثابت می‌کند که کنترل دامنه در دست شماست، از یکی از این دو راه:

  • چالش HTTP-01: کلاینت فایل کوچکی در مسیر /.well-known/acme-challenge/ سایت می‌گذارد و سرورهای Let's Encrypt آن را از روی پورت ۸۰ می‌خوانند. اگر فایل سر جایش بود، مالکیت ثابت شده است.
  • چالش DNS-01: کلاینت از شما می‌خواهد یک رکورد TXT با نام _acme-challenge بسازید؛ این تنها راه معتبر برای گواهی wildcard است.

و اما عمر ۹۰ روزه‌ی گواهی‌ها، برخلاف تصور اول، نقطه‌ضعف نیست؛ عمداً کوتاه انتخاب شده تا اگر کلید خصوصی سروری لو رفت، پنجره‌ی سوءاستفاده کوچک بماند و — مهم‌تر — همه به تمدید خودکار عادت کنند. وقتی تمدید را یک تایمر انجام می‌دهد، ۹۰ روز و ۹۰۰ روز هیچ فرقی با هم ندارند.

نصب Certbot روی سرور

فرض این راهنما یک سرور لینوکسی با دسترسی root و وب‌سرور Nginx است. اگر هنوز وب‌سرورتان بالا نیامده، اول راه‌اندازی وب‌سایت روی اوبونتو با Nginx را انجام دهید و برگردید؛ پلاگین Certbot دقیقاً روی همان کانفیگ سوار می‌شود.

اوبونتو و دبیان — روش رسمی: snap

تیم Certbot نسخه‌ی snap را روش پیشنهادی نصب اعلام کرده، چون همیشه آخرین نسخه را می‌گیرید و تمدید خودکار هم از همان اول درست تنظیم می‌شود:

sudo apt update
sudo apt install snapd -y
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
certbot --version

اگر قبلاً نسخه‌ی مخزن را نصب کرده‌اید، اول با sudo apt remove certbot حذفش کنید تا دو نسخه با هم تداخل نکنند.

نمودار مراحل صدور گواهی SSL رایگان از Let's Encrypt با چالش HTTP-01 پروتکل ACME روی پورت 80 بین سرور و مرجع صدور گواهی

مسیر جایگزین: apt

روی سرورهایی که snapd ندارند یا نمی‌خواهید اضافه‌اش کنید، بسته‌ی مخزن هم کاملاً کار می‌کند — فقط معمولاً چند نسخه عقب‌تر است:

sudo apt update
sudo apt install certbot python3-certbot-nginx -y

آلمالینوکس و راکی — dnf و مخزن EPEL

در خانواده‌ی RHEL بسته‌ی Certbot داخل مخزن EPEL است، پس اول آن را فعال کنید:

sudo dnf install epel-release -y
sudo dnf install certbot python3-certbot-nginx -y

صدور گواهی SSL با پلاگین Nginx

قبل از اجرای فرمان، دو پیش‌نیاز را چک کنید. اول این‌که رکورد A دامنه (و اگر www هم می‌خواهید، رکورد www) به IP همین سرور اشاره کند — با dig +short example.com مطمئن شوید؛ اگر با رکوردها راحت نیستید، آموزش رکوردهای DNS به زبان ساده را ببینید. دوم این‌که در کانفیگ Nginx یک بلاک server با server_name درست وجود داشته باشد، چون پلاگین از روی همین نام، بلاک مناسب را پیدا و ویرایش می‌کند.

sudo certbot --nginx -d example.com -d www.example.com

در اولین اجرا یک آدرس ایمیل برای حساب ACME می‌پرسد (برای بازیابی حساب و اطلاع‌رسانی‌های مهم) و تأیید توافق‌نامه را می‌خواهد؛ بعد چالش HTTP-01 را خودش پاس می‌کند و چند ثانیه بعد چیزی شبیه این می‌بینید:

Requesting a certificate for example.com and www.example.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2026-11-04.

Deploying certificate
Successfully deployed certificate for example.com to /etc/nginx/sites-enabled/example.com
Congratulations! You have successfully enabled HTTPS on https://example.com

پلاگین بعد از گرفتن گواهی، بلاک server شما را ویرایش می‌کند: گوش‌دادن روی پورت ۴۴۳ را اضافه می‌کند، مسیر گواهی و کلید خصوصی را می‌نشاند و تنظیمات امن TLS را include می‌کند — همه با کامنت «managed by Certbot»، تا همیشه معلوم باشد کدام خط‌ها دست او بوده:

server {
    server_name example.com www.example.com;
    root /var/www/example.com;

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
💡 نکته: هر صدور موفق در سهمیه‌ی Let's Encrypt حساب می‌شود — برای مجموعه‌ی دامنه‌ی یکسان فقط ۵ گواهی در هفته. اگر می‌خواهید مسیر را آزمایش کنید یا با اسکریپت ور می‌روید، سوییچ --dry-run را اضافه کنید تا درخواست به سرور آزمایشی برود و سهمیه‌ی واقعی نسوزد.

روش webroot — وقتی نمی‌خواهید سرویس بایستد یا کانفیگ دست بخورد

روش standalone که در آموزش‌های قدیمی زیاد دیده می‌شود، خودش روی پورت ۸۰ گوش می‌دهد و مجبورید وب‌سرور را موقتاً خاموش کنید؛ روی سایت زنده منطقی نیست. روش webroot همان چالش HTTP-01 را از طریق وب‌سرورِ درحال‌کار پاس می‌کند: Certbot فایل چالش را داخل روت سایت می‌گذارد و Let's Encrypt آن را مثل هر فایل استاتیک دیگری می‌خواند — بدون یک ثانیه قطعی و بدون دست‌زدن به هیچ کانفیگی:

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

certonly یعنی «فقط گواهی را بگیر و به کانفیگ کاری نداشته باش»؛ در این حالت دو خط ssl_certificate و ssl_certificate_key را خودتان به بلاک server اضافه می‌کنید و با nginx -t && systemctl reload nginx اعمالش می‌کنید. مسیر webroot در پرونده‌ی تمدید ذخیره می‌شود، پس تمدیدهای بعدی هم به همین شکل خودکار و بی‌قطعی انجام می‌شوند.

گواهی wildcard: فقط با چالش DNS-01

اگر ساب‌دامنه‌های زیاد یا نامشخصی دارید، گواهی wildcard مثل *.example.com همه را یک‌جا پوشش می‌دهد؛ ولی Let's Encrypt برای آن فقط چالش DNS-01 را می‌پذیرد، چون کنترل کل DNS دامنه باید ثابت شود:

sudo certbot certonly --manual --preferred-challenges dns \
     -d example.com -d "*.example.com"

Certbot یک مقدار متنی نشان می‌دهد که باید به‌عنوان رکورد TXT با نام _acme-challenge در پنل DNS ثبت کنید. قبل از زدن Enter مطمئن شوید رکورد منتشر شده است:

dig TXT _acme-challenge.example.com +short
# should print the exact value certbot asked for

نکته‌ی مهم برای کاربران ایرانی: اگر DNS دامنه روی سرویسی باشد که پلاگین API برای Certbot دارد (مثل certbot-dns-cloudflare)، ساخت رکورد و تمدید هر دو خودکار می‌شوند. اما بیشتر پنل‌های DNS ایرانی API و پلاگینی ندارند و همین روش دستی (--manual) تنها راه می‌ماند — که تمدید خودکار هم ندارد و هر دوره باید تکرارش کنید. جمع‌بندی عملی: تا مجبور نشده‌اید wildcard نگیرید؛ برای چند ساب‌دامنه‌ی مشخص، همه را با چند -d در یک گواهی عادی بگیرید — یک گواهی تا ۱۰۰ نام جا دارد.

تمدید خودکار SSL — گواهی ۹۰ روزه‌ای که هیچ‌وقت منقضی نمی‌شود

Certbot هنگام نصب یک تایمر systemd می‌سازد که روزی دو بار اجرا می‌شود و هر گواهی‌ای را که کمتر از ۳۰ روز اعتبار دارد تمدید می‌کند. اول مطمئن شوید تایمر فعال است:

systemctl list-timers | grep -i certbot
# snap.certbot.renew.timer   -> snap install
# certbot.timer              -> apt / dnf install

بعد همین امروز — نه ۸۹ روز دیگر — کل مسیر تمدید را شبیه‌سازی کنید:

sudo certbot certificates      # list certs and expiry dates
sudo certbot renew --dry-run
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

اگر گواهی را با پلاگین nginx گرفته‌اید، Certbot بعد از هر تمدید خودش Nginx را reload می‌کند تا گواهی تازه سرو شود. اگر با certonly و webroot رفته‌اید، این کار را به یک هوک بسپارید:

printf '#!/bin/bash\nsystemctl reload nginx\n' \
  | sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

و برای اطمینان از بیرون، تاریخ انقضای گواهیِ درحال‌سرویس را مستقیم از خود سرور بپرسید:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
     | openssl x509 -noout -dates
# notBefore=Aug  6 07:15:22 2026 GMT
# notAfter=Nov  4 07:15:21 2026 GMT

curl -vI https://example.com 2>&1 | grep "expire date"
#  expire date: Nov  4 07:15:21 2026 GMT
💡 نکته: Let's Encrypt از سال ۲۰۲۵ دیگر ایمیل هشدار انقضا نمی‌فرستد. اگر تمدید خودکار بی‌صدا بشکند، اولین کسی که می‌فهمد بازدیدکننده‌ی سایت شماست؛ پس همین چک openssl را در مانیتورینگ دوره‌ای‌تان بگذارید تا مثلاً ۱۵ روز مانده به انقضا هشدار بگیرید.

ری‌دایرکت ۳۰۱ و آزمون نهایی

نسخه‌های جدید Certbot هنگام نصب گواهی با پلاگین nginx، ری‌دایرکت HTTP به HTTPS را هم به‌صورت پیش‌فرض فعال می‌کنند. اگر با webroot رفته‌اید یا می‌خواهید مطمئن شوید، بلاک پورت ۸۰ باید فقط یک کار انجام دهد:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

کد ۳۰۱ (دائمی) مهم است، نه ۳۰۲: به موتورهای جست‌وجو می‌گوید نسخه‌ی HTTPS آدرس اصلی است و اعتبار لینک‌های قدیمی به آن منتقل شود. بعد از تغییر، مثل همیشه nginx -t && systemctl reload nginx.

یک تله‌ی رایج بعد از مهاجرت، محتوای مختلط (mixed content) است: صفحه از HTTPS می‌آید ولی عکس‌ها و اسکریپت‌ها هنوز با آدرس http:// صدا زده می‌شوند و مرورگر یا قفل را برمی‌دارد یا آن منابع را بلاک می‌کند. در وردپرس باید آدرس سایت در تنظیمات و آدرس‌های ذخیره‌شده در دیتابیس هر دو به https اصلاح شوند — روش درستش را در راهنمای نصب و انتقال وردپرس روی سرور مجازی آورده‌ایم.

در پایان، دامنه را در آزمون رایگان SSL Labs وارد کنید؛ چند دقیقه صبر می‌خواهد ولی گزارش کاملی از زنجیره‌ی گواهی، پروتکل‌ها و نقاط ضعف می‌دهد. با کانفیگی که Certbot می‌سازد معمولاً بدون هیچ کار اضافه نمره‌ی A می‌گیرید.

⚠️ هدر HSTS (Strict-Transport-Security) به مرورگر می‌گوید تا ماه‌ها فقط با HTTPS سراغ دامنه‌ی شما بیاید — و مرورگر این قول را فراموش نمی‌کند. تا وقتی ری‌دایرکت، تمدید خودکار و همه‌ی ساب‌دامنه‌ها چند هفته بی‌مشکل کار نکرده‌اند، فعالش نکنید؛ اگر بعد از فعال‌کردن آن HTTPS بشکند، کاربران قبلی حتی نمی‌توانند موقتاً از نسخه‌ی HTTP استفاده کنند و سایت برایشان کاملاً بسته می‌شود.

خطاهای رایج گواهی SSL و راه‌حل سریع

اگر صدور گواهی شکست خورد یا بعد از نصب رفتار عجیبی دیدید، مشکل شما تقریباً همیشه یکی از این پنج مورد است:

نشانه / پیام خطاعلت واقعیراه‌حل
Timeout during connect یا Connection refused در چالش HTTP-01پورت ۸۰ در فایروال بسته استپورت‌های ۸۰ و ۴۴۳ را در ufw یا firewalld باز کنید (دستورها پایین‌تر)
no valid A records found یا NXDOMAINدامنه هنوز به IP سرور اشاره نمی‌کند یا انتشار DNS کامل نشدهرکورد A را بسازید، با dig +short چک کنید و به انتشار فرصت بدهید
too many certificates already issuedسقف ۵ گواهی در هفته برای مجموعه‌ی دامنه‌ی یکسان پر شدهچند روز صبر کنید؛ برای تست همیشه --dry-run بزنید
CAA record prevents issuanceرکورد CAA دامنه اجازه‌ی صدور به Let's Encrypt نمی‌دهدرکورد CAA را با مقدار 0 issue "letsencrypt.org" اصلاح کنید
خطای «too many redirects» بعد از نصب گواهیسایت پشت کلادفلر است و حالت SSL روی Flexible ماندهحالت رمزنگاری کلادفلر را روی Full (strict) بگذارید

شایع‌ترینِ همه، پورت بسته است. چالش HTTP-01 حتماً باید از اینترنت به پورت ۸۰ سرور شما برسد؛ اگر طبق چک‌لیست امنیت سرور لینوکس فایروال را سفت‌وسخت بسته‌اید، این دو سرویس باید استثنا باشند:

sudo ufw allow 'Nginx Full'                        # Ubuntu / Debian
sudo firewall-cmd --permanent --add-service=http   # AlmaLinux / Rocky
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

مورد CAA هم یک چک یک‌خطی دارد؛ اگر خروجی خالی بود مشکلی نیست و اگر رکوردی بود، باید letsencrypt.org در آن مجاز باشد:

dig CAA example.com +short
# 0 issue "letsencrypt.org"

و اما کلادفلر، که بخش بزرگی از سایت‌های ایرانی پشت آن نشسته‌اند: در حالت Flexible، کلادفلر با بازدیدکننده HTTPS حرف می‌زند ولی با سرور شما HTTP؛ حالا که ری‌دایرکت ۳۰۱ گذاشته‌اید، سرورتان همان درخواست HTTP را دوباره به HTTPS می‌فرستد و یک حلقه‌ی بی‌پایان ساخته می‌شود — همان «too many redirects» معروف. راه‌حل درست، حذف ری‌دایرکت نیست: حالا که با Certbot گواهی معتبر روی سرور اصلی دارید، حالت را روی Full (strict) بگذارید تا مسیر کاربر تا سرور سرتاسر رمزنگاری‌شده و معتبر باشد. ناهماهنگی SSL بین کلادفلر و سرور اصلی معمولاً خودش را به شکل خطاهای خانواده‌ی 52x (مثل 521 و 526) نشان می‌دهد که تفکیک کاملشان در راهنمای رفع خطای 502 آمده است.

سؤالات پرتکرار

آیا گواهی SSL رایگان Let's Encrypt از گواهی پولی ضعیف‌تر است؟

نه. سطح رمزنگاری، اعتبار در مرورگرها و ظاهر قفل دقیقاً یکسان است. گواهی‌های پولی در نوع اعتبارسنجی (سازمانی OV و EV)، بیمه‌ی صدور و پشتیبانی فرق دارند که برای اکثریت مطلق سایت‌ها هیچ ارزش عملی اضافه‌ای ندارد؛ به همین دلیل بخش بزرگی از وب امروز روی همین گواهی‌های رایگان می‌چرخد.

چرا گواهی Let's Encrypt فقط ۹۰ روزه است؟

عمداً؛ عمر کوتاه یعنی اگر کلید خصوصی لو برود، مهاجم مدت کمی فرصت سوءاستفاده دارد، و یعنی همه مجبور می‌شوند تمدید را خودکار کنند. با تایمر systemd که Certbot می‌سازد، تمدید حدود ۳۰ روز مانده به انقضا خودش انجام می‌شود و شما عملاً هیچ‌وقت متوجه آن نمی‌شوید.

از کجا مطمئن شوم تمدید خودکار SSL واقعاً کار می‌کند؟

سه چک: systemctl list-timers نشان بدهد تایمر certbot فعال است؛ sudo certbot renew --dry-run بدون خطا تمام شود؛ و تاریخ انقضای واقعی را با openssl s_client یا curl -vI ببینید. چون Let's Encrypt دیگر ایمیل هشدار انقضا نمی‌فرستد، این چک آخر را در مانیتورینگ دوره‌ای بگذارید.

برای چند دامنه و ساب‌دامنه چند گواهی لازم دارم؟

معمولاً فقط یکی: هر گواهی می‌تواند تا ۱۰۰ نام داشته باشد، کافی است همه را با -d پشت سر هم بدهید. اگر تعداد ساب‌دامنه‌ها نامشخص یا متغیر است، گواهی wildcard بگیرید که چالش DNS-01 می‌خواهد؛ برای دامنه‌های کاملاً جدا هم گواهی‌های مستقل تمیزتر است.

قدم بعدی

مسیر کامل همین بود: Certbot را نصب کنید، با پلاگین nginx گواهی بگیرید، همان روز اول renew --dry-run را تست کنید و در آخر نمره‌تان را از SSL Labs بگیرید. اگر می‌خواهید قبل از دست‌زدن به سایت اصلی یک بار کامل و بی‌استرس تمرین کنید، یک سرور ابری ساعتی در مهران هاست بسازید — تحویلش حدود ۶۰ ثانیه است — یک ساب‌دامنه‌ی آزمایشی به آن بدهید، کل مسیر از نصب تا خراب‌کردن و درست‌کردنِ دوباره را بروید و فقط هزینه‌ی همان یکی‌دو ساعت تمرین را بپردازید.

آموزش‌های مرتبط

آماده‌ی تمرین عملی هستید؟

سرور ابری ساعتی مهران هاست در ۶۰ ثانیه تحویل می‌شود — تمرین کنید و فقط بابت همان ساعت‌ها پرداخت کنید. هزینه را پیش از ثبت‌نام با محاسبه‌گر برآورد کنید.