SSD Nodes Learn
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-07-24

Як встановити Certbot для nginx на Ubuntu 24.04

Покрокова інструкція встановлення Certbot через apt або snap. Дізнайтеся, чому виникають конфлікти таймерів та як правильно налаштувати Let's Encrypt на Ubuntu.

Встановлення Certbot: apt або snap

В Ubuntu 24.04 sudo apt install certbot python3-certbot-nginx надає робочий Certbot, який видає справжні, публічно довірені сертифікати Let's Encrypt. Документація Certbot рекомендує використовувати snap. Різниця незначна: snap отримує оновлення безпосередньо від розробників, а пакет з репозиторію (archive package) містить версію, що постачалася з LTS, та отримує лише виправлення безпеки.

Оберіть один варіант. Наявність двох копій Certbot призведе до створення двох таймерів оновлення для одного дерева /etc/letsencrypt. Це призведе до помилок через конфлікт процесів.

Шлях через apt:

sudo apt update
sudo apt install certbot python3-certbot-nginx

Це встановить /usr/bin/certbot, плагін nginx, пару certbot.service + certbot.timer та запис /etc/cron.d/certbot, який не виконує жодних дій у systemd.

Шлях через snap:

sudo apt remove certbot python3-certbot-nginx
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Snap містить власний таймер snap.certbot.renew.timer. Видаліть пакет apt перед встановленням snap.

Після встановлення обидва методи працюють однаково. Certbot 2.x за замовчуванням використовує ключі ECDSA (P-256) — використовуйте --key-type rsa лише якщо клієнт не підтримує ECDSA. Усі дані зберігаються в /etc/letsencrypt: archive/ містить фактичні файли ключів та сертифікатів, live/ містить символічні посилання на поточні файли, renewal/ містить по одному конфігураційному файлу на кожен сертифікат, accounts/ містить ваш ключ облікового запису ACME.

Що насправді робить HTTP-01 і чому порт 80 є обов'язковим

HTTP-01 challenge — це механізм зворотного виклику. Ви запитуєте у Let's Encrypt сертифікат для example.com; сервіс визначає ім'я в публічному DNS, відкриває з'єднання на порт 80 за знайденою адресою та запитує http://example.com/.well-known/acme-challenge/<token>. Ваш сервер має відповісти саме тим вмістом токена, який Certbot щойно записав на диск. Це весь механізм. Це призводить до трьох наслідків, які є причиною більшості помилок видачі сертифікатів.

  • Порт 80 має бути доступним з публічного інтернету, а не лише з вашого ноутбука. Правило ufw, security group хмарного провайдера або firewall у консолі VPS, що відкриває лише 443, призведе до помилки видачі та всіх наступних оновлень.
  • DNS вже має вказувати на цей сервер. Сервер перевірки виконує власний пошук ззовні; ваші записи /etc/hosts та кеш браузера для нього не мають значення.
  • Якщо ви публікуєте AAAA-запис, спочатку пробується IPv6. Let's Encrypt повторно намагається підключитися через IPv4, якщо IPv6-з'єднання повністю відхилено. Проте неактуальний AAAA-запис, що вказує на хост, який приймає з'єднання, але віддає інший контент, призведе до критичної помилки.

Перенаправлення (redirects) дозволені: перевірка виконується через HTTP redirect на HTTPS і не враховує, що сертифікат на іншому кінці відсутній, прострочений або самопідписаний. Проте перевірка не почнеться ні на якому іншому порту, окрім 80. Certbot не має реалізації TLS-ALPN-01, тому порада "просто використовуйте 443" не є вирішенням проблеми.

Вибір автентифікатора: --nginx, --webroot, --standalone

--nginx — оптимальний варіант за замовчуванням, якщо nginx вже запущений і обслуговує цей домен. Certbot аналізує конфігурацію, створює тимчасову директорію для challenge, перезавантажує nginx, виконує перевірку та записує TLS-директиви у ваш server block. Робота сервісу не переривається.

sudo certbot --nginx -d example.com -d www.example.com

Для автоматизації на новому сервері:

sudo certbot --nginx \
  -d example.com -d www.example.com \
  --agree-tos -m ops@example.com --no-eff-email \
  --redirect --non-interactive

--webroot підходить, якщо ви не хочете змінювати конфігурацію nginx через Certbot — наприклад, якщо ви генеруєте конфігурацію з шаблону, зберігаєте її в git або розгортаєте через Ansible. Certbot записує лише файл challenge у директорію, яку ви вже обслуговуєте.

