SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-28

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

Встановіть Certbot через apt або snap, виконайте certbot --nginx і отримайте сертифікат Let's Encrypt. Дізнайтеся про apt, snap та тайм-аут порту 80.

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

В Ubuntu 24.04 команда sudo apt install certbot python3-certbot-nginx встановлює працездатний Certbot, який видає справжні сертифікати Let's Encrypt, довірені публічними центрами сертифікації. В офіційній документації Certbot рекомендовано використовувати snap. Різниця невелика: snap відстежує upstream-релізи, а пакет з архіву відповідає версії, що постачалася з 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 — це callback. Ви запитуєте в 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-запис, спрямований на хост, який приймає з’єднання та повертає інший вміст, призводить до помилки перевірки.

Редиректи дозволені: перевірка переходить за HTTP-редиректом на HTTPS і не враховує, що сертифікат на іншому кінці відсутній, прострочений або самопідписаний. Але перевірка не починається з іншого порту, крім 80. Certbot не реалізує TLS-ALPN-01, тому варіант «просто використати 443» не є вирішенням.

Вибір authenticator: --nginx, --webroot, --standalone

--nginx — правильний варіант за замовчуванням, якщо nginx уже запущений і обслуговує домен. Certbot аналізує конфігурацію, додає тимчасову location для 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 підходить, якщо ви не хочете, щоб Certbot змінював конфігурацію nginx, яку ви генеруєте з шаблону, зберігаєте в 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 не прослуховується жодним процесом: наприклад, це mail server, API, який працює лише через 443, або скрипт першого запуску, що виконується до запуску nginx. Certbot сам прив’язується до порту 80 на кілька секунд. Якщо nginx запущений, команда завершиться помилкою. Зупиніть його на час виконання:

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

Ці hook-команди записуються в конфігурацію поновлення сертифіката, тому під час автоматичного поновлення nginx також буде зупинено та знову запущено без втручання.

Блок server, який працює до та після появи сертифіката

Проблема залежності: 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-only.

Обидва наведені вище блоки передають файли з диска. Якщо nginx натомість працює як reverse proxy перед застосунком, location / стає блоком proxy_pass. У матеріалі блок server reverse proxy, рядок за рядком описано заголовки, потрібні цьому застосунку. Локація ACME та директиви TLS залишаються без змін.

Синтаксис 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, оскільки немає одного hostname, з якого можна отримати файл. DNS-01 — єдиний варіант: ви підтверджуєте контроль, опублікувавши TXT-запис _acme-challenge.example.com. Certbot потребує API-облікових даних вашого 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 не розгорнув його як шаблон. DNS-01 також вирішує проблему, яку не може вирішити HTTP-01: він дає змогу отримувати сертифікати для хостів без публічного порту 80, внутрішнього сервісу, сервера, доступного лише через self-hosted WireGuard VPN на VPS, або панелі адміністрування на приватному інтерфейсі.

Поновлення: 90 днів, timer і deploy hook

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

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

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

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

Поновлення файлу на диску саме по собі нічого не змінює. nginx продовжує використовувати старий сертифікат із пам’яті, доки не отримає команду на reload. Один раз налаштуйте 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/. Flag --deploy-hook виконує те саме завдання для одного сертифіката та зберігає renew_hook = ... у його конфігурації поновлення. certbot --nginx виконує reload автоматично; для конфігурацій із --webroot і --standalone це не відбувається. Відсутній hook — саме тому сайт може надавати прострочений сертифікат, тоді як certbot certificates повідомляє про успішне поновлення. Будь-який інший компонент, який зчитує сертифікат під час запуску, також потребує такого hook. Для containerised застосунку, наприклад інсталяції Nextcloud VPS із Docker, TLS і резервними копіями, тут також потрібно налаштувати власний restart або reload.

Перевірка поновлення в реальному режимі

sudo certbot renew --dry-run

Ця команда виконує повну перевірку через середовище staging Let's Encrypt: використовується той самий шлях виконання, той самий firewall і той самий DNS; ліміти запитів не витрачаються, а на диск нічого не записується. Якщо перевірка проходить сьогодні, автоматичне поновлення через 60 днів також має пройти, якщо конфігурація сервера до того часу не зміниться.

Пробний запуск не доводить, що hook для reload спрацьовує, оскільки його поведінка залежить від версії 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'), потім firewall самого 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 доступний, але token не обслуговується. Запит потрапив в інший 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, ім’я не розпізнається публічно. Це може бути новий запис, який ще не поширився, або запис у зоні, яку ваш registrar не обслуговує.

too many certificates already issued for: example.com, це обмеження частоти запитів. Саме з ним часто стикаються під час циклічного налагодження. Let's Encrypt обмежує кількість duplicate-сертифікатів для того самого точного набору імен до 5 на тиждень. Окремо дозволено отримувати 50 нових сертифікатів для зареєстрованого домену на тиждень. Зняти ці обмеження можна лише з часом. Виконуйте налагодження в staging за допомогою --dry-run.

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

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

Керування в масштабі

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

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

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

Усе це передбачає, що ви керуєте сервером із публічною IP-адресою та відкритим для всього світу портом 80. Іншими словами, йдеться про VPS. Наведені вище процедури однакові для будь-якого такого сервера.

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

FAQ

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

Так, для перевірки HTTP-01. Let’s Encrypt завжди починає запит перевірки на порту 80, а Certbot не має реалізації TLS-ALPN-01. Тому firewall, який відкриває лише 443, блокує і перший випуск сертифіката, і кожне автоматичне поновлення після нього. Редирект із порту 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. Цієї версії достатньо для всього, що описано в цьому посібнику. Вона отримує security patches через unattended-upgrades і не потребує snapd. Обирайте snap лише тоді, коли вам негайно потрібен найновіший реліз або DNS-плагін, який поширюється тільки як snap. У будь-якому разі встановлюйте лише один варіант: два встановлення означають два таймери поновлення, спрямовані до одного дерева /etc/letsencrypt, і саме забутий варіант зрештою спричинить проблему.

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

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

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

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

Чи доводить certbot renew --dry-run, що поновлення працюватиме?

Переважно так. Команда виконує справжню перевірку в staging-середовищі, використовуючи той самий firewall, той самий DNS і той самий шлях виконання коду. Вона не використовує ліміти частоти запитів і нічого не записує на диск. Тому успішний результат означає, що мережева частина працює правильно. Однак команда не гарантує, що deploy hook буде виконано. Перевірте це окремо: запустіть скрипт hook вручну й перевірте sudo grep renew_hook /etc/letsencrypt/renewal/example.com.conf.