نحوه فعال کردن https  و مدیریت سرتیفیکیت دامنه با nginx

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

بیشتر آموزش‌های فعال‌سازی HTTPS روی Nginx به شما می‌گویند دستور certbot --nginx -d example.com را اجرا کنید و تمام! این روش کار می‌کند اما اولین باری که چیزی خراب شود، گم می‌شوید؛ چون هیچ‌وقت نفهمیده‌اید آن دستور در واقع چه کاری انجام داده است.

این مقاله مسیر متفاوتی را طی می‌کند. ابتدا می‌فهمیم پشت صحنه چه می‌گذرد، بعد با دستورهای خام Certbot (بدون افزونه Nginx) گواهی می‌گیریم و آن را خودمان به کانفیگ Nginx وصل می‌کنیم. فقط بعد از این مراحل، سراغ آن یک دستور جادویی می‌رویم که همه کارها را خودکار می‌کند و در آن لحظه دقیقاً می‌دانید چه کاری برایتان انجام می‌دهد.

پیش‌نیازها: یک سرور اوبونتو (۲۰.۰۴ / ۲۲.۰۴ / ۲۴.۰۴)، Nginx نصب‌شده، دسترسی sudo و دامنه‌ای که DNS آن به سرور شما اشاره کند. در سراسر مقاله از example.com به‌عنوان جایگزین دامنه استفاده می‌کنیم آن را با دامنه خودتان عوض کنید.


بخش ۱ پشت صحنه چه می‌گذرد؟

مشکلی که HTTPS حل می‌کند

ترافیک ساده HTTP به‌صورت متن باز (Plaintext) منتقل می‌شود و هر کسی در مسیر شبکه می‌تواند آن را بخواند. HTTPS ترافیک HTTP را داخل رمزنگاری TLS می‌پیچد و TLS به سرور شما نیاز دارد که یک گواهی (Certificate) ارائه دهد: فایلی شامل کلید عمومی سرور و نام دامنه شما که توسط یک مرجع صدور گواهی (Certificate Authority یا CA) امضا شده و مرورگرها به آن اعتماد دارند.

Let's Encrypt و پروتکل ACME

گواهی Let's Encrypt یک CA رایگان و غیرانتفاعی است. اما هیچ CA‌ای نمی‌تواند بی‌هیچ بررسی گواهی صادر کند باید مطمئن شود واقعاً کنترل دامنه دست شماست. این بررسی با پروتکل استاندارد ACME انجام می‌شود که رایج‌ترین روش آن چالش HTTP-01 است:

  1. شما برای example.com درخواست گواهی می‌دهید.
  2. گواهی Let's Encrypt پاسخ می‌دهد: «اثباتش کن. این توکن تصادفی را در آدرس http://example.com/.well-known/acme-challenge/<token> قرار بده.»
  3. گواهی Let's Encrypt آن آدرس را از اینترنت عمومی درخواست می‌کند. اگر توکن آنجا باشد، یعنی شما سروری را کنترل می‌کنید که دامنه به آن اشاره می‌کند. گواهی صادر می‌شود.

 

Certbot: کلاینتی که این گفت‌وگو را خودکار می‌کند

کلاینت Certbot یک کلاینت ACME است یعنی از طرف شما با Let's Encrypt صحبت می‌کند. افزونه‌های (Plugin) Certbot دو نقش مجزا دارند.

نقش افزونهوظیفهمثال‌ها
Authenticatorاثبات مالکیت دامنه (انجام چالش)standalone، webroot، nginx، manual، افزونه‌های DNS
Installerویرایش کانفیگ وب‌سرور برای استفاده از گواهیnginx، apache

دستور معروف certbot --nginx در واقع افزونه nginx است که هر دو نقش را هم‌زمان بازی می‌کند. در مسیر دستی ما، از standalone به‌عنوان Authenticator استفاده می‌کنیم و نقش Installer را خودتان بازی خواهید کرد.

سه حقیقتی که باید به خاطر بسپارید

  1. گواهی‌های Let's Encrypt فقط ۹۰ روز اعتبار دارند ← پس تمدید باید خودکار باشد.
  2. همه فایل‌های گواهی زیر مسیر /etc/letsencrypt/ قرار می‌گیرند.
  3. بعد از هر تمدید، Nginx باید reload شود تا فایل‌های جدید را بخواند.

بخش ۲ پیش‌نیازها (بررسی های قبل از شروع برای رفع ارور های احتمالی)

# 1. DNS باید به همین سرور اشاره کند.
dig +short example.com        # باید IP عمومی همین سرور را برگرداند

# 2. فایروال باید پورت 80 (برای چالش) و 443 (برای HTTPS) را باز کند
sudo ufw allow 'Nginx Full'
# درصورت فعال بودن ufw  این دسترسی باید داده شود