sudo certbot certonly --webroot -w /var/www/example.com \
  -d example.com -d www.example.com \
  --deploy-hook "systemctl reload nginx"

--standalone підходить, якщо порт 80 не зайнятий іншими сервісами: поштовим сервером, API, що працює лише через 443, або скриптом першого запуску, який виконується до появи nginx. Certbot самостійно займає порт 80 на кілька секунд. Якщо nginx вже запущений, виникне помилка — зупиніть його перед запуском:

sudo certbot certonly --standalone -d mail.example.com \
  --pre-hook "systemctl stop nginx" \
  --post-hook "systemctl start nginx"

Ці хуки записуються в конфігурацію оновлення сертифіката, тому при автоматичному оновленні процедури зупинки/запуску виконуватимуться автоматично.

Server block, що працює до та після створення сертифіката

Проблема «курки та яйця»: nginx не запускається, якщо ssl_certificate вказує на неіснуючий файл, а Certbot не може виконати перевірку, поки nginx вимкнено. Спочатку запустіть сайт на порту 80.

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/example.com;
    index index.html;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/example.com;
        default_type "text/plain";
        try_files $uri =404;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

Запустіть sudo nginx -t && sudo systemctl reload nginx, перевірте відповіді curl -I http://example.com/ з зовнішнього пристрою, а потім запустіть процес видачі. Після цього:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/example.com;
        default_type "text/plain";
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

Префікс ^~ у локації ACME є необхідним: він не дає блоку return 301 перехоплювати запит на перевірку. Збереження цієї локації на порту 80 забезпечує коректне оновлення сертифікатів після переходу всього сайту на HTTPS.

Синтаксис HTTP/2 залежить від версії nginx; змішування двох форматів призводить до помилки при запуску. Ubuntu 24.04 постачає nginx 1.24, де параметр має бути вбудованим — listen 443 ssl http2;. Debian 13 постачає новішу версію nginx, яка потребує окремої директиви http2 on;. Спочатку перевірте nginx -v.

Вказуйте nginx на live/, а не на archive/. Символічні посилання live/ оновлюються під час кожного перезапуску; використання прямого шляху до archive/ призведе до помилки після закінчення терміну дії сертифіката.

Wildcards означає DNS-01, а DNS-01 означає плагін

Сертифікат wildcard (*.example.com) неможливо перевірити через HTTP-01, оскільки не існує єдиного хостнейму для завантаження файлу. DNS-01 — єдиний доступний шлях: ви підтверджуєте контроль шляхом публікації _acme-challenge.example.com TXT-запису. Для автоматизації Certbot потребує API-credentials вашого DNS-провайдера; саме для цього існують плагіни провайдерів. Повний посібник із отримання wildcard-сертифіката описує механізм TXT-запису та проблему оновлення в ручному режимі; нижче наведено короткий варіант для Cloudflare.

sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare

У репозиторіях apt шлях відрізняється на sudo apt install python3-certbot-dns-cloudflare. Дані для авторизації зберігаються у файлі, доступному лише root:

# /root/.secrets/cloudflare.ini
# then: sudo chmod 600 /root/.secrets/cloudflare.ini
dns_cloudflare_api_token = your_scoped_token_here

Обмежте токен правами на редагування DNS лише для цієї зони. Це ключ до вашого DNS; ставтеся до нього як до ключа.

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  -d example.com -d '*.example.com'

Візьміть wildcard у лапки, щоб shell не виконував globbing. DNS-01 також вирішує проблему, яку неможливо вирішити через HTTP-01: отримання сертифікатів для хостів без відкритого 80-го порту — внутрішніх сервісів, вузлів, доступних лише через self-hosted WireGuard VPN на VPS, або панелей адміністрування на приватному інтерфейсі.

Продовження: 90 днів, таймер та deploy hook

Сертифікати Let's Encrypt діють 90 днів. Certbot запускає оновлення, коли залишається менше 30 днів. Це дає 30-денне вікно, коли помилка оновлення є лише дрібною проблемою, а не повноцінним простоєм. Let's Encrypt більше не надсилає попередження про закінчення терміну дії — ніхто не нагадає вам про це особисто, тому моніторинг тепер лежить на вас.

Перевірте таймер, який постачається з вашою інсталяцією:

systemctl list-timers 'certbot*' 'snap.certbot*'
sudo certbot certificates

certbot renew перевіряє кожен конфігураційний файл у /etc/letsencrypt/renewal/, пропускає все, що не підпадає під 30-денне вікно, і оновлює решту, використовуючи ті самі прапорці, що й під час першого запуску. Саме тому перший запуск є критичним: саме його дані записуються.

