Допустим, вы не девопс. Вы — вполне себе фронтендер, бэкендер, может даже мобильщик. Но вот беда: у вас сервер, и ему нужен SSL. А девопс уехал в отпуск. Или вообще не нанят. И вот вы стоите, глядите на терминал и думаете: «Ну всё, теперь я — DevOps». ?

Пугаться не стоит. Сегодня расскажу, как быстро и автоматически настроить SSL-сертификаты от Let’s Encrypt с помощью Certbot на Ubuntu. С шутками, примерами и bash-магией.


? Зачем нужен Certbot и Let’s Encrypt?

Let’s Encrypt — это бесплатный центр сертификации. Он позволяет выпускать SSL-сертификаты для HTTPS. Certbot — это утилита для автоматического получения и обновления этих сертификатов.

Комбо для тех, кто не хочет возиться с ручной генерацией ключей и походами в коммерческие CA.


? Установка Certbot

sudo apt update
sudo apt install certbot

Важно: Certbot нужно запускать на том же сервере, для которого вы хотите выпустить сертификат.


? Получение сертификата (и вывод информации о текущих сертификатах)

sudo certbot certonly --standalone -d project.com -d www.project.com
sudo certbot certificates
  • --standalone означает, что Certbot временно поднимет собственный сервер на 80 порту для валидации домена.

  • Проверьте, что порт 80 не занят! Иначе ничего не заработает.

    Если там ваш Nginx или Docker — остановите его на время выполнения команды:

sudo systemctl stop nginx

Альтернатива: можно использовать плагин webroot — он не требует остановки сервиса и просто создаёт специальный файл в директории сайта.

Подробнее про плагины — в официальной документации.


⏱ Автоматическое обновление через systemd

После установки Certbot автоматически добавляет systemd-таймер:

systemctl list-timers | grep certbot

Пример вывода:

Mon 2025-03-10 03:12:00 UTC  10h left  Mon 2025-03-09 03:12:00 UTC  certbot.timer  certbot.service

Проверить, что автообновление работает:

sudo certbot renew --dry-run

Если всё хорошо:

Certbot dry-run was successful.

Логи последних обновлений:

journalctl -u certbot.service --no-pager --since "2 days ago"

Напоминание: Certbot обновляет сертификаты только если до их окончания < 30 дней.


?️ Альтернатива: обновление через Cron

Иногда systemd-таймеры неудобны, особенно если вы настраиваете всё через Ansible или shell-скрипты. В этом случае можно использовать Cron.

  1. Отключаем таймер:

sudo systemctl stop certbot.timer
sudo systemctl disable certbot.timer
  1. Добавляем Cron-задачу:

sudo crontab -e

Пример:

0 0 1 * * /usr/bin/certbot renew --standalone --quiet

Чтобы узнать точный путь к certbot, используйте:

which certbot

⚙️ Хуки для перезапуска сервисов

Certbot умеет выполнять действия до, после или только при успешном обновлении сертификата. Это удобно, если нужно остановить сервис, скопировать сертификаты или перезапустить сервер.

# /etc/letsencrypt/renewal/project.com.conf

pre_hook = systemctl stop my-project.service
deploy_hook = systemctl reload my-project.service
post_hook = systemctl start my-project.service

?️ Скрипт на все случаи жизни

Вместо описания всего в кроне, можно создать bash-скрипт, который будет:

  1. Останавливать сервис

  2. Обновлять сертификаты

  3. Копировать файлы в нужное место

  4. Ставить права

  5. Запускать сервис обратно

#!/bin/bash

APP_PATH="/home/projects/project"
DOMAIN="project.com"

FULL_CHAIN_SRC="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
PRIVATE_KEY_SRC="/etc/letsencrypt/live/${DOMAIN}/privkey.pem"
FULL_CHAIN_DIST="${APP_PATH}/volumes/etc/ssl/certs/project_com.full.crt"
PRIVATE_KEY_DIST="${APP_PATH}/volumes/etc/ssl/private/project_com.key"

echo "Starting script execution: $(date "+%Y-%m-%d %H:%M:%S")"

echo "Stopping the service..."
systemctl stop my-project.service

echo "Renewing the certificates..."
/usr/bin/certbot renew --standalone --quiet
/usr/bin/certbot certificates

echo "Copying the certificates to the project..."
cp -f "$FULL_CHAIN_SRC" "$FULL_CHAIN_DIST"
cp -f "$PRIVATE_KEY_SRC" "$PRIVATE_KEY_DIST"

echo "Setting correct permissions for the certificates..."
chmod 644 "$FULL_CHAIN_DIST"
chmod 644 "$PRIVATE_KEY_DIST"

echo "Running the service..."
systemctl start my-project.service

echo "End of script execution: $(date "+%Y-%m-%d %H:%M:%S")"

А в кроне вызываем его так:

0 0 1 * * sh /home/projects/project/cert-renew.sh >> /var/log/project-cert-renew.log 2>&1

? Заключение

Иногда даже разработчику приходится немного быть девопсом. Главное — не бояться терминала и знать, где гуглить. А ещё — не забыть проверить через полгода, что автообновление всё ещё работает. ?

Если вы нашли ошибку или хотите поделиться своим способом автоматизации — велком в комментарии!

