Автоматическое управление сертификатами Let’s Encrypt стало стандартом для HTTPS в контейнерных инфраструктурах. Однако на практике возникают вопросы: как правильно организовать выпуск и продление сертификатов, как избежать гонок при обновлении, как не сломать доступность доменов при перезапусках, и как совместить это с архитектурой Nginx reverse‑proxy и Traefik в Docker‑Compose.
В этой статье разберем рабочий подход к автоматизации Let’s Encrypt для сценариев с Nginx reverse‑proxy в контейнерах и интеграцией с Traefik. Отдельно уделим внимание вопросам безопасности, хранению приватных ключей, а также архитектурным практикам.
Нормативная и правовая рамка (РФ) и практические последствия
При проектировании HTTPS‑инфраструктуры для сайтов и сервисов важно учитывать, что в РФ криптографическая защита и использование средств криптографии могут подпадать под требования регуляторов. На практике для большинства веб‑проектов используется публичная TLS‑проверка и сертификаты общедоступных центров сертификации. Let’s Encrypt является общедоступным CA, и часто применяется без дополнительных сертифицированных криптосредств.
Чтобы соответствовать требованиям и избежать рисков в конкретных проектах, ориентируйтесь на следующие принципы:
- Если проект обрабатывает персональные данные, а также если требуется соблюдать требования по защите информации, проверьте применимость регуляторных требований к криптографии и общую модель угроз. Для персональных данных обычно требуется обоснование мер защиты и оформление организационно‑технических решений.
- Для систем, подпадающих под специальные требования (критическая инфраструктура, ГИС/АС, ведомственные контуры), подход может потребовать использования сертифицированных средств криптографии и/или дополнительных компонентов. В таких случаях Let’s Encrypt может оказаться неприемлемым без дополнительных мер.
- Технически вы должны обеспечить: корректную изоляцию приватных ключей, ограничение доступа к хранилищам, безопасные разрешения файлов, защиту от утечек логов, а также корректную ротацию/обновление.
Важно: ниже описываем архитектуру как инженерный подход. Для юридической оценки и определения применимости требований конкретного регулятора рекомендуется привлекать профильного специалиста и проводить анализ под ваш контур.
Архитектурные варианты: Traefik как ACME‑клиент и Nginx как reverse‑proxy
Есть два основных способа:
- Traefik управляет Let’s Encrypt, а Nginx используется как внутренний reverse‑proxy (например, терминация запросов/доп. маршрутизация/служебные заголовки). Traefik отвечает за прохождение ACME‑челленджа и подмену/обновление сертификатов в нужной точке.
- Nginx сам управляет сертификатами (через certbot/lego/другие агенты). Traefik при этом может использовать сертификаты, монтированные в контейнер, или выступать только как маршрутизатор без терминатора TLS.
Практически в большинстве задач проще и надежнее: пусть Traefik является ACME‑клиентом. Он умеет автоматом запросить/обновлять сертификаты, корректно организовать HTTP‑01/ALPN‑01/TLS‑ALPN‑01 (в зависимости от конфигурации) и уменьшить вероятность «двоения» продлений.
Базовые принципы безопасной эксплуатации
- Хранилище сертификатов: приватные ключи должны храниться в объемах (volumes) и иметь строгие права доступа. Не кладите их в image.
- Изоляция: запуск ACME‑агента (Traefik или certbot) делайте в отдельном контейнере/с ограниченными правами.
- Гонки при продлении: при нескольких репликах одного сервиса продление должно быть единственным (singleton) или с согласованными блокировками (например, через общую директорию и корректную стратегию lock).
- Логи: отключайте вывод секретов в логах. Убедитесь, что в логах не печатаются приватные ключи и токены.
- Публичные порты: для HTTP‑01 убедитесь, что 80/TCP доступен извне, а маршрутизация не перехватывает путь / .well‑known/acme‑challenge вашим приложением.
Пример №1: Traefik получает сертификаты Let’s Encrypt, Nginx работает как внутренний reverse‑proxy
Ниже пример, где:
- Traefik стоит на границе (публикует 80/443).
- Traefik получает сертификаты через ACME HTTP‑01.
- Nginx — внутренний сервис, к которому Traefik проксирует по сети Docker.
Важно: домены (example.com и www.example.com) замените на свои. Укажите корректный email для ACME.
docker-compose.yml
version: "3.9"
services:
traefik:
image: traefik:v3.1
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik-certs:/letsencrypt
command:
- "--api.dashboard=true"
- "--api.insecure=false"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
# EntryPoints
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
# Redirect HTTP -> HTTPS
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
# ACME (Let’s Encrypt) - HTTP-01
- "--certificatesresolvers.le.acme.httpchallenge=true"
- "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.le.acme.email=admin@example.com"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.le.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
networks:
- edge
labels:
- "traefik.enable=true"
nginx:
image: nginx:1.27-alpine
container_name: nginx
restart: unless-stopped
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
networks:
- edge
labels:
- "traefik.enable=true"
- "traefik.http.routers.site.rule=Host(example.com) || Host(www.example.com)"
- "traefik.http.routers.site.entrypoints=websecure"
- "traefik.http.routers.site.tls=true"
- "traefik.http.routers.site.tls.certresolver=le"
- "traefik.http.services.site.loadbalancer.server.port=80"
networks:
edge:
volumes:
traefik-certs:
driver: localnginx/conf.d/default.conf
server {
listen 80;
server_name _;
# Пример: проксируем на ваше приложение в контейнерной сети.
# В этом примере предполагаем, что приложение доступно по имени app:8080.
location / {
proxy_pass http://app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Что важно проверить
- DNS: A/AAAA записи для example.com и www.example.com должны указывать на публичный IP/балансер.
- Порты 80 и 443 должны быть доступны извне на узле с Traefik.
- Маршрутизация ACME HTTP‑01: путь /.well-known/acme-challenge должен обслуживаться Traefik. В конфигурации выше redirection HTTP->HTTPS включен, но Traefik использует entrypoint web (80) для httpchallenge, и корректная работа зависит от общей схемы маршрутизации. Если возникают проблемы, проверьте, что Traefik действительно обрабатывает ACME путь.
Обновление сертификатов и поведение при перезапуске
Traefik хранит состояние ACME в /letsencrypt/acme.json на volume traefik-certs. При перезапуске контейнера обновление продолжится. Для корректной работы важно, чтобы volume сохранялся и не был очищен.
С практической стороны:
- Убедитесь, что acme.json не теряется при пересоздании контейнеров.
- Если используете несколько окружений (staging/production), храните отдельные storage и/или отдельные резолверы.
Пример №2: Traefik терминирует TLS, а Nginx получает уже HTTP (мягкая интеграция)
Если вам нужно, чтобы Nginx не занимался TLS вообще, то достаточно оставлять Nginx listen=80 и проксировать только по внутренней сети. Traefik будет заниматься сертификатами, а Nginx — приложением/правилами.
Эта схема чаще всего снижает риски:
- меньше «точек отказа»;
- меньше контейнеров, которые знают о приватных ключах;
- единый ACME‑клиент (Traefik).
Обработка нескольких доменов и SAN
Let’s Encrypt может выпускать сертификаты на набор доменов (SAN). В Traefik вы можете описывать роуты на несколько Host‑условий, а Traefik сам определяет, какие имена включить в выпуск. Если вы хотите строгий контроль SAN, используйте более явную конфигурацию: либо отдельные routers на домены, либо отдельные certificate domains через динамическую конфигурацию Traefik (если ваш вариант требует).
Про продакшен: рекомендации по настройке Traefik
- Скорость и лимиты: Let’s Encrypt имеет rate limits. Настраивайте конфигурацию так, чтобы не «дергать» выпуск каждые несколько минут при ошибках. Исправляйте причину (DNS/доступность/маршрутизация), а не перезапускайте бесконечно.
- Защита dashboard: не оставляйте api.insecure=true в продакшене. Используйте отдельный роут с авторизацией (например, через базовую авторизацию/SSO) или полностью отключайте dashboard.
- Headers и безопасность: на стороне Nginx добавляйте security headers, HSTS (после проверки, что сертификаты стабильно работают), строгие правила проксирования.
Nginx reverse‑proxy в контейнере: архитектурные детали
Даже если TLS терминируется Traefik, Nginx всё равно выполняет важную роль:
- агрегация/маршрутизация по путям;
- поддержка websockets;
- буферизация/таймауты;
- нормализация заголовков и cookies.
На практике:
- правильно передавайте X-Forwarded-Proto и Host (как в примере);
- для websockets добавьте proxy_set_header Upgrade $http_upgrade и proxy_set_header Connection "upgrade" там, где это нужно;
- задавайте timeout’ы под реальные SLA приложений.
Если вам нужен certbot в Docker (когда Traefik не управляет ACME)
Иногда архитектурно Traefik не должен заниматься сертификатами, а Nginx должен использовать сертификаты непосредственно. Тогда применяют certbot как отдельный сервис.
Ключевые моменты:
- certbot должен иметь доступ к домену для HTTP‑01/ALPN‑01;
- сертификаты должны монтироваться в Nginx volume;
- обновление должно быть безопасным и не конфликтовать с чтением файлов Nginx.
Ниже общий каркас (адаптируйте под вашу схему). Отдельно отметим: реализация с certbot требует дисциплины по mount путям и правам.
services:
certbot:
image: certbot/certbot:latest
volumes:
- ./letsencrypt:/etc/letsencrypt
- ./webroot:/var/www/html
command: certonly --webroot -w /var/www/html --email admin@example.com --agree-tos --no-eff-email -d example.com -d www.example.com
# запуск по требованию или отдельным cron контейнеромЗатем в Nginx:
server {
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;
location / {
proxy_pass http://app:8080;
}
}Для продления обычно добавляют отдельный cron‑контейнер. Но, как правило, если есть Traefik, предпочтительнее пусть он управляет ACME.
Автоматизация и инфраструктурная зрелость: мониторинг и алерты
Чтобы система была действительно «автоматической», нужны признаки успеха/ошибок:
- проверяйте, что сертификат обновился до наступления истечения (например, 30 дней — как сигнал для алерта);
- логируйте события ACME (включая причины ошибок);
- введите healthcheck для Traefik и Nginx, чтобы быстро локализовать отказ.
Практический подход: добавить отдельный сервис мониторинга, который раз в N часов проверяет дату NotAfter сертификата (из acme storage или из endpoint’а) и отправляет уведомление.
Разбор типичных проблем
- Let’s Encrypt не может подтвердить домен: DNS неверен или порт 80/443 недоступен, или ACME путь блокируется Nginx/app.
- Сертификат выпускается, но HTTPS не работает: неверная маршрутизация на entrypoint websecure, проблемы с labels, ошибки в правилах роутера.
- Конфликт обновлений: несколько экземпляров ACME‑клиента используют один и тот же storage без согласования — избегайте этого.
- Проблемы прав на volume: Nginx/Traefik/Certbot не может читать/записывать acme.json/ключи — проверьте владельца и права.
Рекомендации по выбору технологии (PHP/Python/и т.п. в контексте)
Сам механизм TLS от языка не зависит: PHP/Python приложения работают за reverse‑proxy. Архитектурно важно:
- приложение должно корректно работать с заголовками прокси (X-Forwarded-Proto, Host);
- если есть редиректы (http->https), они должны быть согласованы с тем, что делает Traefik (например, переадресации на websecure).
Если используете frameworks (например, Symfony/Laravel/Django/FastAPI), включите trust proxy/forwarded headers в соответствии с рекомендациями фреймворка.
Заключение
Наиболее надежная и поддерживаемая схема для автоматического управления Let’s Encrypt сертификатами в Docker‑Compose: Traefik выступает ACME‑клиентом, а Nginx — внутренним reverse‑proxy без необходимости хранить приватные ключи. Это упрощает эксплуатацию, уменьшает количество точек отказа и повышает устойчивость к обновлениям.
При этом важно учитывать правовую и организационно‑техническую сторону применения криптографии в вашем контуре в соответствии с требованиями РФ, а также обеспечивать безопасное хранение ключей и корректную работу продления.
Если хотите, чтобы мы помогли спроектировать и внедрить такую схему под ваш ландшафт (Traefik/Nginx, домены, окружения, мониторинг, политики безопасности), обратитесь в РыбинскЛАБ. Мы выполняем разработку и сопровождение инфраструктурных решений (в том числе на PHP/Python и в архитектуре контейнеров).
Услуги РыбинскЛАБ по разработке: проектирование и внедрение веб‑систем, DevOps/контейнеризация, настройка обратных прокси и TLS‑инфраструктуры, интеграции и эксплуатационная поддержка.