Оновлення файлу на диску саме по собі нічого не змінює — nginx продовжує використовувати старий сертифікат із пам'яті, доки не отримає команду на перезавантаження. Налаштуйте deploy hook один раз:

sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/sh
set -e
nginx -t && systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Будь-який виконуваний файл у renewal-hooks/deploy/ запускається після кожного успішного оновлення. Прапорець --deploy-hook виконує ту саму функцію для одного сертифіката, зберігаючи renew_hook = ... у конфігурації оновлення. certbot --nginx виконує перезавантаження за вас; налаштування --webroot та --standalone цього не роблять. Відсутність hook — це причина, чому сайт видає прострочений сертифікат, поки certbot certificates повідомляє про успішне оновлення. Будь-який інший серіал, що зчитує сертифікат під час запуску, потребує такого ж hook — наприклад, контейнеризований додаток, як Nextcloud VPS install with Docker, TLS and backups, також потребує налаштування кроку перезапуску або перезавантаження тут.

Тестування оновлення у реальних умовах

sudo certbot renew --dry-run

Цей процес запускає повну перевірку (challenge) у стейджингу Let's Encrypt: той самий код, ті самі налаштування firewall та DNS, без ризику перевищення лімітів (rate-limit) та без запису даних на диск. Якщо перевірка пройде успішно, автоматичне оновлення через 60 днів також пройде успішно, якщо системні налаштування сервера не зміняться.

Режим dry run не підтверджує спрацювання reload hook — поведінка залежить від версії Certbot. Перевірте цей етап вручну: запустіть скрипт hook безпосередньо, переконайтеся, що systemctl reload nginx завершився успішно, та перевірте sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.

Помилки, з якими ви стикнетеся

Could not bind to IPv4 or IPv6.--standalone, оскільки nginx вже використовує порт 80. Використовуйте --nginx або --webroot, або зупиніть nginx перед запуском. Перевірте, який процес займає порт, за допомогою sudo ss -lntp | grep ':80'.

Timeout during connect (likely firewall problem) — Let's Encrypt не зміг підключитися до порту 80. Перевірте налаштування по черзі: sudo ufw status (відкрийте його за допомогою sudo ufw allow 'Nginx Full'), потім фаєрвол провайдера VPS, потім DNS. Перевірте доступність з іншого сервера: curl -sSv http://example.com/.well-known/acme-challenge/test. Ця ж помилка виникає через застарілий AAAA-запис.

unauthorized :: Invalid response from http://example.com/.well-known/acme-challenge/xyz: 404 — порт 80 доступний, але токен не видається. Запит потрапив у інший server block (перевірте, який саме використовує default_server), або директорія, передана в -w, не є тією, яку обслуговує nginx. Створіть файл у /var/www/example.com/.well-known/acme-challenge/test і спробуйте завантажити його ззовні; якщо ви отримаєте 404, проблема не в сертифікаті.

DNS problem: NXDOMAIN looking up A for example.com — ім'я не резолвиться у публічній мережі. Причина: нові записи, які ще не поширилися, або запис у зоні, яку не обслуговує ваш реєстратор.

too many certificates already issued for: example.com — обмеження частоти запитів (rate limit), яке часто виникає під час циклічної відладки. Let's Encrypt обмежує створення дублікатів сертифікатів (однаковий набір імен) до 5 разів на тиждень, а також дозволяє 50 нових сертифікатів на один зареєстрований домен на тиждень; жоден метод не знімає ці обмеження, окрім очікування. Використовуйте --dry-run для тестування в режимі staging.

nginx: [emerg] cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": No such file or directory — nginx налаштований на сертифікат, який ніколи не видавався або був видалений за допомогою certbot delete. Закоментуйте TLS server block, запустіть nginx, видайте сертифікат, а потім розкоментуйте блок.

open() "/etc/letsencrypt/options-ssl-nginx.conf" failed — цей файл постачається разом із пакетом nginx plugin. На системі certonly без python3-certbot-nginx потрібно або встановити плагін, або замінити рядок include на власні налаштування ssl_protocols та ssl_ciphers.

Управління цим у масштабі

Один сертифікат може містити до 100 імен. Використання одного certbot --nginx -d a.example.com -d b.example.com ... виглядає привабливо, доки застарілий DNS-запис не провалить перевірку, що призведе до відмови всіх інших імен у цьому сертифікаті. Окремі сертифікати для кожного сайту відмовляють незалежно — це саме те, що потрібно на сервері, де хоститься понад кілька ресурсів. Коли сайтів стає багато, ACME-aware front end стає необхідним: reverse proxy Traefik, що запускає кілька додатків через Docker Compose, самостійно запитує та оновлює сертифікати, а Certbot більше не потрібен.

