Перейти к содержимому
Alex Kovalev

SSL для простых смертных, или PunchSalad вам не нужен

Практический гайд: как выпустить бесплатный SSL-сертификат через Certbot, пройти ACME HTTP-проверку через .well-known и настроить продление без платного SSL-сервиса.

Guide5мин чтения
Питер Брейгель, «Жатва»: крестьяне жнут пшеницу и обедают под грушевым деревом.
Питер Брейгель, «Жатва»: крестьяне жнут пшеницу и обедают под грушевым деревом.

Почти у каждой хостинг-панели сейчас есть кнопка SSL, Let’s Encrypt или AutoSSL. Нажмите её. Если Cloudflare, cPanel, Plesk, ваш хостер или кто-то ещё уже сам продлевает сертификат, закрывайте статью и идите гулять. Вы победили.

Этот гайд для другого хостинга. Того, который продаёт SSL как платную опцию, выдаёт файловый менеджер из 2009 года и каким-то образом убеждает вас, что без PunchSalad замочек в браузере не выживет.

Выживет. PunchSalad проходит ту же ACME-проверку, которую Certbot делает бесплатно.

Совсем коротко: что такое SSL?

SSL — это старое название, которым все до сих пор называют TLS, шифрование, на котором работает HTTPS.

Когда браузер подключается, ваш сервер показывает ему сертификат, как паспорт на входе. Браузер проверяет три вещи: сертификат подписан центром сертификации, которому он доверяет, имя в нём совпадает с вашим доменом, и срок его действия не истёк. Если всё сходится, они договариваются о временных ключах и дальше общаются по старому доброму HTTP внутри зашифрованного туннеля.

Сертификат делает две полезные вещи:

  • доказывает, что сервер, который отвечает за example.com, действительно контролирует example.com;
  • шифрует трафик между посетителем и этим сервером.

Он не доказывает, что владелец хороший человек, что сайт безопасен или что в установке WordPress нет плагина, который последний раз обновлялся при администрации Обамы.

Как работает ACME-проверка

Let’s Encrypt раздаёт сертификаты бесплатно, но сначала хочет убедиться, что домен ваш. ACME — это протокол, по которому идёт этот разговор.

На пещерном языке:

  1. Certbot просит у Let’s Encrypt сертификат для example.com.
  2. Let’s Encrypt говорит: положи этот странный текст в файл с этим странным именем.
  3. Вы кладёте его по адресу http://example.com/.well-known/acme-challenge/WEIRD-NAME.
  4. Let’s Encrypt скачивает файл и видит ожидаемый текст.
  5. Такое мог сделать только тот, кто управляет сайтом, поэтому сертификат выдаётся.
Не защищеноhttp://example.com

Certbot выдаёт вам файл:

Я всегда смотрю только в /.well-known/acme-challenge/. Каждый раз.

сертификата пока нетexample.com · Let's Encrypt · действует 90 дней
Перетащите файл в папку или нажмите на него, а потом на папку. Остальное сделает робот.

Это называется HTTP-01 challenge. Порт 80 должен быть доступен из интернета. Папка .well-known не магическая; это просто условленный шкафчик, в котором роботы, выдающие сертификаты, ищут доказательства.

Сначала попробуйте скучный автоматический вариант

Если у вас есть root-доступ и вы используете Nginx или Apache, Certbot сам пройдёт проверку, поправит конфиг веб-сервера и настроит продление:

Terminal window
sudo certbot --nginx
# or
sudo certbot --apache

Для большинства серверов это правильный ответ. Один раз проверьте продление и больше не трогайте:

Terminal window
sudo certbot renew --dry-run

Большинство установок Certbot включают systemd-таймер или cron-задачу, которая запускает certbot renew. Вам не нужно помнить про сертификат и продлевать его раз в несколько месяцев. Компьютеры неплохо справляются с календарями.

Webroot, если хотите сами управлять конфигом