Комментарии (12)


  1. ki11j0y
    13.05.2025 19:23

    Есть acme.sh и выдача сертификатов без перезагрузки сервиса.


  1. NotSlow
    13.05.2025 19:23

    Если "фронтендер, бэкендер, может даже мобильщик" заходит на сервер и под root запускает что-то из статей в интернетах или по советам gpt, то...

    Скрытый текст

    Интересно, многие ли заметили, что с мая let's encrypt завязал с OCSP. И теперь кто использовал в nginx ssl_stapling столкнутся с:


  1. pae174
    13.05.2025 19:23

    он не требует остановки сервиса и просто создаёт специальный файл в директории сайта

    Он создает файл в директории .well-known (имя директории начинается с точки). У веб серверов часто запрещено отдавать директории и файлы с именами, ничинающимися с точки - это делается на случай когда в директории с сайтом есть всякие там .git, .svn, .htaccess и тому подобные служебные штуки. Так что надо заблаговременно проверить конфиг вашего Apache или Nginx на предмет таких запретов.

    Кроме того для получения wildcard сертификата необходимо не только размещать файл но еще и добавлять запись в DNS.


    1. ki11j0y
      13.05.2025 19:23

      Достаточно просто разместить txt запись без .well-known для wildcard

      Метод называется dns challenge, а ещё есть dns alias mode когда для проверки используется другой домен, тогда в случае слива токена ни чего не произойдёт с основным доменом.


    1. ki11j0y
      13.05.2025 19:23

      В случае  stateless режима acme и например haproxy, то ни чего не создаётся, не обязательно иметь даже веб сервер за обратным прокси для получения сертификатов


  1. RomanKu
    13.05.2025 19:23

    Для пет проекта сойдет, в продакшин такое выпускать - сомнительно, очень сомнительньно.

    За долгие годы работы с certbot убедился, что не все так просто с ним и приходится изворачиваться местами, новичкам (не смотря на то, что этот проект ориентирован на простоту) не всегда удается сделать нормально, а при запихивании во всякие докеры легче не становится.

    Для фронтендеров и бекендеров, не девопсов всегда рекомендую Nginx Proxy Manager - это реверс прокси с cert bot из коробки. Если не надо перегонять петабайты данных, то проще поставить NPN в одном месте, а потом в нем уже прописать нужные сервисы. Как минимум

    1. Меньше проблем с сертификатами

    2. Не будет даунтайма на время перевыпуска и проверки сертификатов.

    С этим скриптом получается, что сервис будет останавливаться каждый раз перед проверкой сертификата, даже если время перевыпуска еще не наступило, если упадет во время работы, то сервис может и не подняться


  1. FSA
    13.05.2025 19:23

    Из всей статьи разве что может быть полезно для кого-то информация про хуки. Всё остальное вообще не имеет никакого смысла, ибо просто ставишь certbot, даёшь команду на получение сертификата, пользуешься. Ничего вообще трогать не надо ни в Ubuntu, ни в Debian, ни в Fedora.

    А вот чего реально не хватает в статье - информации о челленджах по получение сертификата. Есть про webroot, есть про standalone, но совершенно нет информации о получении сертификата через dns, которые позволяют получить в том числе и в wildcard сертификаты, не требуют остановки веб-сервера и вообще установку certbot и получение нужного сертификата можно хоть через ansible сделать.

    А вот вся эта маета с настройкой таймеров и крона нужна для acme.sh и lego.


  1. Sayyat
    13.05.2025 19:23

    Интересно, я когда-то настроил через docker. Так будет быстрее наверное.


  1. Lazhu
    13.05.2025 19:23

    как-то все чрезмерно сложно у вас

    cat /usr/local/etc/letsencrypt/renewal/mydomain.ru.conf
    # renew_before_expiry = 30 days
    version = 2.3.0
    archive_dir = /usr/local/etc/letsencrypt/archive/mydomain.ru
    cert = /usr/local/etc/letsencrypt/live/mydomain.ru/cert.pem
    privkey = /usr/local/etc/letsencrypt/live/mydomain.ru/privkey.pem
    chain = /usr/local/etc/letsencrypt/live/mydomain.ru/chain.pem
    fullchain = /usr/local/etc/letsencrypt/live/mydomain.ru/fullchain.pem
    
    # Options used in the renewal process
    [renewalparams]
    account = acc8b9bfe080d37449336cdgh6048b5d
    authenticator = webroot
    webroot_path = /usr/local/www/mydomain.ru,
    server = https://acme-v02.api.letsencrypt.org/directory
    key_type = ecdsa
    post_hook = /root/bin/certbot-posthook.sh
    [[webroot_map]]
    mydomain.ru = /usr/local/www/mydomain.ru
    cat /root/bin/certbot-posthook.sh
    #!/bin/sh
    postmap -F hash:/usr/local/etc/postfix/vmail_ssl.map
    service postfix reload
    service dovecot reload
    apachectl graceful


  1. dgohn404
    13.05.2025 19:23

    а, certbot webroot чем не метод


  1. 1nt
    13.05.2025 19:23

    Пока админ в отпуске, откроем 80 порт или выключим все что на нем висит или bind9 настроим. Кстати я думал уже 80 порт все закрывают.


    1. DaemonGloom
      13.05.2025 19:23

      80 порт обычно доступен, но отдаёт переадресацию на https/443. Ну и для прохождения челленджа, если dns способ невозможен.