Ви виконали certbot renew. Він повідомив «success». Моніторинг все ще кричить «сертифікат закінчується за 2 дні».
Ви перевіряєте файлову систему і новий сертифікат на місці. Та браузери й досі бачать старий — іноді навіть із тієї ж машини.
Це не містика. Це набір дуже передбачуваних режимів помилок: неправильний шлях, неправильний серверний блок, відсутність перезавантаження,
балансувальник навантаження, який виконує TLS перед вами, або застарілий процес, який ніколи не відкривав файли заново. На Ubuntu 24.04 налаштування за замовчуванням
розумні, але навколишня екосистема (Snap, systemd, кілька інстансів Nginx, контейнери) робить легкою помилку з упевненістю.
Що насправді відбувається, коли «оновлено» ≠ «віддається»
Працюють дві окремі системи:
- Видача/оновлення сертифікатів: ACME-клієнт (зазвичай Certbot, іноді lego/acme.sh) записує нові файли на диск.
- Обслуговування TLS: Nginx читає файли сертифікатів у пам’ять при завантаженні конфігурації (старт або reload). Він не «бачить» автоматично нові байти на диску.
Тому режим помилки простий: оновлення пройшло успішно, але стек обслуговування не перемкнувся.
Хитрість у тому, що «стек обслуговування» може бути не тим процесом, який ви собі уявляєте. Це може бути:
Nginx на хості, Nginx у контейнері, Nginx у chroot, другий інстанс Nginx, зворотній проксі зверху або хмарний балансувальник, що завершує TLS ще до того, як трафік потрапляє до Nginx.
Ще одна тонкість: іноді Nginx перезавантажується правильно, але все одно віддає «неправильний» сертифікат через вибір блоків за SNI.
Це поширено, якщо у вас є сервер за замовчуванням, wildcard-сертифікати або універсальний блок, залишений автоматизацією.
Ваша мета — не «оновити сертифікат». Це легка частина. Ваша мета: довести, який процес відповідає за TLS для конкретного імені хоста, і довести, які файли він завантажив.
Жарт №1: Сертифікати як молоко — свіжість важлива, але ніхто не хоче бути тим, хто нюхає їх в продакшні о 2:00.
Швидкий план діагностики (перший/другий/третій)
Перший: підтвердьте, що бачать клієнти
- З машини поза вашою мережею (або використовуючи публічний зонд) перевірте представлені сертифікати для конкретного імені хоста.
- Запишіть видавця, серійний номер та дати notBefore/notAfter.
- Якщо сертифікат старий, не чіпайте Certbot одразу. Сервер віддає старі байти; оновлення може вже бути в порядку.
Другий: встановіть, хто завершує TLS
- Чи порт 443 на хості справді належить Nginx?
- Чи є балансувальник, CDN, WAF або контролер Ingress, що робить TLS перед Nginx?
- Чи є більше одного Nginx (хост + контейнер)?
Третій: зіставте конфіг Nginx → шлях до сертифікату → файл на диску → запущений процес
- Знайдіть
serverблок, що відповідає SNI-імені хоста. - Перевірте шляхи в
ssl_certificateіssl_certificate_key. - Перевірте, чи це посилання Let’s Encrypt
live/або «закріплено» наarchive/. - Перезавантажте Nginx і повторно перевірте зовні.
- Якщо reload не змінює подачу, ви перезавантажуєте неправильний Nginx або неправильну конфігурацію.
Це порядок пошуку вузького місця. Починайте з того, що бачать користувачі, потім рухайтесь всередину. Не починайте з перегляду логів Certbot.
Саме так годину доводять неправильну річ.
Цікавi факти та контекст (чому ця проблема повторюється)
- Факт 1: Nginx не читає сертифікати автоматично заново з диска. Він завантажує їх при старті та при
reload(грейсфул перезавантаження конфігурації). - Факт 2: Сертифікати Let’s Encrypt мають короткий термін життя (зазвичай 90 днів), це зроблено навмисно щоб зменшити ризик компрометації ключа.
- Факт 3: Certbot підтримує дві директорії:
/etc/letsencrypt/archive(версійовані файли) і/etc/letsencrypt/live(символьні посилання на «поточні» файли). - Факт 4: Досить поширений інцидент: «оновлення пройшло успішно, але reload зазнав невдачі». Лог оновлення каже OK; Nginx продовжує віддавати старий сертифікат днями.
- Факт 5: На ранніх етапах TLS деякі сервери вимагали повних рестартів при зміні сертифікатів; грейсфул reload став практичною функцією надійності, а не лише зручністю.
- Факт 6: SNI (Server Name Indication) дозволяє одному IP обслуговувати кілька сертифікатів. Якщо вибір SNI потрапляє в інший серверний блок, ви отримаєте неправильно сертифікат, навіть якщо правильний сертифікат існує.
- Факт 7: Прийняття Snap-пакетів Certbot в Ubuntu змінило місця файлів для логів і іноді змінювало, як запускаються хук-скрипти при оновленні, особливо при змішуванні встановлень apt і snap.
- Факт 8: OCSP stapling може ускладнити відладку: клієнти можуть кешувати або відображати статус stapling окремо від ланцюжка сертифікатів, тому «виглядає неправильно» не обов’язково про файл сертифікату.
Основні причини: звідки насправді береться старий сертифікат
1) Nginx ніколи не перезавантажувався (або reload зазнав невдачі)
Certbot може оновити без перезапуску нічого. Nginx продовжує працювати і віддавати те, що був завантажив минулого тижня.
Якщо у вас є deploy-hook, який має перезавантажувати Nginx, він може бути не налаштований, не запускатися або падати.
Ще гірше: nginx -s reload може вийти успішно, але ви перезавантажили інший бінар або інший інстанс, ніж той, що слухає 443.
2) Nginx вказує на неправильний шлях до файлу
Правильний шаблон — посилатися на /etc/letsencrypt/live/yourname/fullchain.pem і privkey.pem.
Якщо хтось захардкодив /etc/letsencrypt/archive/yourname/fullchain2.pem, він ніколи не оновиться автоматично.
Це працюватиме, доки не перестане. Це класичний випадок «працює до наступної ротації».
3) Обраний неправильний серверний блок (SNI mismatch)
Можливо, правильний сертифікат у одному серверному блоці, а дефолтний серверний блок містить застарілий сертифікат.
Клієнти, що заходять на example.com, отримують правильний сертифікат; клієнти на www.example.com або API-хост отримують дефолтний.
Або ваш перевірочник здоров’я використовує IP-адресу і не відправляє SNI, тому він завжди потрапляє в дефолт. Тоді ви «вирішуєте» не ту проблему.
4) TLS завершується десь іще
Якщо ви використовуєте хмарний балансувальник, CDN, зворотній проксі або Kubernetes ingress, Nginx може взагалі не обслуговувати TLS.
Оновлення на бекенді не має значення; фронт-двері все ще мають старий сертифікат.
Найдорожчі інциденти — ті, де всі дебажать неправильний шар з великим ентузіазмом.
5) Кілька інстансів Nginx, контейнери або різні порти
Ubuntu 24.04 без проблем може запускати:
Nginx на хості (systemd), Nginx у Docker (compose) і контролер ingress (Kubernetes).
Якщо два процеси слухають 443 на різних інтерфейсах (або один на хост-мережі, інший за NAT), ви можете цілий день «перезавантажувати» неправильний.
6) Проблеми з правами або форматом ключа
Certbot може оновити, але записати ключі з правами, які Nginx не може прочитати (менш поширено з типовими шляхами Let’s Encrypt, частіше з кастомними хуками або скопійованими файлами).
Або ви перейшли з RSA на ECDSA, змінили імена файлів і забули оновити конфіг Nginx. Тоді reload зазнає невдачі і Nginx продовжує тримати стару конфігурацію в пам’яті.
Практичні завдання: команди, виводи та рішення (12+)
Ось перевірки, які я справді запускаю, коли продакшн каже «старий сертифікат». Кожне завдання включає:
команду, що означає вивід, і рішення, яке ви приймаєте.
Завдання 1: Перевірте поданий сертифікат зовні (SNI увімкнено)
cr0x@server:~$ openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates -serial
subject=CN = example.com
issuer=C = US, O = Let's Encrypt, CN = R11
notBefore=Dec 1 00:12:34 2025 GMT
notAfter=Feb 29 00:12:33 2026 GMT
serial=03A1B2C3D4E5F6
Значення: Це те, що бачать клієнти. Поле notAfter показує, чи воно старе.
Рішення: Якщо це ще старий термін, дійте далі. Якщо воно нове, ваш моніторинг може перевіряти інше ім’я хоста або кінцеву точку.
Завдання 2: Перевірка подачі сертифікату без SNI (поведінка сервера за замовчуванням)
cr0x@server:~$ openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null | openssl x509 -noout -subject -dates
subject=CN = default.invalid
notBefore=Sep 2 10:00:00 2025 GMT
notAfter=Dec 1 10:00:00 2025 GMT
Значення: Без SNI Nginx обирає сервер за замовчуванням для цього IP:port.
Рішення: Якщо сертифікат за замовчуванням застарів, виправте дефолтний серверний блок також або налаштуйте клієнтів/health checks щоб відправляли SNI.
Завдання 3: Визначте, який процес слухає 443
cr0x@server:~$ sudo ss -ltnp | grep ':443 '
LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=2147,fd=6),("nginx",pid=2146,fd=6))
Значення: Ви бачите, який бінар володіє сокетом.
Рішення: Якщо це не Nginx (або не той, який ви очікуєте), зупиніться і відслідкуйте цей процес. Не перезавантажуйте не той процес.
Завдання 4: Переконайтесь, що ви перезавантажуєте саме той Nginx, що працює
cr0x@server:~$ ps -fp 2147
UID PID PPID C STIME TTY TIME CMD
root 2147 1 0 Dec28 ? 00:00:02 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
Значення: Підтверджує шлях (/usr/sbin/nginx) і що systemd ймовірно ним керує.
Рішення: Використовуйте systemctl reload nginx для цього екземпляра; не запускайте інший бінар з образу контейнера.
Завдання 5: Перевірка конфігурації Nginx перед перезавантаженням
cr0x@server:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Значення: Reload ймовірно пройде успішно. Якщо це падає, Nginx відмовиться завантажити нові шляхи/сертифікати.
Рішення: Спочатку виправте помилки конфігурації. Якщо nginx -t неуспішний, «reload» не оновить сертифікати.
Завдання 6: Перезавантажте Nginx та підтвердіть, що systemd прийняв
cr0x@server:~$ sudo systemctl reload nginx
cr0x@server:~$ systemctl status nginx --no-pager -l
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Sun 2025-12-28 09:10:12 UTC; 1 day 3h ago
Docs: man:nginx(8)
Process: 33910 ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload (code=exited, status=0/SUCCESS)
Значення: Reload виконався і завершився успішно.
Рішення: Заново перевірте подачу сертифікату зовні. Якщо нічого не змінилось, ви дивитесь на неправильний TLS-термінатор або неправильний серверний блок.
Завдання 7: Знайдіть, який серверний блок відповідає вашому імені хоста
cr0x@server:~$ sudo nginx -T 2>/dev/null | grep -nE 'server_name|listen 443|ssl_certificate'
415: listen 443 ssl http2;
416: server_name example.com www.example.com;
432: ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
433: ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
601: listen 443 ssl;
602: server_name _;
612: ssl_certificate /etc/ssl/certs/old-default.pem;
613: ssl_certificate_key /etc/ssl/private/old-default.key;
Значення: Маєте принаймні два TLS серверні блоки: один правильний, один дефолтний зі старим сертифікатом.
Рішення: Оновіть дефолтний блок (або видаліть його), якщо клієнти можуть потрапити на нього. Також переконайтесь, що кожне ім’я хоста явно вказане в server_name.
Завдання 8: Перевірте, що симвпосилання live/ вказують на найновіші файли
cr0x@server:~$ sudo ls -l /etc/letsencrypt/live/example.com/
total 4
-rw-r--r-- 1 root root 692 Sep 2 10:00 README
lrwxrwxrwx 1 root root 42 Dec 28 09:05 cert.pem -> ../../archive/example.com/cert12.pem
lrwxrwxrwx 1 root root 43 Dec 28 09:05 chain.pem -> ../../archive/example.com/chain12.pem
lrwxrwxrwx 1 root root 47 Dec 28 09:05 fullchain.pem -> ../../archive/example.com/fullchain12.pem
lrwxrwxrwx 1 root root 45 Dec 28 09:05 privkey.pem -> ../../archive/example.com/privkey12.pem
Значення: Nginx повинен посилатися на ці симвпосилання. Certbot обертає цільові файли.
Рішення: Якщо Nginx вказує безпосередньо на archive/, змініть на live/, щоб майбутні оновлення не вимагали ручних змін.
Завдання 9: Перегляньте дати сертифікатів на диску (що саме створило оновлення)
cr0x@server:~$ sudo openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -dates -issuer -subject
notBefore=Dec 28 09:05:11 2025 GMT
notAfter=Mar 28 09:05:10 2026 GMT
issuer=C = US, O = Let's Encrypt, CN = R11
subject=CN = example.com
Значення: Файл на диску новий.
Рішення: Якщо диск новий, а віддається старий — проблема в reload/SNI/TLS-термінаторі, а не в оновленні.
Завдання 10: Перевірте історію оновлень Certbot і чи виконувався deploy hook
cr0x@server:~$ sudo grep -R "Deploying certificate" -n /var/log/letsencrypt/letsencrypt.log | tail -n 3
2025-12-28 09:05:12,345:INFO:Deploying certificate to /etc/letsencrypt/live/example.com/fullchain.pem
2025-12-28 09:05:12,346:INFO:Deploying key to /etc/letsencrypt/live/example.com/privkey.pem
2025-12-28 09:05:12,900:INFO:Running deploy-hook command: systemctl reload nginx
Значення: Certbot оновив сертифікат і намагався виконати reload.
Рішення: Якщо немає запису про deploy-hook, додайте його. Якщо він є — перевірте, чи успішно він пройшов у журналі systemd.
Завдання 11: Перевірте таймер Certbot (планування systemd в Ubuntu 24.04)
cr0x@server:~$ systemctl list-timers --all | grep -E 'certbot|letsencrypt'
Sun 2025-12-29 06:18:00 UTC 10h left Sat 2025-12-28 06:18:01 UTC 13h ago snap.certbot.renew.timer snap.certbot.renew.service
Значення: Оновлення заплановано (тут через unit Snap).
Рішення: Якщо таймера немає — оновлення не відбуватиметься автоматично. Якщо таймер є, але ви використовували apt certbot, може бути дві конкуретуючі установки — оберіть одну.
Завдання 12: Підтвердіть, який Certbot ви використовуєте (Snap vs apt), щоб уникнути роздвоєння
cr0x@server:~$ which certbot
/snap/bin/certbot
cr0x@server:~$ snap list certbot
Name Version Rev Tracking Publisher Notes
certbot 2.11.0 3741 latest/stable certbot* classic
Значення: Ви використовуєте Snap Certbot.
Рішення: Переконайтесь, що всі хуки, логи та очікування відповідають пакету Snap. Уникайте змішування з apt-встановленням Certbot, якщо вам подобається судова археологія.
Завдання 13: Дізнайтесь, чи стоїте ви за балансувальником або проксі, що завершує TLS
cr0x@server:~$ curl -sI https://example.com | grep -iE 'server:|via:|x-forwarded|cf-|x-amz'
server: cloud-proxy
via: 1.1 edge-gw
x-forwarded-proto: https
Значення: Заголовки натякають на шар проксі. Це не доказ, але сильний запах проблеми.
Рішення: Перевірте DNS і мережевий шлях. Якщо TLS термінується зверху — оновлюйте сертифікат там, а не на Nginx.
Завдання 14: Перевірте журнали помилок Nginx для невдач при читанні сертифікатів або reload
cr0x@server:~$ sudo tail -n 30 /var/log/nginx/error.log
2025/12/28 09:05:13 [notice] 2147#2147: signal process started
2025/12/28 09:05:13 [emerg] 2147#2147: cannot load certificate "/etc/letsencrypt/live/example.com/fullchain.pem": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory)
Значення: Спроба reload була, але не вдалась прочитати файл. Nginx залишить стару конфігурацію активною.
Рішення: Виправте шлях до файлу, права або обмеження SELinux/AppArmor (AppArmor частіше на Ubuntu). Потім перезавантажте знову.
Завдання 15: Доведіть, який файл сертифікату відкритий у робочому процесі Nginx
cr0x@server:~$ sudo lsof -p 2147 | grep -E 'fullchain|cert\.pem|privkey' | head
nginx 2147 root mem REG 252,0 4231 131072 /etc/letsencrypt/live/example.com/fullchain.pem
nginx 2147 root mem REG 252,0 1704 131073 /etc/letsencrypt/live/example.com/privkey.pem
Значення: Це найближче до «що Nginx завантажив» з погляду ОС.
Рішення: Якщо воно все ще вказує на старий файл з archive або інший домен — виправте конфіг і перезавантажте. Якщо там правильно, а клієнти бачать старе — TLS завершується десь іще.
Завдання 16: Підтвердіть, що ваше ім’я хоста резолвиться на машину, яку ви дебажите
cr0x@server:~$ dig +short A example.com
203.0.113.10
cr0x@server:~$ ip -brief address show | awk '{print $1,$3}'
lo 127.0.0.1/8
eth0 203.0.113.10/24
Значення: DNS A-запис відповідає IP хоста.
Рішення: Якщо DNS вказує в інше місце (або ви за anycast/LB), ви дебагуєте не ту машину. Це трапляється частіше, ніж усі признаються.
Три міні-історії з корпоративного життя
Міні-історія 1: Інцидент від неправильної припущення
Середня компанія думала, що має «просту» конфігурацію: одна VM, один Nginx, один домен. Або так усі вірили.
Вони оновили сертифікат Let’s Encrypt на Ubuntu, перезавантажили Nginx, а сповіщення про закінчення терміну все ще надходили.
Інженер у чергуванні припустив, що моніторинг помиляється, бо certbot certificates показував свіжий термін.
Браузер на їхньому ноутбуці теж показував старий сертифікат. Потім стало ще дивніше: колега на іншому провайдері бачив новий.
Ця різниця змусила поставити правильне питання: «Чи ми стоїмо за edge-мережею?»
Виявилось, що маркетинг нещодавно ввімкнув керований CDN/WAF у панелі DNS-провайдера.
TLS завершувався на edge із завантаженим сертифікатом, який ніхто не оновив.
«Неправильне припущення» — це не технічна некомпетентність; це організаційна проблема. Усі думали, що діаграма архітектури минулого року все ще актуальна.
Насправді система еволюціонувала без єдиного pull request, що торкався Nginx.
Оновлення бекенду нічого не дало, бо бекенд більше не був TLS-ендпоінтом.
Виправлення було нудним: оновити сертифікат там, де TLS термінується, задокументувати це і додати зонд, що перевіряє сертифікат із різних мереж.
Запобігання — ще нудніше: щотижневий перегляд змін у налаштуваннях edge.
Ніхто цього не любить, але це краще, ніж дізнатись про зміни з пейджера.
Міні-історія 2: Оптимізація, що зіграла проти
Інша команда хотіла «зменшити кількість reload» на завантаженому флоті Nginx. Вони вірили, що часті reload спричиняють спайки латентності.
Вони відключили автоматичні хуки перезавантаження після оновлення і планували робити reload під час тижневого вікна обслуговування.
Ідея звучала розумно: менше reload, менше рухомих частин.
Через два місяці спрацював прогнозований ефект: оновлення проходило кілька разів, але запущені процеси ніколи не перезавантажувалися.
Деякі сервери були перезапущені з інших причин і віддавали свіжі сертифікати; інші — ні і віддавали застарілі.
Флот перетворився на патчворк з різними датами закінчення. Моніторинг перетворився з чистого сигналу на шум.
Операційний біль виник від неоднозначності. Коли одне ім’я хоста почало падати TLS для підмножини користувачів, інженери не могли зрозуміти, чи це мережева проблема,
окремий вузол чи кеш клієнта. Вони витратили години на збір доказів, що вели до одного висновку: «наша оптимізація створила дрейф стану».
Вони скасували зміни: відновили deploy-хуки, залишили reload автоматичним і виміряли вплив замість припущень.
Правильно виконаний reload Nginx — грейсфул. Він не обриває підключення; запускає нових воркерів і дренує старих.
Проблема не в тому, що reloads небезпечні, а в тому, що операційна узгодженість стала необов’язковою.
Міні-історія 3: Сумна, але правильна практика, що врятувала день
Регульоване підприємство запускало Nginx на Ubuntu зі строгим процесом змін. Усі скаржились на чеклісти.
Але у них була одна практика, яка здавалася бюрократією, а діяла як страховка: перевірка після кожного оновлення.
Після кожного оновлення запускалась завдання ззовні мережі, яке записувало серійний номер і термін поданого сертифікату у центральний лог.
Одного ранку задача помітила один VIP-хост все ще з старим сертифікатом. Все інше було в порядку.
Команда не панікувала; у них був план дій. Перша перевірка: SNI. Друга: сервер за замовчуванням. Третя: слухачі балансувальника.
Вони знайшли застарілий слухач на балансувальнику, що використовував вручну завантажений сертифікат замість керованого.
Виправлення зайняло хвилини, бо доказ був миттєвий і конкретний: «цей слухач подає серійник X; очікували Y».
Жодних суперечок, археології скріншотів чи «в мене працює».
Запит на зміну був швидко затверджений, бо це була проста заміна, а не експериментальна операція.
Мораль — агресивно нефантастична: верифікуйте те, що бачать користувачі, автоматично після кожної ротації.
Це практика, яка робить інженерів недооціненими — до моменту, коли вона рятує від інциденту.
Типові помилки: симптом → корінь → виправлення
1) «Certbot каже, що оновлено, але браузери все ще показують старий термін»
Корінь: Nginx не перезавантажився, або reload зазнав невдачі.
Виправлення: Запустіть sudo nginx -t; потім sudo systemctl reload nginx. Перевірте systemctl status nginx і /var/log/nginx/error.log. Додайте deploy-hook щоб це відбувалось автоматично.
2) «Сертифікат на диску новий, але віддається старий — лише для деяких імен хостів»
Корінь: SNI/серверний блок не той. Дефолтний блок або інше server_name ловить трафік.
Виправлення: Використовуйте openssl s_client -servername для кожного імені хоста. Проаналізуйте nginx -T на предмет listen 443 і server_name. Переконайтесь, що кожне ім’я хоста має правильний сертифікат.
3) «Health checks кажуть, що сертифікат старий, але звичайні користувачі в порядку»
Корінь: Перевірочник здоров’я не надсилає SNI і потрапляє в дефолтний сервер/сертифікат.
Виправлення: Налаштуйте перевірочник щоб використовував ім’я хоста (SNI) або виправте дефолтний сервер на валідний сертифікат для тієї IP-цели.
4) «Reload вдається, але нічого не змінюється»
Корінь: Ви перезавантажили інший Nginx, ніж той, що обслуговує 443, або TLS завершується вгорі.
Виправлення: Підтвердіть власника сокета за допомогою ss -ltnp. Переконайтесь, що DNS вказує на цю машину. Якщо є балансувальник/CDN — оновіть сертифікат там.
5) «Після оновлення Nginx не перезавантажується; він продовжує віддавати старий сертифікат»
Корінь: Нові файли відсутні/нечитаються через права, помилки шляху або неправильні посилання файлів (наприклад, посилання на chain.pem замість fullchain.pem в деяких налаштуваннях).
Виправлення: Перевірте /var/log/nginx/error.log на повідомлення cannot load certificate. Виправте шляхи, права та використовуйте fullchain.pem. Заново запустіть nginx -t.
6) «Лише деякі клієнти бачать старий сертифікат; інші бачать новий»
Корінь: Багато edge-вузлів / декілька A-записів / anycast / пул балансувальника з різними станами.
Виправлення: Розв’язуйте DNS з різних місць; перевірте кожний бекенд окремо; переконайтесь, що оновлення і reload відбуваються скрізь; виправте дрейф.
7) «Ми оновили конфіг Nginx на новий шлях сертифікату, але він потім відкотився»
Корінь: Система управління конфігурацією або плагін Certbot Nginx перезаписав файли.
Виправлення: Керуйте TLS-директивами в єдиному джерелі правди (Ansible, Puppet тощо) і уникайте ручних правок генерованих фрагментів без власності.
Жарт №2: Нічого так не збирає команду, як сертифікат, що закінчується — раптом усі пам’ятають, хто відповідає за DNS.
Контрольні списки / покроковий план
Покроково: безпечно виправити ситуацію «оновлено, але все ще старе»
- Підтвердіть симптом зовні. Використайте
openssl s_client -servernameі зафіксуйте expiry + serial. - Підтвердіть, хто володіє :443. Використайте
ss -ltnp. Якщо це не Nginx — зупиніться і перенаправте тикет правильно. - Підтвердіть, що DNS вказує сюди. Використайте
dig +shortі порівняйте з локальними IP. - Проаналізуйте вибір конфігурації Nginx. Використайте
nginx -T, знайдіть правильнийserver_nameі ідентифікуйтеssl_certificateшляхи. - Переконайтесь, що ви посилаєтесь на Let’s Encrypt
live/симвпосилання. Виправте будь-яке пряме використанняarchive/. - Перевірте конфіг. Запустіть
nginx -t. Без валідації — жодного reload. - Перезавантажте Nginx. Використайте
systemctl reload nginx(або ваш сервіс-менеджер) і підтвердіть успіх вsystemctl status. - Повторно перевірте зовні. Тими ж командами, тим же іменем хоста, підтвердіть зміну серійника/терміну.
- Якщо без змін — шукайте upstream-термінацію. Перевірте слухачі LB/CDN і місця, де керуються сертифікати.
- Автоматизуйте наступний раз. Додайте deploy-hook і зовнішню перевірку після оновлення.
Контрольний список: як має виглядати «добре» на Ubuntu 24.04
- Конфіг TLS Nginx посилається на
/etc/letsencrypt/live/<name>/fullchain.pemіprivkey.pem. - Існує лише один pipeline CA (Snap Certbot або apt-інструменти), а не обидва одночасно.
- systemd-таймер регулярно запускає оновлення, і логи показують виконання deploy-хуків.
- Reload Nginx перевіряється (
nginx -t) і моніториться на помилки. - Зовнішній зонд верифікує поданий сертифікат після оновлення і алертує при невідповідності.
Контрольний список: уникайте цих «хитрих» ходів
- Не вказуйте Nginx на
/etc/letsencrypt/archive, якщо не любите ручні ротації. - Не «оптимізуйте» шляхом видалення reload-хуків. Дрейф знайде вас.
- Не припускайте, що VM обслуговує TLS тільки тому, що на ній стоїть Nginx.
- Не відлажуйте лише за допомогою скриншота браузера. Використовуйте
opensslі фіксуйте серійники.
Поширені питання
1) Чому Nginx не підхоплює автоматично оновлені сертифікати?
Тому що Nginx читає сертифікат і ключ при завантаженні конфігурації. Оновлення змінює файли на диску, але не стан у пам’яті Nginx.
Потрібен reload (або рестарт), щоб знову відкрити і розпарсити нові файли.
2) Чи безпечно виконувати systemctl reload nginx в продакшні?
Зазвичай — так. Reload розроблений як грейсфул: нові воркери стартують з новою конфігурацією, старі дренуються.
Все ж запустіть nginx -t перед цим; зламана конфігурація перетворює «безпечне» в «самозавданий інцидент».
3) У чому різниця між fullchain.pem і cert.pem?
cert.pem — це лише leaf-сертифікат. fullchain.pem містить leaf плюс проміжні сертифікати.
Багатьом клієнтам потрібні проміжні для правильної побудови довіри, тому fullchain.pem — стандартний вибір для Nginx.
4) Чому я бачу новий сертифікат на диску, а по мережі — старий?
Або Nginx не перезавантажився, або Nginx вказує на інші файли, ніж ви перевіряли, або TLS-ендпоінт — не Nginx (балансувальник/CDN).
Розглядайте це як проблему маршрутизації/володіння, поки не доведено протилежне.
5) Моніторинг каже «сертифікат скоро закінчиться», а openssl s_client показує свіжий сертифікат. Хто бреше?
Можливо ніхто. Моніторинг може перевіряти інше ім’я хоста, перевіряти без SNI, перевіряти стару IP-адресу або перевіряти інший регіон/edge.
Оновіть перевірку так, щоб вона відправляла SNI і валідувала саме те ім’я хоста, до якого звертаються користувачі.
6) Чи можна просто рестартувати Nginx замість reload?
Можна, але reload зазвичай краща практика: менше переривань і менше несподіваних побічних ефектів.
Restart — грубий інструмент; використовуйте його коли reload заблокований (наприклад, завислі воркери) або коли ваш менеджер процесів цього вимагає.
7) Що робити, якщо я використовую балансувальник, який завершує TLS?
Тоді оновлення бекенду не вплине на те, що бачать користувачі. Поворачайте сертифікат на балансувальнику (або ввімкніть керовані сертифікати там).
Ви все одно можете тримати TLS на бекенді для defense-in-depth, але не плутайте його з публічним сертифікатом.
8) Як запобігти цьому в майбутньому?
Дві речі: (1) deploy-hook, який перезавантажує Nginx після успішного оновлення та (2) зовнішня перевірка, що підтверджує серійник/термін поданого сертифікату.
Автоматизація без перевірки — це просто швидка помилка.
9) Який сигнал я довіряю найбільше під час відладки?
Сертифікат, який справді подається реальному клієнту, виміряний з SNI за допомогою openssl s_client (або еквівалентного зонду) і зафіксований з серійником + терміном.
Все інше — допоміжні докази.
Висновок: наступні кроки щоб уникнути повторення
Ця проблема рідко є «Let’s Encrypt зламався». Майже завжди це «шар обслуговування не перемкнувся». Ваш відлад має це відображати.
Починайте з зовнішньої перевірки, доведіть, що подається, доведіть, хто подає, потім вирівняйте шляхи конфігурації і поведінку перезавантаження.
Операційний принцип добре передано перефразованою ідеєю, часто приписуваною Ronald Coase: якщо довго мучити дані, вони визнаються
.
В оперуванні: не мучте логи й припущення. Виміряйте живий ендпоінт, потім рухайтесь назад.
Практичні наступні кроки:
- Уніфікуйте Nginx на посилання
/etc/letsencrypt/live/.../fullchain.pemіprivkey.pem, а неarchive/. - Зробіть
nginx -t+systemctl reload nginxпост-оновлювальною дією через deploy-hook. - Додайте зовнішній зонд, який записує серійник і термін поданого сертифікату для кожного імені хоста після оновлення.
- Аудитуйте точки термінації TLS: VM, ingress контейнера, балансувальник, CDN. Прикріпіть власника до кожної з них.