We detected you are likely not from a Russian-speaking region. Would you like to switch to the international version of the site?

К списку статей

Автоматическое управление сертификатами Let’s Encrypt для Nginx‑reverse‑proxy в Docker‑Compose и Traefik

Автоматическое управление сертификатами 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

Есть два основных способа:

  1. Traefik управляет Let’s Encrypt, а Nginx используется как внутренний reverse‑proxy (например, терминация запросов/доп. маршрутизация/служебные заголовки). Traefik отвечает за прохождение ACME‑челленджа и подмену/обновление сертификатов в нужной точке.
  2. 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: local

nginx/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’а) и отправляет уведомление.

Разбор типичных проблем

  1. Let’s Encrypt не может подтвердить домен: DNS неверен или порт 80/443 недоступен, или ACME путь блокируется Nginx/app.
  2. Сертификат выпускается, но HTTPS не работает: неверная маршрутизация на entrypoint websecure, проблемы с labels, ошибки в правилах роутера.
  3. Конфликт обновлений: несколько экземпляров ACME‑клиента используют один и тот же storage без согласования — избегайте этого.
  4. Проблемы прав на 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‑инфраструктуры, интеграции и эксплуатационная поддержка.

Материал подготовлен и отредактирован для практического применения. Перед внедрением в продакшен проверьте код и команды на своём окружении.

Поделиться материалом

Нужна сложная backend-разработка?

Проектирование архитектуры, PHP/Python backend, интеграции API, боты, автоматизация и оптимизация существующих систем.

Обсудить проект
Поддержать проект