Production-ready reverse proxy gateway на базе Nginx с генерацией nginx.conf из YAML-маршрутов и запуском в Docker.
- Docker-контейнер с Nginx, Python и генератором конфига.
- Маршрутизация в
config/routes.yml. - Генерация итогового
/etc/nginx/nginx.confпри старте контейнера. - Проверка конфига через
nginx -tперед запуском. - HTTP to HTTPS redirect для всего трафика, кроме ACME HTTP-01 challenge.
- WebSocket support, proxy headers, default server и базовые production-настройки таймаутов.
.env.example— пример переменных окружения.compose.yaml— запускgatewayи подключение к external Docker network.config/routes.yml— декларативные маршруты по доменам.scripts/generate_nginx_conf.py— валидация YAML и генерацияnginx.conf.scripts/entrypoint.sh— генерация конфига,nginx -t, запуск Nginx.scripts/start_gateway.sh— старт gateway на production-сервере с автосозданием Docker network.scripts/certbot.sh— выпуск или перевыпуск сертификата Let’s Encrypt для одного домена.nginx/nginx.conf.template— шаблон базового конфига.
Имя сети должно совпадать со значением GATEWAY_NETWORK в .env.
Так как в compose.yaml используется external network, Docker Compose не создаст её автоматически. Если сети с именем из GATEWAY_NETWORK ещё нет, создайте её один раз вручную перед первым запуском gateway.
docker network create gateway-netПроверьте, что ваши upstream-сервисы подключены к этой же сети и доступны по service name, например tochka-backend, karabas-admin и т.д.
На production-сервере вместо ручных команд удобнее использовать:
./scripts/start_gateway.shСкрипт сам:
- подхватывает
.env - создает
${GATEWAY_NETWORK}, если сети еще нет - запускает
docker compose up -d --build
Скопируйте пример и при необходимости измените имя сети и порты:
cp .env.example .envПример:
GATEWAY_NETWORK=gateway-net
GATEWAY_HTTP_PORT=80
GATEWAY_HTTPS_PORT=443
CERTBOT_EMAIL=admin@example.commkdir -p certbot/www certbot/confcompose.yaml монтирует:
./certbot/wwwв/var/www/certbotдля ACME HTTP-01 challenge./certbot/confв/etc/letsencryptдля сертификатов
Рекомендуемый вариант:
./scripts/start_gateway.shЛибо вручную:
docker compose up -d --buildПроверка:
docker compose logs -f gateway
docker exec gateway nginx -tЕсли config/routes.yml невалиден или итоговый nginx.conf некорректен, контейнер завершится с ошибкой на старте.
Если для домена сертификат еще не выпущен, gateway стартует с fallback self-signed сертификатом. Это позволяет поднять контейнер и пройти ACME HTTP-01 challenge по 80 порту до получения боевого сертификата.
Достаточно добавить новый блок в config/routes.yml и перезапустить контейнер:
domains:
- host: new-site.example.com
routes:
- path: /app
upstream: http://new-frontend:80
- path: /api
upstream: http://new-backend:8000
strip_prefix: falseПосле изменения:
docker compose restart gatewayПример:
domains:
- host: tochka.etalonfood.com
routes:
- path: /app
upstream: http://tochka-frontend:80
- path: /admin
upstream: http://tochka-admin:80
- path: /api
upstream: http://tochka-backend:8000
strip_prefix: false
- host: karabas.etalonfood.com
routes:
- path: /app
upstream: http://karabas-frontend:80
- path: /admin
upstream: http://karabas-admin:80
- path: /api
upstream: http://karabas-backend:8000
strip_prefix: falseГенератор валидирует:
hostне пустойpathначинается с/- комбинация
(host, path)уникальна upstreamначинается сhttp://илиhttps://strip_prefixопционален и должен быть boolean
Для каждого домена генерируются:
- HTTP server block на
80с/.well-known/acme-challenge/и redirect на HTTPS - HTTPS server block на
443с сертификатом из/etc/letsencrypt/live/<host>/
Маршруты работают как path-prefix gateway:
- запрос на
/adminуходит в upstream как/ - запрос на
/admin/assets/app.jsуходит в upstream как/assets/app.js - по умолчанию префикс маршрута срезается
- если
strip_prefix: false, исходный путь сохраняется - запрос на
/api/usersприstrip_prefix: falseуходит в upstream как/api/users
Используется webroot-режим: challenge-файлы пишутся в ./certbot/www, а Nginx отдает их через /.well-known/acme-challenge/.
Для выпуска и перевыпуска сертификатов используйте helper-скрипт:
./scripts/certbot.sh <domain>Скрипт делает следующее:
- подхватывает
.env - при отсутствии создает Docker network
${GATEWAY_NETWORK} - поднимает
gateway, чтобы ACME challenge был доступен по80порту - запускает
certbotвwebroot-режиме - если сертификат выпускается впервые, выполняет
docker compose restart gateway - если сертификат уже существует и был обновлен, выполняет
docker exec gateway nginx -s reload
Пример для tochka.etalonfood.com:
./scripts/certbot.sh tochka.etalonfood.comПример для karabas.etalonfood.com:
./scripts/certbot.sh karabas.etalonfood.comОба домена по очереди:
./scripts/certbot.sh tochka.etalonfood.com
./scripts/certbot.sh karabas.etalonfood.comСкрипт сам выбирает правильное действие:
- первый выпуск:
docker compose restart gateway - перевыпуск или продление существующего сертификата:
docker exec gateway nginx -s reload
Пример cron:
0 3 * * * cd /path/to/gateway && ./scripts/certbot.sh tochka.etalonfood.com && ./scripts/certbot.sh karabas.etalonfood.comПример systemd unit:
[Unit]
Description=Renew Let's Encrypt certificates for gateway
[Service]
Type=oneshot
WorkingDirectory=/path/to/gateway
ExecStart=/bin/sh -lc './scripts/certbot.sh tochka.etalonfood.com && ./scripts/certbot.sh karabas.etalonfood.com'Пример systemd timer:
[Unit]
Description=Run gateway certificate renewal twice daily
[Timer]
OnCalendar=*-*-* 03,15:00:00
Persistent=true
[Install]
WantedBy=timers.targetСкрипт сам выполняет docker exec gateway nginx -s reload после успешного обновления существующего сертификата. Для первичного выпуска он делает docker compose restart gateway, чтобы gateway пересобрал nginx.conf и переключился с fallback сертификата на настоящий.
- Контейнер запускает
scripts/entrypoint.sh. entrypoint.shсоздает fallback TLS-сертификат дляdefault_server.- Затем запускается
scripts/generate_nginx_conf.py. - Генератор читает
config/routes.yml, валидирует его и собирает/etc/nginx/nginx.conf. - Выполняется
nginx -t. - Если проверка успешна, стартует
nginx -g 'daemon off;'.