Иногда не хочется, чтобы Certbot лез в конфиг Nginx, или плагин веб-сервера просто не понимает вашу настройку. Плагин webroot доказывает владение доменом, записывая файл проверки в существующую папку сайта, без остановки сервера.

Допустим, сайт отдаётся из:

/var/www/example.com/public

Убедитесь, что Nginx отдаёт папку проверки по обычному HTTP:

server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/public;
location ^~ /.well-known/acme-challenge/ {
default_type text/plain;
try_files $uri =404;
}
location / {
return 301 https://$host$request_uri;
}
}

Прежде чем связываться с сертификатами, проверьте шкафчик:

Terminal window
sudo mkdir -p /var/www/example.com/public/.well-known/acme-challenge
echo works | sudo tee /var/www/example.com/public/.well-known/acme-challenge/test
curl http://example.com/.well-known/acme-challenge/test
sudo rm /var/www/example.com/public/.well-known/acme-challenge/test

Если curl напечатал works, запрашивайте сертификат:

Terminal window
sudo certbot certonly --webroot \
-w /var/www/example.com/public \
-d example.com \
-d www.example.com

Certbot сохранит его здесь:

/etc/letsencrypt/live/example.com/fullchain.pem
/etc/letsencrypt/live/example.com/privkey.pem

Укажите эти файлы в HTTPS-сервере:

server {
listen 443 ssl;
server_name example.com www.example.com;
root /var/www/example.com/public;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# The rest of your site config goes here.
}

Потом проверьте конфиг и перезагрузите Nginx:

Terminal window
sudo nginx -t
sudo systemctl reload nginx
sudo certbot renew --dry-run

При продлении Certbot помнит, что вы использовали webroot, кладёт новую проверку в ту же папку, получает новый сертификат и подменяет файлы по этим путям. Но Nginx нужно перезагрузить, чтобы он заметил замену. Добавьте постоянный deploy-хук, который запускается только после успешного продления:

sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx >/dev/null <<'EOF'
#!/bin/sh
systemctl reload nginx
EOF
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx
sudo certbot renew --dry-run --run-deploy-hooks
https://example.comистекает 2 дек. 2026 г.NET::ERR_CERT_DATE_INVALID

диск

  • live/example.com/
  • fullchain.pem
  • privkey.pem
  • archive/example.com/
  • privkey1.pem
  • fullchain1.pem
  • privkey2.pem
  • fullchain2.pem

истекает 2 дек. 2026 г.

память nginx

серт. #1
истекает 2 дек. 2026 г.

Больше 30 дней. Certbot проверил, пожал плечами, спит.

Совсем ручной способ для ужасного хостинга

Вот мы и добрались до сценария PunchSalad: сайт работает, но SSH-доступа нет, и кнопки Let’s Encrypt тоже нет. Вы всё равно можете запустить Certbot на другой Linux-машине и загрузить доказательство через FTP или файловый менеджер хостинга.

Другой Linux-машины тоже нет? Я сделал инструмент для SSL-сертификата, который ведёт тот же диалог прямо в браузере: выдаёт файлы (или DNS-записи), просит Let’s Encrypt их проверить и отдаёт сертификат, ключ и CA bundle. Шаги ниже это ровно то, что он делает за вас.

Запустите:

Terminal window
sudo certbot certonly --manual \
--preferred-challenges=http \
--agree-tos \
-m you@example.com \
-d example.com \
-d www.example.com

Certbot покажет имя файла, его содержимое и URL примерно такого вида:

http://example.com/.well-known/acme-challenge/a1b2c3-weird-token

Пока не нажимайте Enter. В файловом менеджере хостинга:

  1. Откройте корневую папку сайта, обычно это public_html.
  2. Создайте в ней .well-known. Папки с точкой в начале могут быть скрыты по умолчанию.
  3. Создайте acme-challenge внутри .well-known.
  4. Создайте ровно тот файл, который попросил Certbot, ровно с тем содержимым, которое он напечатал.
  5. Откройте URL в браузере или через curl и убедитесь, что он возвращает только это значение.
  6. Вернитесь в Certbot и нажмите Enter.

