Костыльное продление сертификата для статики
Задача
У нас на работе есть огромное количество статических доменов, которые ходят по достаточно сложной схеме. Но изначально они идут на балансер хостера, а оттуда они уже отправляются на другие сервера.
Так вот обычно мы генерируем сертификаты с помощью certman. Но сейчас это... цензурных слов у меня нет... в общем он соизволил плеваться ошибкой вида:
2025-01-23 13:04:45,527 INFO Deploing domain1.com from path "/data/certman/certs/domain1.com/fullchain.pem" to server dsde321.frnx - path "/etc/ssl/private/domain1.com/fullchain.pem"
2025-01-23 13:04:45,527 ERROR No such file or directory
2025-01-23 13:04:45,553 INFO Deploing domain1.com from path "/data/certman/certs/domain1.com/privkey.pem" to server dsde321.frnx - path "/etc/ssl/private/domain1.com/privkey.pem"
2025-01-23 13:04:45,556 ERROR No such file or directory
2025-01-23 13:04:45,588 WARNING Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f773c240dd0>: Failed to establish a new connection: [Errno -2] Name or service not known')': /api/7/store/
Нагуглить и начатджипить я эту ошибку не смог. Последний и вовсе чушь мне выдал. Коллеги тоже не смогли подсказать. Тогда я решил обратиться к костылю в виде certbot
Решение задачи
Для костыля необходимо сделать вот что:
Для начала вводим:
certbot certonly --manual --preferred-challenges=dns --email otulashvili.ge@gmail.com --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d domain1 -d *.domain1
Тем самым мы говорим:
certonly | Запросить сертификат без его установки |
-manual | Получение сертификатов |
-preferred-challenges=dns | Использовать DNS для подтверждения, что я владелец домена |
-server | Сервер, который будет использоваться для генерации сертификатов |
-agree-tos | Согласиться с политикой ACME |
-d | Домен, для которого будут созданы сертификаты |
Далее нам предлагается TXT
-запись, которую нужно вставить у хостера, тк мы выборали -preferred-challenges=dns
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for domain1 and *.domain1
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:
_acme-challenge.domain1.
with the following value:
<value>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Добавляем указанную TXT
запись у провайдера. Проверяем, что запись добавлена:
dig TXT _acme-challenge.domain1.
; <<>> DiG 9.10.6 <<>> TXT _acme-challenge.domain1.
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41334
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;_acme-challenge.domain1. IN TXT
;; ANSWER SECTION:
_acme-challenge.domain1. 3600 IN TXT "NH2ApWYWFyJJMcUS4dAwEAdu1XTj12VGNqpEJPOiJ0o"
;; Query time: 173 msec
;; SERVER: 10.10.10.114#53(10.10.10.114)
;; WHEN: Fri Jan 24 17:41:53 MSK 2025
;; MSG SIZE rcvd: 117
Первый раз у меня не получилось - ввел не тот value для своей записи, а второй раз, после внесения изменений, ждал, когда nslookup мне покажет новую TXT запись. Спустя 2 минуты он ее не показывал и я понял, что она просто закэшировалась (c кэшированием DNS-записей я разобрался тут)
Тогда я подтвердил для certbot
, что я установил запись у хостера и получил:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/domain1/fullchain.pem
Key is saved at: /etc/letsencrypt/live/domain1/privkey.pem
This certificate expires on 2025-04-24.
These files will be updated when the certificate renews.
NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Окей, сертификат сгенерирован. Теперь:
cp -r /etc/letsencrypt/archive/domain1/* <dir_ssl_nginx>
dir_ssl_nginx
- это директория, которая указана для сертификатов вnginx
archieve
- выбираем именно эту папку, тк изначально сертификаты являются симлинком на эту директорию и создаются в/etc/letsencrypt/live/domain/
Вdir_ssl_nginx/domain/
получилась такая картина:
root@dsde321:/etc/ssl/private/domain1# ls
cert1.pem chain1.pem fullchain1.pem privkey1.pem
Переименовываем наши полученные сертификаты:
mv cert1.pem cert.pem && mv chain1.pem chain.pem && mv fullchain1.pem fullchain.pem && mv privkey1.pem privkey.pem
Меняем права у файлов:
chown root:root cert.pem chain.pem fullchain.pem && chown nginx:root privkey.pem && chmod 644 privkey.pem
Далее проверяем, встал ли сертификат:
curl -vI https://domain1
curl -vI https://gr2.domain1.com
Если не подтянулись, то можно сделать reload nginx
Резюме
Нужно понимать, что данные сертификаты нужно будет продлевать вручную, пройдя путь с самого начала. Поэтому решений тут несколько:
- Разобраться с
certman
Этот вариант мне совсем не нравится, тк я не первый раз ловлю от него подобные "сюрпризы" - Найти альтернативную систему выпуска и автоматического обновления сертификатов
Тут уже поинтереснее, нужно изучать. Насколько я знаю есть еще acme.sh - Написать свою систему
Как любитель изобретать велосипеды мне этот вариант импонирует больше всего, но насколько это целесообразно мне, на данный момент, не совсем ясно