Let's Encrypt и certbot на Ubuntu: бесплатный SSL для nginx
Let's Encrypt — бесплатные SSL/TLS-сертификаты для любого домена. На Ubuntu выпускаются через утилиту certbot одной командой; автообновление работает само через systemd-таймер. Разбираем установку, выпуск для nginx, DNS-challenge для wildcard-сертификатов и грабли с rate-limit.
Let's Encrypt на Ubuntu: certbot, автообновление, DNS-challenge
Let's Encrypt — бесплатные SSL/TLS-сертификаты для любого домена. На Ubuntu выпускаются через утилиту certbot одной командой; автообновление работает само через systemd-таймер. Разбираем установку, выпуск для nginx, DNS-challenge для wildcard-сертификатов и грабли с rate-limit.
Что такое Let's Encrypt
Let's Encrypt — это центр сертификации (CA), выдающий бесплатные SSL/TLS-сертификаты сроком на 90 дней. Запущен в 2016 году, сейчас покрывает большую часть HTTPS-сайтов в интернете. Принципы:
- Бесплатно. Без скрытых тарифов и регистрации.
- Автоматически. Выпуск через ACME-протокол: машинно-читаемый, скриптуемый.
- 90-дневный срок. Сертификаты обновляются часто (стандарт — за 30 дней до истечения).
- Любой домен. Работают и DV-сертификаты (Domain Validation) — подтверждение, что вы владелец.
- Не работает для IP-адресов. Только полные доменные имена.
Не работает для:
- IP-адресов и localhost (нужны самоподписные).
- EV/OV-сертификатов с проверкой организации (для них берите коммерческие CA).
- Подписи кода или email-сертификатов (LE только для TLS).
Стандартный клиент на Ubuntu — certbot, разработанный EFF.
Ставим certbot
На Ubuntu есть два пути установки. Snap-вариант рекомендуется самой EFF:
sudo apt install -y snapd
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
--classic нужен для прямого доступа к файловой системе. Подробно про snap — глоссарий snap.
Альтернатива — apt-репозиторий Ubuntu:
sudo apt install -y certbot python3-certbot-nginx
apt-вариант отстаёт по версии на полгода-год; для большинства задач этого хватает. Если вам нужен DNS-01 для wildcard или новые ACME-фичи — берите snap.
Проверка:
certbot --version
Выпускаем сертификат для nginx
Самый частый случай. У вас есть nginx-конфиг с server_name app.example.com, и вы хотите HTTPS.
Предусловия:
- Домен
app.example.comуказывает A/AAAA-записями на ваш сервер. - Порт 80 открыт в UFW:
sudo ufw allow 80/tcp. - nginx запущен и слушает 80-й порт для этого домена.
Команда:
sudo certbot --nginx -d app.example.com -d www.app.example.com
Что произойдёт:
- certbot спросит email и согласие с TOS (только в первый раз).
- Сделает HTTP-01 challenge: создаст файл по
/.well-known/acme-challenge/..., Let's Encrypt запросит его через 80-й порт. - Получит сертификат и положит в
/etc/letsencrypt/live/app.example.com/. - Откроет ваш nginx-конфиг, добавит:
listen 443 ssl http2;ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
- Перезагрузит nginx (
systemctl reload nginx).
Готово — https://app.example.com работает с сертификатом.
Подробно про reverse proxy и nginx-конфигурацию — в гайде nginx reverse proxy на Ubuntu.
Структура /etc/letsencrypt/
После выпуска создаётся:
/etc/letsencrypt/
├── live/
│ └── app.example.com/
│ ├── cert.pem — сам сертификат
│ ├── chain.pem — промежуточные CA
│ ├── fullchain.pem — cert + chain (используется в nginx)
│ ├── privkey.pem — приватный ключ
│ └── README
├── archive/
│ └── app.example.com/ — все версии после обновлений
└── renewal/
└── app.example.com.conf — настройки обновления
/live/ — симлинки на актуальные версии в /archive/. Используйте именно /live/ в nginx — после обновления симлинки обновятся, новый сертификат подхватится.
privkey.pem — режим 600, читать может только root. Не давайте этому файлу более широкие права.
Автообновление
certbot ставит systemd-таймер, который запускается дважды в день и обновляет сертификаты, у которых до истечения осталось меньше 30 дней:
systemctl status certbot.timer
systemctl list-timers | grep certbot
Принудительный тест обновления (без записи изменений):
sudo certbot renew --dry-run
--dry-run имитирует обновление, но не сохраняет результат. Рекомендуется запустить сразу после первого выпуска, чтобы убедиться: всё настроено корректно.
После реального обновления certbot сам перезагрузит nginx (через хук --deploy-hook или --post-hook). Если хук не настроен — добавьте:
# /etc/letsencrypt/renewal/app.example.com.conf
[renewalparams]
post_hook = systemctl reload nginx
Или глобально для всех сертификатов:
sudo mkdir -p /etc/letsencrypt/renewal-hooks/post
sudo bash -c 'cat > /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh' <<'EOF'
#!/bin/bash
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
Подробно про systemd-таймеры и unit-файлы — в гайде systemctl enable.
DNS-01 challenge для wildcard
Сертификат *.example.com (wildcard) выпускается только через DNS-01 challenge — нужно подтвердить владение через TXT-запись в DNS, не через файл на сервере.
Установка DNS-плагина (зависит от провайдера DNS):
# Cloudflare
sudo snap install --classic certbot-dns-cloudflare
# или через apt:
sudo apt install -y python3-certbot-dns-cloudflare
# Hetzner Cloud DNS
sudo snap install certbot-dns-hetzner
# Прочие: route53 (AWS), digitalocean, gandi, godaddy и т. д.
Сохраняем API-токен провайдера в защищённый файл:
sudo tee /root/.cloudflare.ini > /dev/null <<'EOF'
dns_cloudflare_api_token = your_cloudflare_token_here
EOF
sudo chmod 600 /root/.cloudflare.ini
Выпускаем wildcard:
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.cloudflare.ini \
-d 'example.com' \
-d '*.example.com'
certonly (вместо --nginx) — только получить сертификат, не править nginx-конфиг. Wildcard сертификаты часто используют в Kubernetes / Docker — там nginx-конфиги генерируются автоматически.
После выпуска — пропишите путь к сертификату в нужные конфиги вручную.
Standalone (если nginx ещё не настроен)
Если nginx не запущен (новый сервер), а сертификат нужен — certbot может стать временным веб-сервером:
sudo certbot certonly --standalone -d app.example.com
Запустит свой HTTP-сервер на 80-м порту, пройдёт challenge, выйдет. Никакой --nginx-конфигурации не делает — только получает сертификат в /etc/letsencrypt/live/.
Перед запуском убедитесь, что 80-й порт свободен (остановите nginx, если он работает).
Грабли certbot
Rate limits Let's Encrypt:
- 50 сертификатов на домен в неделю.
- 5 одинаковых выпусков в неделю.
- 5 неудачных проверок в час на хост.
При тестировании используйте staging environment Let's Encrypt:
sudo certbot --staging --nginx -d test.example.com
Сертификат не доверенный, но лимиты на staging выше в 10–100 раз. Удалите тестовый: sudo certbot delete --cert-name test.example.com.
HTTP-01 за CDN. Cloudflare, Bunny, Selectel CDN могут перехватывать /.well-known/acme-challenge/. Решения:
- Временно отключить proxy (Cloudflare: облачко серое = DNS only).
- Использовать DNS-01 вместо HTTP-01.
Несколько серверов с одним доменом. Если домен указан на 2+ серверов через round-robin DNS, HTTP-01 может попасть не на тот сервер. Используйте DNS-01 или single-server-сценарий.
Не настроен AAAA. Если домен имеет AAAA-запись (IPv6), а сервер не слушает 80-й порт по IPv6 — challenge провалится. Либо настройте IPv6, либо удалите AAAA-запись на время выпуска.
Забыл --keep-until-expiring. Если запустите certbot повторно с теми же -d, он создаст новый сертификат, тратя rate-limit. Используйте sudo certbot renew (без -d) для штатных обновлений.
Closing port 80 после выпуска. Соблазнительно закрыть 80-й, оставить только 443. Но HTTP-01 challenge при обновлении использует именно 80-й порт. Альтернатива — TLS-ALPN-01 (требует поддержку, certbot её сделать сам не может) или DNS-01.
TLS-настройки nginx после certbot
certbot вставляет минимальные TLS-настройки. Для прода добавьте:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# HSTS — заставляет браузер всегда ходить по HTTPS
add_header Strict-Transport-Security "max-age=63072000" always;
Современные рекомендации (2026): отключайте TLS 1.0/1.1, оставляйте только 1.2 и 1.3. SSL Labs (ssllabs.com/ssltest) поможет проверить итог — целевой grade A+.
Удаление сертификата
sudo certbot delete --cert-name app.example.com
Удалит файлы из /etc/letsencrypt/live/ и /archive/, остановит автообновление этого сертификата. nginx-конфиг не правит — это нужно сделать руками (убрать listen 443 ssl; и пути к сертификату).
Частые вопросы
Что такое Let's Encrypt
Бесплатный центр сертификации (CA), выдающий SSL/TLS-сертификаты сроком на 90 дней. Запущен в 2016 году EFF/Mozilla/Akamai/Cisco. Работает через автоматизированный протокол ACME — выпуск и обновление можно полностью скриптовать. На Ubuntu стандартный клиент — certbot.
Бесплатно ли использовать Let's Encrypt в коммерческих целях
Да. Сертификаты бесплатные для любого использования — личное, коммерческое, корпоративное. Никаких лицензий, тарифов, ограничений по выручке. Единственные лимиты — rate-limits на количество выпусков в неделю.
Как часто обновляются сертификаты Let's Encrypt
Сертификаты живут 90 дней. certbot обновляет их автоматически за 30 дней до истечения через systemd-таймер (certbot.timer), который запускается дважды в день. Если автообновление работает — вмешательство не требуется.
Как выпустить сертификат для nginx через certbot
sudo certbot --nginx -d example.com -d www.example.com. certbot сделает HTTP-01 challenge, получит сертификат, отредактирует nginx-конфиг (добавит listen 443 ssl, пути к сертификату), перезагрузит nginx. Работает только если домен указывает на сервер и порт 80 открыт.
Как получить wildcard-сертификат через certbot
Только через DNS-01 challenge. Установите DNS-плагин (например, python3-certbot-dns-cloudflare), сохраните API-токен провайдера в файл, запустите sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/.cloudflare.ini -d 'example.com' -d '*.example.com'.
Что делать если certbot выдаёт rate limit
Подождать неделю или использовать staging environment: sudo certbot --staging ... — лимиты в 10+ раз выше. Сертификаты со staging не доверенные браузерами, но подходят для отладки конфига. После настройки — удалить staging-сертификат и выпустить настоящий.
Можно ли использовать Let's Encrypt без домена
Нет. LE выдаёт только DV-сертификаты для полноценных доменных имён. Для localhost, IP-адресов или внутренних имён используйте самоподписные сертификаты (openssl req) или внутренний CA (например, mkcert для разработки, step-ca для прода).
Что запомнить
- certbot ставится через
snap(рекомендация EFF) илиapt(постарше). Командаsudo certbot --nginx -d example.comза 30 секунд выпускает сертификат и правит nginx-конфиг. - Сертификаты живут 90 дней, обновляются автоматически через
certbot.timer. Запуститеcertbot renew --dry-runпосле первого выпуска. - Wildcard (
*.example.com) — только через DNS-01 challenge с плагином DNS-провайдера. HTTP-01 не подходит. - 80-й порт должен оставаться открытым для обновлений HTTP-01. Не закрывайте его «потому что есть HTTPS».
- Перед массовыми экспериментами —
--staging, чтобы не упереться в rate-limit прода. - Подробно про SSL и TLS-настройки — гайд по nginx reverse proxy.
Обложка: фото Iain с Unsplash, лицензия Unsplash.