SSL و امنیت
نصب SSL با Certbot و Let's Encrypt رایگان روی Nginx و Apache
نصب SSL با Certbot یعنی گرفتن گواهی رایگان Let's Encrypt برای دامنه ای که روی VPS شما به Nginx یا Apache وصل است. یک پلاگین Certbot گواهی را می گیرد، در وب سرور تنظیم می کند و تمدید را به یک تایمر سیستم می سپارد.
اگر سرور Ubuntu یا Debian دارید و دسترسی root، نصب SSL با Certbot چند دستور بیشتر نیست: نصب بسته certbot و پلاگین وب سرور، اجرای certbot --nginx یا certbot --apache و بعد تست تمدید. این راهنما همین مسیر را با دستورهای واقعی نشان می دهد و بعد سراغ خطاهای رایج می رود. اگر هاست اشتراکی cPanel دارید، Certbot لازم نیست و SSL با AutoSSL گرفته می شود؛ مشکلات آن در آموزش AutoSSL در cPanel آمده است.
پیش نیازها
پیش از اجرای Certbot چهار چیز باید درست باشد، چون بیشتر شکست ها از همین جا شروع می شوند:
- رکورد A دامنه (و اگر لازم دارید رکورد www) به IP همین سرور اشاره کند. با
dig +short example.comمی توانید مقدار را ببینید. - پورت 80 و 443 از بیرون باز باشد. روی سرور با ufw این دو را باز کنید و فایروال پنل سرویس دهنده را هم بررسی کنید.
- وب سرور نصب باشد و دامنه در یک server block یا VirtualHost تعریف شده باشد.
- سرور بتواند به Let's Encrypt وصل شود. این را با
curl -sI https://acme-v02.api.letsencrypt.org/directoryامتحان کنید. روی بعضی سرورها داخل ایران ممکن است این اتصال محدود باشد؛ در این حالت پاسخی نمی بینید و باید مسیر شبکه را از ارائه دهنده بپرسید.
نصب Certbot روی Ubuntu و Debian
مستندات Certbot نصب با snap را توصیه می کند، ولی بسته apt هم روی Ubuntu و Debian موجود است و برای بیشتر سرورها کافی است. نسخه آن ممکن است کمی قدیمی تر باشد. برای Nginx:
sudo apt update
sudo apt install certbot python3-certbot-nginx
برای Apache:
sudo apt update
sudo apt install certbot python3-certbot-apache
گرفتن گواهی روی Nginx و Apache
دستور زیر برای Nginx است. گواهی را می گیرد، فایل تنظیمات سایت را اصلاح می کند و وب سرور را reload می کند:
sudo certbot --nginx -d example.com -d www.example.com
برای Apache همین دستور با پلاگین دیگر اجرا می شود:
sudo certbot --apache -d example.com -d www.example.com
Certbot در اولین اجرا ایمیل شما را برای اعلان های انقضا و موافقت با شرایط سرویس می پرسد. در مرحله بعد می پرسد http به https ریدایرکت شود یا نه. اگر سایت فقط روی https کار می کند، ریدایرکت را فعال کنید. اگر بعد از آن به خطای ریدایرکت بیش از حد رسیدید، علت معمولا پشت پروکسی بودن سایت است.
پیش از اجرا از فایل تنظیمات سایت (مثلا /etc/nginx/sites-available/example.com یا /etc/apache2/sites-available/example.com.conf) یک نسخه کپی بگیرید. Certbot فایل را مستقیم ویرایش می کند. بعد از اجرا هم sudo nginx -t یا sudo apachectl configtest را بزنید تا خطای syntax را قبل از reload ببینید.
گواهی و کلید در مسیر /etc/letsencrypt/live/example.com/ ذخیره می شوند. فایل های fullchain.pem و privkey.pem همان هایی هستند که در تنظیمات وب سرور به آن ها اشاره می شود. این مسیر از فایل های اصلی archive ساخته شده و نباید فایل داخل live را دستی کپی یا ویرایش کنید.
HTTP-01 یا DNS-01
Let's Encrypt باید ثابت شود که دامنه مال شماست. این کار با «چالش» انجام می شود و دو نوع رایج دارد، که در مستندات انواع چالش توضیح داده شده اند.
| ویژگی | HTTP-01 | DNS-01 |
|---|---|---|
| روش اثبات | فایلی زیر /.well-known/acme-challenge/ روی پورت 80 | یک رکورد TXT با نام _acme-challenge در DNS |
| پورت 80 باز لازم است | بله | نه |
| گواهی Wildcard | پشتیبانی نمی شود | پشتیبانی می شود |
| سرور پشت NAT یا بدون IP عمومی | کار نمی کند | کار می کند |
| تمدید خودکار | با پلاگین nginx، apache یا webroot | فقط با پلاگین DNS یا اسکریپت hook |
برای یک سایت معمولی با IP عمومی HTTP-01 ساده تر است و Certbot همان را پیش فرض می زند. اگر پورت 80 را نمی توانید باز کنید یا گواهی *.example.com می خواهید، DNS-01 لازم است:
sudo certbot certonly --manual --preferred-challenges dns -d example.com -d '*.example.com'
در این حالت Certbot یک مقدار TXT می دهد که باید در DNS دامنه بسازید. حالت --manual تمدید خودکار ندارد، چون هر بار باید رکورد را دستی بسازید. برای تمدید خودکار از پلاگین DNS ارائه دهنده دامنه یا اسکریپت --manual-auth-hook استفاده کنید. اگر پلاگینی برای ارائه دهنده شما وجود ندارد، تمدید را دستی انجام دهید و برایش یادآور بگذارید.
اگر وب سرور را نمی خواهید Certbot دست بزند، دو حالت دیگر هست: certbot certonly --webroot -w /var/www/example -d example.com که فایل چالش را در پوشه سایت می گذارد و certbot certonly --standalone که خودش موقتا روی پورت 80 گوش می دهد و برای همین باید وب سرور را موقتا متوقف کنید. اگر پورت 80 توسط سرویس دیگری گرفته شده، آموزش رفع مشکل پورت 80 در Apache کمک می کند.
تمدید خودکار و certbot renew --dry-run
گواهی Let's Encrypt عمر کوتاه دارد، پس تمدید باید خودکار باشد. بسته Certbot روی Ubuntu و Debian معمولا یک تایمر systemd به اسم certbot.timer می سازد که چند بار در روز اجرا می شود و فقط گواهی های نزدیک به انقضا را تمدید می کند. وضعیت آن را اینطور ببینید:
systemctl list-timers | grep certbot
sudo certbot certificates
دستور دوم همه گواهی ها و تاریخ انقضای آن ها را فهرست می کند. تمدید را بدون تغییر واقعی با دستور زیر امتحان کنید:
sudo certbot renew --dry-run
این دستور از سرور staging استفاده می کند و تمام مراحل تمدید را اجرا می کند ولی گواهی واقعی عوض نمی شود. اگر خروجی در انتها Congratulations, all simulated renewals succeeded بگوید، تمدید واقعی هم باید کار کند. روی سرور جدید این تست را همان روز نصب بزنید و هر چند ماه یک بار تکرار کنید.
اگر وب سرور باید بعد از هر تمدید reload شود و پلاگین آن را انجام نمی دهد، hook اضافه کنید:
sudo certbot renew --deploy-hook "systemctl reload nginx"
برای Apache به جای nginx نام سرویس apache2 را بنویسید.
گرفتن گواهی برای چند دامنه و بازگرداندن آن
یک گواهی می تواند چند نام را پوشش بدهد. همه نام ها را با -d پشت سر هم بنویسید و نام اول، نام اصلی پوشه live می شود. اگر بعدا دامنه ای اضافه کردید، همان دستور را با فهرست کامل و گزینه --expand اجرا کنید تا گواهی موجود گسترش پیدا کند و گواهی تازه ای جدا ساخته نشود:
sudo certbot --nginx --expand -d example.com -d www.example.com -d shop.example.com
برای حذف کامل گواهی دامنه ای که دیگر استفاده نمی کنید از sudo certbot delete --cert-name example.com کمک بگیرید. این دستور فایل ها را پاک می کند، پس قبلش مطمئن شوید هیچ سایتی هنوز به آن اشاره نمی کند. اگر فقط می خواهید گواهی را باطل کنید چون کلید خصوصی لو رفته، certbot revoke --cert-name example.com را بزنید و بعد گواهی جدید بگیرید.
برای سروری که با چند سایت پر شده، فهرست sudo certbot certificates سریع ترین راه دیدن این است که کدام گواهی نزدیک انقضاست و کدام نام ها زیر یک گواهی جمع شده اند. فایل تنظیمات هر گواهی در /etc/letsencrypt/renewal/ قرار دارد و نوع چالش و پلاگین استفاده شده در آن نوشته شده است. اگر روش اعتبارسنجی را بعدا عوض کنید، گواهی را دوباره با روش جدید بگیرید تا این فایل به روز شود.
نکته درباره سرور پشت پنل یا چند سایت
اگر روی همان VPS پنلی مثل cPanel یا Plesk نصب است، Certbot را کنار آن اجرا نکنید. پنل فایل های تنظیمات وب سرور را خودش مدیریت می کند و تغییر دستی شما در اولین بازسازی پاک می شود. در cPanel از AutoSSL و در Plesk از افزونه Let's Encrypt خود پنل استفاده کنید؛ راهنمای رفع خطاهای آن در آموزش Plesk Let's Encrypt آمده است.
اگر چند سایت روی یک Nginx دارید، هر سایت یک server block جدا با server_name درست لازم دارد. Certbot گواهی را به server block ای وصل می کند که نام دامنه در server_name آن باشد. نام نوشته نشده یا اشتباه تایپ شده باعث می شود پلاگین بلوک را پیدا نکند و پیام می دهد که نمی تواند VirtualHost یا server block مناسب را پیدا کند. در این حالت اول server_name را درست کنید و دستور را دوباره اجرا کنید.
خطاهای رایج Certbot
| پیام | علت محتمل | بررسی | |
|---|---|---|---|
Timeout during connect (likely firewall problem) | پورت 80 از بیرون بسته است | ufw status و فایروال پنل سرویس دهنده | |
Invalid response from http://... 404 | وب سرور به فایل چالش جواب نمی دهد یا دامنه به سرور دیگری اشاره می کند | dig +short و تنظیمات server block | |
Connection refused | وب سرور اجرا نیست | systemctl status nginx یا apache2 | |
too many failed authorizations یا rate limit | تکرار زیاد درخواست ناموفق | چند ساعت صبر کنید و با --staging تست کنید | |
Could not bind TCP port 80 | سرویس دیگری پورت را گرفته (در حالت standalone) | `ss -tlnp | grep :80` |
Let's Encrypt محدودیت تعداد درخواست دارد. برای تست از --dry-run یا --staging استفاده کنید و جزئیات محدودیت ها را از صفحه rate limits بخوانید. ممکن است مقدارها عوض شده باشد، پس عدد را از حافظه نگیرید.
بعد از نصب گواهی
بعد از اولین موفقیت، همان روز sudo certbot renew --dry-run را اجرا کنید و تاریخ انقضا را در یادداشت بگذارید.
آدرس سایت را در مرورگر باز کنید و گواهی را از قفل کنار آدرس ببینید. اگر خطای اتصال امن نیست می بینید، راهنمای رفع خطای ssl your connection is not private علت ها را به ترتیب شیوع می نویسد. برای ریدایرکت دستی http به https روی Apache، ریدایرکت با htaccess را ببینید. اگر هنوز بین VPS داخل و خارج ایران مردد هستید، مقایسه VPS ایران و خارج را بخوانید.