Зробіть повну резервну копію /etc/letsencryptsudo tar -czf letsencrypt-$(date +%F).tar.gz -C /etc letsencrypt — зі збереженням усіх symlinks. У цьому дереві зберігається accounts/, ваш ключ облікового запису ACME, який неможливо відтворити ідентично. Переїзд на новий VPS зводиться до наступного: виконайте rsync дерева з використанням -a, встановіть Certbot, перенаправте DNS і запустіть certbot renew --dry-run перед перемиканням трафіку.

Таймер оновлення не переноситься автоматично при перевстановленні системи або переході на новий LTS. Після будь-якої міграції, відновлення з snapshot або оновлення дистрибутива виконайте systemctl list-timers 'certbot*' та один --dry-run. Якщо цього не зробити, сайт перестане працювати через 89 днів о 3 годині ночі, оскільки сертифікат, який мав оновлюватися автоматично, не оновився.

Все це передбачає наявність машини під вашим контролем з публічною IP-адресою та відкритим портом 80 для всього світу — іншими словами, VPS. Описані механізми однакові для будь-якого з таких серверів.

Ті самі кроки для сертифікатів застосовуються в Apache замість nginx, а якщо публічний сертифікат недоступний, самопідписаний сертифікат на Ubuntu підійде для внутрішніх сервісів.

FAQ

Чи потрібно відкривати порт 80, якщо сайт працює тільки через HTTPS?

Так, для проходження перевірки HTTP-01. Let's Encrypt завжди починає запит на валідацію через порт 80. Certbot не має реалізації TLS-ALPN-01, тому брандмауер, який відкриває лише 443, заблокує як перше отримання сертифіката, так і всі наступні автоматичні оновлення. Перенаправлення (redirect) з порту 80 на HTTPS є допустимим — валідація пройде через нього. Єдиний спосіб повністю уникнути використання порту 80 — це метод DNS-01 за допомогою плагіна провайдера.

apt чи snap — який Certbot обрати для nginx на Ubuntu 24.04?

Використовуйте apt. sudo apt install certbot python3-certbot-nginx надає Certbot 2.9.0 на Ubuntu 24.04, що є достатньо актуальним для всіх інструкцій у цьому посібнику. Ця версія отримує патчі безпеки через unattended-upgrades і не потребує snapd. Обирайте snap лише якщо вам негайно потрібна найновіша версія або DNS-плагін, доступний виключно як snap. У будь-якому разі оберіть лише один варіант: дві інсталяції призведуть до того, що два таймери оновлення будуть вказувати на одне й те саме дерево /etc/letsencrypt, і помилка в одному з них призведе до збою.

Чи може Certbot видати wildcard-сертифікат для nginx?

Тільки через DNS-01. Wildcard-сертифікат на кшталт *.example.com не має єдиного хостнейму для завантаження файлу перевірки, тому методи --nginx, --webroot та --standalone не підходять. Встановіть плагін для вашого DNS-провайдера, додайте обмежений за правами доступу API-токен у файл облікових даних для root-користувача та запустіть certbot certonly --dns-cloudflare -d example.com -d '*.example.com', взявши wildcard у лапки, щоб уникнути розгортання (globbing) оболонкою shell.

Чому nginx продовжує використовувати старий сертифікат після успішного оновлення?

nginx зберігає сертифікат у пам'яті та не помічає новий файл на диску до моменту перезавантаження конфігурації. certbot --nginx виконує перезавантаження автоматично, але команди --webroot та --standalone цього не роблять, тому оновлення може завершитися успішно, поки браузер все ще бачить сертифікат, термін дії якого закінчується. Помістіть виконуваний скрипт, що запускає nginx -t && systemctl reload nginx, у директорію /etc/letsencrypt/renewal-hooks/deploy/, щоб він виконувався після кожного успішного оновлення.

Чи гарантує certbot renew --dry-run успішне оновлення?

Майже. Ця команда виконує реальну перевірку у стейджинг-середовищі — з тим самим брандмауером, DNS та шляхом виконання коду, — але без лімітів запитів (rate-limit) та без запису на диск. Успішний результат означає, що мережева частина налаштована правильно. Проте це не гарантує надійну роботу вашого скрипта розгортання (deploy hook). Перевірте це окремо: запустіть скрипт вручну та перевірте sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.