# 3. نصب Certbot از طریق snap (روش رسمی؛ دلیلش پایین بلوک آمده)
#    در مسیر دستی به افزونه nginx نیازی نداریم، ولی پکیج snap به هر حال همراهش است
sudo apt remove certbot   # فقط اگر قبلاً نسخه‌ی apt را نصب کرده بودید
sudo apt install -y snapd
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot   # تا certbot مستقیم از PATH اجرا شود

# 4. ببینید کدام افزونه‌ها را دارید (nginx هم از قبل همراه پکیج است؛ فعلاً کاری با آن نداریم)
certbot plugins
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* apache
* manual
* nginx
* null
* standalone
* webroot
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

چرا snap و نه apt؟

نسخه‌ای که در مخازن apt اوبونتو (۲۰.۰۴ به بعد) قرار دارد معمولاً چند فصل از Certbot رسمی عقب است و ممکن است با تغییرات پروتکل ACME یا کتابخانه‌های پایتونِ Let's Encrypt ناسازگار شود. پیشنهاد رسمی خود Certbot هم امروز نصب از طریق snap است؛ به همین دلیل در کل این مقاله از نسخه‌ی snap استفاده می‌کنیم. افزونه‌های nginx و apache هم از قبل داخل همین پکیج هستند و نصب جداگانه نمی‌خواهند.


بخش ۳ گرفتن گواهی با Certbot خام (بدون افزونه)

روش standalone

روش standalone یعنی Certbot موقتاً وب‌سرور کوچک خودش را روی پورت 80 بالا می‌آورد تا به چالش پاسخ دهد. هیچ کانفیگ Nginxای لازم ندارد اما پورت 80 باید آزاد باشد، پس Nginx برای حدود ده ثانیه متوقف می‌شود:

sudo systemctl stop nginx
sudo certbot certonly --standalone -d example.com
  • certonly — گواهی را بگیر اما هیچ‌جا نصبش نکن. این فلگ، قلب مسیر دستی ماست.
  • --standalone — از وب‌سرور موقت داخلی برای چالش استفاده کن.
  • -d — دامنه‌ای که گواهی برای آن صادر می‌شود. برای چند نام روی یک گواهی، آن را تکرار کنید.

در اولین اجرا، Certbot ایمیل (برای هشدارهای انقضا) و پذیرش قوانین را می‌خواهد. خروجی موفق چنین چیزی است:

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-13.

حالا نگاهی دقیق‌تر به آنچه اتفاق افتاده بیندازیم

sudo ls -l /etc/letsencrypt/live/example.com/
cert.pem  -> ../../archive/example.com/cert1.pem
chain.pem -> ../../archive/example.com/chain1.pem
fullchain.pem -> ../../archive/example.com/fullchain1.pem
privkey.pem -> ../../archive/example.com/privkey1.pem
فایلمحتواکاربرد
privkey.pemکلید خصوصی شما هرگز با کسی به اشتراک نگذاریدssl_certificate_key
cert.pemفقط گواهی شمابه‌ندرت مستقیم استفاده می‌شود
chain.pemگواهی‌های واسط CAبه‌ندرت مستقیم استفاده می‌شود
fullchain.pemگواهی شما + زنجیره، کنار همssl_certificate ← همین را می‌خواهید

همیشه به سیم‌لینک‌ها ارجاع بدهید، هرگز فایل‌ها را کپی نکنید

هر تمدید، فایل‌های تازه‌ای در archive/ می‌سازد و سیم‌لینک‌های live/ به آن‌ها اشاره میکنند. اگر کانفیگ Nginx شما به live/... اشاره کند، تمدیدها کار می‌کنند. اگر فایل‌ها را جای دیگری کپی کنید، سایتتان در روز تمدید دچار مشکل میشود.

داخل خود گواهی را ببینید:

sudo openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -subject -issuer -dates
subject=CN = example.com
issuer=C = US, O = Let's Encrypt, CN = R11
notBefore=Aug 15 10:00:00 2026 GMT
notAfter=Nov 13 10:00:00 2026 GMT     <- ۹۰ روز بعد از صدور

و ببینید Certbot چه چیزی را برایتان پیگیری می‌کند:

sudo certbot certificates                          # همه گواهی‌ها، دامنه‌ها و تاریخ انقضا
cat /etc/letsencrypt/renewal/example.com.conf      # تنظیمات تمدید، از جمله Authenticator استفاده‌شده

فایل کانفیگ تمدید (renewal conf) مهم است: Certbot به خاطر می‌سپارد که هر گواهی را چگونه گرفته‌اید و هنگام تمدید همان روش را تکرار می‌کند.


