В недавней статье об SSL-сертификатах, точнее, в комментариях к ней, затронули вопрос, который похоже создает для многих головную боль: как обновлять сертификаты от Let's Encrypt? Ведь сертификаты выдаются на 3 месяца, а потом их надо обновлять.
Конечно, есть Certbot, есть софт, который умеет сам получать и обновлять сертификаты — но вопрос возник именно по тому софту, который сам не умеет (а подключить Certbot почему‑то не получается)
Когда‑то у меня тоже возник такой вопрос, и почему‑то не устроил Certbot — не помню уже точную причину. Решил проблему иначе.
Во‑первых, что именно удостоверяет удостоверяющий центр Let's Encrypt? Он просто проверяет, что у якобы владельца сайта (для простоты будем считать что у нас сайт) есть права доступа к записям DNS домена или к самому сайту на этом домене.
То есть, если вы хотите получить себе сертификат например для сайта на домене Сбербанка — то у вас должен быть либо доступ к DNS‑серверу, либо к сайту Сбербанка, иначе ничего не получится. Причем к сайту доступ все равно нужен, потому что там должен находиться приватный ключ сервера и полученный сертификат. Для большинства применений такого уровня безопасности достаточно.
Как именно потом вы будете использовать полученный для домена сертификат — это ваше дело. Главное, на момент получения‑обновления сайт на этом домене должен быть доступен извне (ну, или доступны записи в DNS). При отправке вашего запроса на сертификат Let's Encrypt проверит «секретный файл» на сервере, и если он там есть — продлит действие сертификата. Называется это все acme protocol.
Для работы с ним есть скрипт, который так и называется — 'letsencrypt.sh'.
Проект есть на Гитхабе — https://github.com/digint/letsencrypt.sh
Это по факту просто shell‑скрипт, который не требует никакой особой экзотики для работы, не висит в памяти, не требует какого‑то особого взаимодействия с ним — просто запускается, отрабатывает, и всё.
Еще потребуется установленный пакет openssl — тоже стандартная для Linux вещь.
Все остальное — shell‑скрипты, причем несложные.
Первым делом нужно создать ключ аккаунта — по этому ключу Let's Encrypt будет дальше общаться с вами. Можно просто выполнить команду, а можно создать скрипт 1.create_account.sh, чтобы не вспоминать потом заново:
#!/bin/sh
umask 0177
openssl genrsa -out account.key 4096
umask 0022
Он просто создает файл ключа. Это ключ аккаунта.
Теперь его надо зарегистрировать в Let's Encrypt - создадим скрипт 2.register.sh:
#!/bin/sh
./letsencrypt.sh register -a account.key -e you@email.there
Теперь надо получить для аккаунта thumbprint - ту самую "секретную строку" в "секретном файле" - пишем скрипт 3.thumbprint.sh:
#!/bin/sh
./letsencrypt.sh thumbprint -a account.key > th
Содержимое файла th примерно такое:
account thumbprint: dkjjsdd6jr2a6JKJH7DFjjlklIU4HdfJkkk7788HhhR
Сохраним, он нам понадобится позже.
Создаем ключ сервера. Он как раз нужен на сервере, указывается в настройках веб-сервера.
Снова скрипт, 4.serverkey.sh:
#!/bin/sh
umask 0177
openssl genrsa -out server.key 4096
umask 0022
openssl req -new -key server.key -out self-signed.csr
openssl x509 -req -in self-signed.csr -signkey server.key -out self-signed.pem -days 365
Как видите, то жесамое что и первый скрипт, просто чтобы не запутываться потом, что когда делать. Кроме того — создается самоподписанный сертификат, он понадобится только один раз.
Теперь самое время настроить веб-сервер. На примере Nginx:
vim /etc/nginx/sites-available/my-site.conf
server {
listen 80;
server_name my-site.com;
location ~ "^/\.well-known/acme-challenge/([-_a-zA-Z0-9]*)$" {
default_type text/plain;
return 200 "$1.dkjjsdd6jr2a6JKJH7DFjjlklIU4HdfJkkk7788HhhR";
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name my-site.com;
ssl_certificate /etc/ssl/my-site.com.pem;
ssl_certificate_key /etc/ssl/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location ~ "^/\.well-known/acme-challenge/([-_a-zA-Z0-9]*)$" {
default_type text/plain;
return 200 "$1.dkjjsdd6jr2a6JKJH7DFjjlklIU4HdfJkkk7788HhhR";
}
..... your site settings ....
}
Что здесь происходит: при запросе типа my-site.com/.well-known/acme-challenge/blablabla сервер возвращает строку «blablabla.ваше_секретное_слово» из файла th, полученного ранее. Так Let's Encrypt понимает, что этот сайт на этом домене вам не чужой.
Также указываются места для сертификата и ключа сервера, на этом этапе сертификат просто должен быть — именно для этого и используем самоподписанный, переименовав его как указано в конфиге. Перезапускаем Nginx:
/etc/init.d/nginx restart
Теперь у нас сайт работает по HTTPS, но с самоподписанным сертификатом. А вот теперь заменим его на сертификат от Let's Encrypt, скрипт 5.sign.sh:
#!/bin/sh
cd /etc/ssl
if [ "x$1" != "x" ] ; then
echo "OK: use $1"
./letsencrypt.sh sign -a account.key -k server.key -c ${1}.pem -P true ${1}
fi
./5.sign.sh my-site.com
Скрипт отправит запрос на сертификат для сайта my-site.com, результат сохранит в my-site.com.pem, а цепочку сертификатов в my-site.com.pem_chain.
Остается добавить цепочку в сертификат (необязательно, но целесообразно) и перезапуcтить nginx:
cat my-site.com.pem_chain >> my-site.com.pem
/etc/init.d/nginx restart
Теперь сайт работает через сертификат от Lets Encrypt. Через три месяца надо продлевать — для этого достаточно повторить шаги:
./5.sign.sh my-site.com
cat my-site.com.pem_chain >> my-site.com.pem
/etc/init.d/nginx restart
Если нужен новый сайт на том же сервере — просто поменять «my‑site.com» на другое имя — шаги с 1 по 4 делать не обязательно, только если нужен другой аккаунт и на другой машине.
Но ведь это ручная работа, нужно следить за сроком сертификата, а не хочется?
Правильно, не хочется. Пусть работает компьютер, он железный:
Пишем скрипт renew.sh:
#!/bin/sh
cd /etc/ssl
list=$(find . -name \*.pem -mtime +30)
for i in ${list} ; do
host=$(echo $i | grep -oP '(?<=/)[^/]+(?=\.pem)')
./5.step.sign ${host}
while [ $? -ne 0 ] ; do
sleep 5
./5.step.sign ${host}
done
cat ${host}.pem_chain >> ${host}.pem
done
/etc/init.d/nginx restart
И вызываем его по крону, раз в несколько дней.
Что он делает? Файлы сертификатов доменов хранятся в виде site‑name.pem, он проверяет наличие тех, которые обновлялись более 30 дней назад. выделяет имя домена, и пытается обновить для него сертификат. Иногда с первого раза это не срабатывает, если сервер перегружен — тогда он с упорством маньяка будет раз в 5 секунд пробовать снова и снова, пока не пробьется.
В итоге у нас кучка скриптов, которые понятно в какой последовательности запускать, можно создавать новые аккаунты или использовать один общий, создавать новые серверные ключи или копировать старые, получать сертификаты для разных сайтов, и автоматически их потом обновлять. И всё — обычные скрипты.
Комментарии (0)
MountainGoat
16.09.2025 19:05Чтобы не заниматься всем этим вручную, я использую https://github.com/linuxserver/docker-swag. Это образ для Докера, содержащий nginx и самостоятельно следящий за сертификатом. Он даже уведомит на почту, если сертификат всё таки скоро протухнет. Точнее, попросит LetsEncrypt уведомить.
Затем из него можно копировать сертификаты куда надо или просто использовать его как proxy.
Sank0k69
16.09.2025 19:05Топ материал, он бы идеально добавил бы мою статью про SSL, о которой идет речь в начале =D
Ахуительный контент, я искренне считаю, что они прям ИДЕАЛЬНО дополняют друг-друга.
greenork
16.09.2025 19:05Зачем использовать форк возрастом с говно мамонта, когда оригинал обновляется и работает? https://github.com/dehydrated-io/dehydrated
JBFW Автор
16.09.2025 19:05Зачем обновлять то, что работает? )
Это ж не московские бордюры....
greenork
16.09.2025 19:051) В вашем форке от 2015 года не вижу использования ACME v2.
https://github.com/digint/letsencrypt.sh
2) В оригинальном скрипте
Use new ACME v2 endpoint by default
2018-03-13
https://github.com/dehydrated-io/dehydrated/releases/tag/v0.6.1
3) С ноября 2021 ACME v1 не работает.
https://community.letsencrypt.org/t/end-of-life-plan-for-acmev1/88430/2
Что там у вас работает? Тут нужна гифка с Тиньковым.
Проверять не буду, мне теперь кажется что вы накопипастили мусор из чатика с нейросеткой.JBFW Автор
16.09.2025 19:05Начнем с того, что это не мой форк. Я его просто использую.
А во-вторых, я его использую - он работает. Вот прямо пару часов назад.
Правда, я совершенно не помню откуда конкретно этот скрипт взял, это было 5 лет назад - возможно это не тот который на конкретно этом Гитхабе, а другой, правильный - но он тоже называется letsencrypt.sh. если вы так хорошо разбираетесь в форках - может быть тогда правильную ссылочку на ТОТ letsencrypt.sh дадите?
Что там у вас за отношения с гифками и нейросетками - этого не знаю.
DikSoft
16.09.2025 19:05Для ленивых есть ещё вариант - Certify The Web
Что, если он "не умеет обслуживать именно вашу программу"?
Последовательность решения такая:
Ставим утилиту на отдельный сервер.
На сервере поднимаем IIS
Утилиту нацеливаем на этот IIS
Балансировщику на входе , который что-то публикует, объясняем, что запросы на /.well-known отправлять надо на этот сервер, например , для HAProxy это примерно так:
haproxy.cfg
.. # ACME acl app-acme-path path -i /.well-known acl app-acme-path path_beg -i /.well-known .. use_backend backend_http_acme if app-acme-path .. backend backend_http_acme mode http balance source server webserver1acme 10.11.12.13:80 check # Web server 1
Утилите задаем post execution script, вся задача которого будет создать в журнале приложений событие с каким-то вашим уникальным кодом
В планировщике создаем триггер на этот уникальный код в журнале, который будет запускать ваш скрипт, занимающийся установкой полученного сертификата, куда нужно и от той учетной записи, которая имеет нужные права.
Вариант рабочий, несложный в отладке, расширяемый и достаточно стабильный.
aleksei_ee
16.09.2025 19:05Есть ли возможность с помощью этого или какого либо другого решения выдать сертификат для сайта, недоступного извне сети? То есть для внутреннего сайта
AntonLarinLive
16.09.2025 19:05Если есть контроль над публичной зоной DNS, совпадающей с внутренней, то можно сделать проверки исключительно через DNS без всяких сайтов.
JBFW Автор
16.09.2025 19:05Есть.
Делается внешний сайт, единственный контент которого - секретная строка.
Делается внутренний сайт с тем же доменным именем, которое прописывается на своем локальном DNS сервере в интранете.
Снаружи - виден сайт-заглушка, этого достаточно для получения сертификата. Внутри виден настоящий внутренний сайт.
Доменное имя - из серии бесплатных, таких сервисов несколько есть.
PanenKov
16.09.2025 19:05А ещё есть caddy, который используется вместо nginx. Он сам запрашивает все сертификаты и сам их обновляет.
JBFW Автор
16.09.2025 19:05Есть. И он работает не точно как nginx, и под него надо переписывать конфиги, непонятно как у него с нагрузкой, балансировкой, перемаршрутизацией запросов, и неплохо бы разобраться как именно "он сам" что-то делает - на это нужно время, это изменение инфраструктуры.
Вообще же, как правило, чем больше разных функций в одной программе - тем хуже, не надёжнее и сложнее в поддержке.
Может caddy исключение из этого правила, но есть сомнения...
Sly_tom_cat
16.09.2025 19:05Есть acme.sh - в нем много вариантов обновления LE сертификатов и для случаев, когда нужно для верификации поднять http/https сервер, скрипт его поднимает сам. Причем тот "сервер" буквально из говна и палок сделан, но большего для верификации домена и не нужно.
DikSoft
У большинства DNS поставщиков есть API с авторизацией.
Для них гораздо проще использовать скрипт, построенный на базе Posh-ACME, запускаемый по расписанию. В скрипт прикручивается и остальная автоматизация, включая установки сертификата, его перепаковки под все разные закидоны (full_chain / стопка файлов), проверки, уведомления, и т.п.
Ваш вариант тоже рабочий. Кому-то будет проще с ним.