Если вы запросили и голый домен, и www, Certbot может попросить ещё одну проверку. Повторите всё заново. Каждое имя хоста должно указывать на этот хостинг-аккаунт и отдавать правильный файл.

После проверки Certbot выдаст вам такие файлы:

ФайлЧто это
cert.pemСертификат вашего домена
chain.pemПромежуточные сертификаты центра сертификации
fullchain.pemcert.pem и chain.pem вместе
privkey.pemВаш приватный ключ; никому его не давайте

Панель хостинга может попросить отдельно Certificate, Private Key и CA Bundle. Дайте ей cert.pem, privkey.pem и chain.pem. Если она просит один файл с цепочкой сертификатов, используйте fullchain.pem.

live/example.com/

публичный
-----BEGIN CERTIFICATE-----
⋮ example.com
-----END CERTIFICATE-----
публичный
-----BEGIN CERTIFICATE-----
⋮ Let's Encrypt
-----END CERTIFICATE-----
публичный
-----BEGIN CERTIFICATE-----
⋮ example.com
-----END CERTIFICATE----------BEGIN CERTIFICATE-----
⋮ Let's Encrypt
-----END CERTIFICATE-----
секрет
-----BEGIN PRIVATE KEY-----
⋮ только на вашей машине
-----END PRIVATE KEY-----

HostPanel SSL/TLS
панель просит

  • Chrome
  • Firefox
  • curl, приложения

curl: (60) SSL certificate problem: unable to get local issuer certificate

Классика: пустой CA Bundle. curl заметит.

Подвох ручного режима

Сертификаты, полученные через --manual, не продлеваются автоматически, если только вы не напишете хуки аутентификации, которые сами загрузят проверку. Повторите ту же команду и переустановите новый сертификат заранее, задолго до истечения текущего.

Это не провал Certbot. Для автоматического продления нужен какой-то автоматический способ доказать владение доменом и установить результат. Человек, перетаскивающий секретный файл в public_html, к сожалению, не API.

https://example.comистекает 2 дек. 2026 г.

Ваше подключение не является закрытым

NET::ERR_CERT_DATE_INVALID

  1. certbot certonly --manual
  2. залить токен в public_html
  3. вставить файлы в панель

ушли 0 · при ~140 посетителях в день

С 60-го дня таймер не справляется. Запасной план — вы.

Если хостер позже даст SSH-доступ, переходите на --webroot. Если добавит встроенную поддержку Let’s Encrypt, пользуйтесь ей. Если он продолжит каждый год брать деньги за привилегию вставлять бесплатные сертификаты в форму, подумайте о смене хостинга.

Когда не получается

Почти любая ошибка HTTP-01 — это что-то из списка:

  • домен указывает на другой сервер;
  • порт 80 заблокирован;
  • .well-known создана не в настоящей корневой папке сайта;
  • WordPress, Nginx или какое-то правило безопасности перехватывает URL проверки;
  • запросили хост www, но у него нет DNS-записи;
  • IPv6-запись AAAA указывает не туда же, куда IPv4-запись A;
  • файловый менеджер услужливо дописал .txt к имени токена.

Не перезапускайте Certbot снова и снова в надежде, что интернет передумает. Откройте точный URL проверки. Пока он не вернёт точное значение, Let’s Encrypt тоже не сможет его проверить.

Полезные ссылки


Обложка: Питер Брейгель Старший, «Жатва», 1565, Метрополитен-музей, общественное достояние.

Комментарии

Комментарии живут в GitHub Discussions (через giscus), так что для участия нужен аккаунт GitHub.

Чирикну, когда выйдет новый пост

Одно письмо на каждый новый пост, обычно по пятницам. Больше ничего, а отписаться можно в любой момент.

Удобнее читать в RSS-ридере? Есть RSS-лента.

© Alex Kovalev. Все права защищены. · Политика конфиденциальности