بخش ۴ وصل کردن گواهی به Nginx به صورت دستی

تمام تنظیمات ssl مورد نیاز برای nginx در دو بلاک server خلاصه می‌شود. فایل /etc/nginx/sites-available/example.com را بسازید:

# Port 80: redirect everything to HTTPS
server {
    listen 80;
    server_name example.com;

    location / {
        return 301 https://$host$request_uri;
    }
}

# Port 443: the real site
server {
    listen 443 ssl;
    server_name example.com;

    # --- the only two lines that make it "SSL" ---
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # --- برخی تنظیمات پیشنهادی برای ssl (توضیحات بیشتر https://ssl-config.mozilla.org) ---
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

همه ماجرا همین است یک بلاک server معمولی به‌اضافه listen 443 ssl و دو مسیر فایل.
برای بررسی:

curl -I http://example.com     # انتظار: HTTP/1.1 301 Moved Permanently -> https://
curl -I https://example.com    # انتظار: HTTP/2 200

سایت را در مرورگر باز کنید باید آیکون قفل را ببینید. برای ارزیابی کامل، تست رایگان SSL Labs را اجرا کنید؛ این کانفیگ نمره A می‌گیرد.


بخش ۵ تمدید: بخشی که آدم‌ها را غافل‌گیر می‌کند

گواهی‌های Let's Encrypt عمداً ۹۰ روزه‌اند; عمر کوتاه، شما را مجبور به خودکارسازی می‌کند. هنگام نصب Certbot، یک تایمر systemd ثبت شده که روزی دو بار اجرا می‌شود و هر گواهی‌ای که کمتر از ۳۰ روز به انقضایش مانده را تمدید می‌کند:

systemctl list-timers | grep certbot     # تایمر تمدید وجود دارد
sudo certbot renew --dry-run             # یک مرتبه فرایند تمدید رو شبیه سازی کنید

اگر dry run موفق بود، ۹۰ درصد راه را رفته‌اید. اما دو دام وجود دارد که مقالات مبتدی معمولاً از روی آن‌ها رد می‌شوند, و چون روش standalone را انتخاب کرده‌ایم، هر دو شامل حال ما می‌شود.

دام اول: Nginx بعد از تمدید خودش reload نمی‌شود

بعد از یک تمدید واقعی، فایل‌های جدید روی دیسک هستند، اما Nginx تا وقتی reload نشود، گواهی قدیمی را از حافظه سرو می‌کند. راه‌حل: یک Deploy Hook هر اسکریپت اجراشدنی در این پوشه، بعد از هر تمدید موفق به‌صورت خودکار اجرا می‌شود:

sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy

sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh > /dev/null <<'EOF'
#!/bin/bash
nginx -t && systemctl reload nginx
EOF

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

دام دوم: تمدید با standalone به پورت 80 آزاد نیاز دارد

کانفیگ تمدید را در بخش ۳ به خاطر دارید؟ تمدید، همان Authenticator اولیه را تکرار می‌کند. standalone باید پورت 80 را بگیرد اما حالا Nginx صاحبش است. بدون مداخله، تمدیدها شکست می‌خورند. راه‌حل: هوک‌های pre/post که هنگام تمدید برای چند ثانیه Nginx را متوقف و دوباره بالا می‌آورند:

sudo certbot renew --dry-run \
  --pre-hook "systemctl stop nginx" \
  --post-hook "systemctl start nginx"

هوک‌هایی که یک بار پاس داده شوند، در کانفیگ تمدید ذخیره می‌شوند؛ پس همین dry run آن‌ها را برای همیشه ثبت می‌کند. قطعی چندثانیه‌ای، دو بار در سال، در ساعات تصادفی برای بیشتر سایت‌ها قابل‌قبول است.

تمدید بدون حتی یک ثانیه قطعی می‌خواهید؟

از Authenticator به نام webroot استفاده کنید ضمیمه A را ببینید. این روش استاندارد production برای مسیر دستی است و برای کارهای جدی، انتخاب من هم همین است.


بخش ۶. انجام بدون دردسر همه چیز با یک دستور

حالا که همه‌کار را دستی انجام داده‌اید، با اتوماسیون آشنا شوید. چون certbot را از snap نصب کرده‌ایم، افزونه‌ی nginx از قبل همراهش است و چیزی برای نصب نداریم — فقط همان تک‌دستور معروف را اجرا کنید:

sudo certbot --nginx -d example.com

بعدش کانفیگ را باز کنید. می‌بینید دقیقاً همان کاری را کرده که شما کردید، با این تفاوت که هر تغییر با # managed by Certbot علامت خورده است. این خروجی واقعی از یک سرور production است:

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

    location / {
        try_files $uri $uri/ =404;
    }

    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
}

