- Shell 100%
|
|
||
|---|---|---|
| .env.example | ||
| .gitignore | ||
| deploy-hook.sh | ||
| docker-compose.yml | ||
| expand.sh | ||
| issue.sh | ||
| README.md | ||
certbot — автоматический выпуск и обновление Let's Encrypt сертификатов
Самодостаточный compose-модуль: выпускает один SAN-сертификат (HTTP-01, webroot)
на все домены из .env и обновляет его каждые 12 часов. После успешного обновления
перезагружает nginx в соседнем compose-проекте через Docker Engine API (unix-socket),
без docker-cli и без кастомного образа.
Состав
| Файл | Назначение |
|---|---|
docker-compose.yml |
сервис certbot (цикл renew каждые 12 ч) + named volumes letsencrypt, certbot-webroot |
.env.example |
шаблон конфигурации (DOMAINS, LE_EMAIL, NGINX_CONTAINER) |
issue.sh |
первый выпуск сертификата; принимает доп. флаги certbot (--staging, --force-renewal, …) |
expand.sh |
добавление домена: дописывает в .env и перевыпускает с --expand |
deploy-hook.sh |
хук certbot: nginx -s reload через docker.sock |
Имя сертификата фиксировано первым доменом из DOMAINS (--cert-name whitera.space),
поэтому пути в nginx-конфигах (/etc/letsencrypt/live/whitera.space/…) не меняются
при добавлении доменов.
Настройка стороны nginx
1. Volumes в compose-проекте nginx
Оба volume создаются этим модулем с фиксированными именами — в nginx-проекте
подключайте их как external, только на чтение:
services:
nginx:
# ...
volumes:
- letsencrypt:/etc/letsencrypt:ro
- certbot-webroot:/var/www/certbot:ro
volumes:
letsencrypt:
external: true
certbot-webroot:
external: true
Монтировать нужно весь /etc/letsencrypt, а не только live/: в live/ лежат
симлинки на archive/, и без него они «повиснут».
2. ACME-challenge в каждом HTTP(80) server-блоке
Location должен стоять до редиректа на https:
server {
listen 80;
server_name whitera.space git.whitera.space ts.whitera.space;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
3. Миграция с хостового bind-mount
Если сертификаты уже есть на хосте в /etc/letsencrypt, скопируйте их внутрь
volume один раз — тогда первый выпуск не нужен, renew подхватит существующие:
# volume должен уже существовать: docker compose up -d (или docker volume create letsencrypt)
docker run --rm \
-v letsencrypt:/dst \
-v /etc/letsencrypt:/src:ro \
alpine cp -a /src/. /dst/
cp -a сохраняет симлинки live/ -> archive/ и права на приватные ключи.
После копирования уберите старый bind-mount /etc/letsencrypt из compose nginx
и замените на external volume (см. п. 1).
Либо чистый старт: certbot delete не нужен — просто выпустите заново в пустой
volume через issue.sh.
Первый запуск
cp .env.example .env # заполнить DOMAINS и LE_EMAIL
docker compose up -d # создаёт volumes и запускает цикл renew
# 1. Пробный выпуск на staging (не тратит rate-limit Let's Encrypt):
./issue.sh --staging
# 2. Боевой выпуск (перезаписывает staging-сертификат):
./issue.sh --force-renewal
# 3. Проверка, что автообновление сработает:
docker compose run --rm --entrypoint certbot certbot renew --dry-run
Порядок важен: сначала должен быть настроен nginx (volumes + acme-location из разделов выше), иначе HTTP-01 challenge не пройдёт.
Добавление домена
./expand.sh new.whitera.space
Скрипт допишет домен в DOMAINS в .env и перевыпустит сертификат с --expand.
Имя сертификата (и пути live/whitera.space/) не изменятся. Не забудьте добавить
новый домен в server_name nginx и DNS A-запись заранее.
Как работает перезагрузка nginx
deploy-hook.sh монтируется в контейнер certbot и вызывается после каждого
успешного обновления. Внутри — два запроса к Docker Engine API через
/var/run/docker.sock (exec create + exec start), эквивалент
docker exec $NGINX_CONTAINER nginx -s reload. Если в образе certbot нет curl,
хук доставит его через apk add (требуется выход в интернет из контейнера).
Отладка
docker compose logs -f certbot # цикл renew
docker volume inspect letsencrypt # где лежат сертификаты
docker compose run --rm --entrypoint certbot certbot certificates # список сертификатов