server {
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name example.com;
    return 404; # managed by Certbot
}

هدیه رایگان افزونه

افزونه دو فایل کارشناسی‌شده روی سیستم شما می‌گذارد: /etc/letsencrypt/options-ssl-nginx.conf (پروتکل‌های TLS مدرن، سایفرها، تنظیمات سشن، OCSP Stapling و HSTS) و /etc/letsencrypt/ssl-dhparams.pem (فایل پارامتر دیفی-هلمن). آن‌ها را باز کنید و بخوانید از بهترین منابع برای یادگیری تنظیمات TLS در production هستند و فایل اول را حتی می‌توانید در کانفیگ‌های دست‌نویس خودتان include کنید.

قاعده کلی: با certonly یاد بگیرید، با --nginx دیپلوی کنید. مسیر دستی وقتی ارزشمند می‌شود که افزونه نتواند کانفیگ شما را بفهمد, کانفیگ‌های بسیار سفارشی، ساختارهای غیراستاندارد، کانتینرها; و برای اینکه بفهمید دارید چه چیزی را خودکار می‌کنید.


ضمیمه A روش Webroot: مسیر دستی بدون قطعی

ایده ساده است: به‌جای اینکه Certbot وب‌سرور خودش را اجرا کند، توکن چالش را داخل یک پوشه می‌نویسد و Nginx در حال اجرای شما آن را سرو می‌کند.

این بلاک location را به بلاک server پورت 80 اضافه کنید:

server {
    listen 80;
    server_name example.com;

    # Let's Encrypt challenges are served from a real directory
    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

سپس:

sudo mkdir -p /var/www/letsencrypt
sudo nginx -t && sudo systemctl reload nginx

# Sanity check before asking Let's Encrypt (catches 90% of failures):
sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
echo "it-works" | sudo tee /var/www/letsencrypt/.well-known/acme-challenge/test.txt
curl http://example.com/.well-known/acme-challenge/test.txt    # must print: it-works

sudo certbot certonly --webroot -w /var/www/letsencrypt -d example.com
  • -w /var/www/letsencrypt مسیر Webroot که توکن‌ها در آن نوشته می‌شوند.

از این به بعد تمدیدها برای همیشه با صفر ثانیه قطعی و بدون هوک stop/start کار می‌کنند چون Nginx همیشه بالا است تا چالش را سرو کند. یک پوشه webroot مشترک می‌تواند برای همه دامنه‌های شما استفاده شود.


ضمیمه B برگه تقلب عیب‌یابی

علامتمحتمل‌ترین علت
no valid A records foundیعنی DNS (هنوز) به این سرور اشاره نمی‌کند dig +short را بررسی کنید
Timeout یا Connection refused هنگام چالشپورت 80 توسط فایروال یا security group بسته است؛ یا سرویس دیگری صاحب پورت 80 است
The requested nginx plugin does not appear to be installedاحتمالاً certbotِ قدیمیِ apt روی سیستم اجرا شده؛ با sudo apt remove certbot حذفش کنید و از نسخه‌ی snap استفاده کنید (افزونه‌ی nginx داخل خود پکیج است)
too many failed authorizationsبه Rate Limit لتس‌انکریپت خورده‌اید یک ساعت صبر کنید؛ همیشه اول با --dry-run تست کنید
قفل نمایش داده می‌شود اما سایت به‌هم‌ریخته استMixed Content: صفحه ریسورس‌هایی با http:// لود می‌کند لینک‌ها را به https:// تغییر دهید
بعد از تمدید، گواهی قدیمی سرو می‌شودیعنی Nginx ریلود نشده; بخش ۵، دام اول
صدور اولیه کار کرد ولی تمدید شکست خوردتداخل پورت در standalone بخش ۵، دام دوم

لاگ دیباگ همیشه در /var/log/letsencrypt/letsencrypt.log است.


قدم‌های بعدی

  • چند دامنه روی یک گواهی (SAN): فقط فلگ را تکرار کنید certbot --nginx -d example.com -d www.example.com -d api.example.com.
  • ابزارهای جایگزین: وب‌سرور Caddy گواهی‌ها را کاملاً خودکار و بدون هیچ ابزار اضافه‌ای می‌گیرد و تمدید می‌کند.

جمع‌بندی

حالا چرخه کامل را می‌دانید: یک CA باید مالکیت دامنه را با چالش ACME بررسی کند؛ Certbot این گفت‌وگو را خودکار می‌کند و چهار فایل PEM را در /etc/letsencrypt/live/ می‌گذارد؛ «فعال‌کردن SSL» در Nginx فقط یک listen 443 ssl به‌اضافه دو مسیر فایل است؛ و تمدید یعنی یک تایمر به‌علاوه یک هوک reload.