Маршрутизация в Docker: настройка reverse proxy для нескольких контейнеров | AdminWiki

Маршрутизация в Docker: настройка reverse proxy для нескольких контейнеров

27 августа 2026 6 мин. чтения

Введение: зачем нужен reverse proxy в Docker

На одном хосте с Docker часто работают несколько веб-приложений: админ-панель, API, документация, клиентский портал. Каждое приложение живет в отдельном контейнере и слушает свой порт. Прокидывать наружу десяток портов и запоминать, что на 8081 сидит Grafana, а на 8082 - Nextcloud, неудобно и небезопасно. Reverse proxy решает эту задачу: он принимает весь входящий трафик на 80 и 443 портах и распределяет его по контейнерам на основе правил.

В этой статье разобраны два инструмента: Nginx и Traefik. Nginx требует ручной конфигурации и дает полный контроль над каждым маршрутом. Traefik автоматически обнаруживает контейнеры через Docker API и строит маршруты из меток. Оба подхода рабочие, но подходят под разные сценарии.

Материал содержит готовые конфигурации для Docker Compose, примеры маршрутизации по доменным именам, портам и URL-путям, а также разбор типичных ошибок. Если вам нужно быстро поднять рабочий reverse proxy, начните с раздела про выбор инструмента, затем переходите к настройке.

Смежная тема - организация сетевого взаимодействия между контейнерами - раскрыта в руководстве по сетям bridge, host и overlay в Docker.

Выбор инструмента: Nginx или Traefik

Выбор между Nginx и Traefik сводится к одному вопросу: как часто меняется состав контейнеров и маршруты. Если у вас стабильный стек из трех-пяти сервисов, Nginx с ручной конфигурацией работает предсказуемо и не требует дополнительных абстракций. Если контейнеры создаются и удаляются регулярно, Traefik экономит часы ручной правки конфигов.

Критерии выбора reverse proxy

  • Автоматическое обновление конфигурации. Traefik читает метки контейнеров и перестраивает маршруты на лету. Nginx требует перезагрузки после изменения конфига.
  • Сложность маршрутизации. Nginx дает тонкий контроль над rewrite, заголовками, кэшированием. Traefik покрывает типовые сценарии через middleware.
  • Требования к производительности. Оба инструмента работают на уровне сотен и тысяч запросов в секунду. Разница на практике незначительна для типовых веб-приложений.
  • Знакомство с инструментом. Если команда уже знает Nginx, внедрение Traefik потребует времени на изучение модели конфигурации.

Сравнительная таблица Nginx и Traefik

ПараметрNginxTraefik
Автоматическое обнаружение контейнеровНет, ручная настройкаДа, через Docker API
Формат конфигурацииСобственный синтаксисYAML, CLI-флаги, Docker-метки
Поддержка DockerЧерез контейнеризацию NginxНативный провайдер Docker
ПроизводительностьВысокаяВысокая
Сложность освоенияСредняяСредняя, но другая модель
ЭкосистемаОгромная, много модулейMiddleware, интеграция с Let's Encrypt

Для простых проектов с ручной конфигурацией выбирайте Nginx. Для продакшн-среды с частыми изменениями и автоматическим выпуском SSL-сертификатов - Traefik. Подробное сравнение обратных прокси для Docker, включая Nginx Proxy Manager и Caddy, есть в отдельном материале.

Подготовка окружения: Docker Compose и сети

Reverse proxy должен видеть все контейнеры, на которые он проксирует трафик. Для этого создается общая пользовательская сеть. Контейнеры в одной сети обращаются друг к другу по имени сервиса, без проброса портов наружу.

Создание общей сети для контейнеров

Базовая структура docker-compose.yml с общей сетью:

networks:
  proxy:
    driver: bridge

services:
  app1:
    image: nginx:alpine
    networks:
      - proxy

  app2:
    image: httpd:alpine
    networks:
      - proxy

Сеть proxy объединяет все сервисы. Reverse proxy подключается к этой же сети и обращается к app1 и app2 по именам. Порты контейнеров наружу не публикуются, доступ к ним идет только через прокси.

Использование переменных окружения в Docker Compose

Домены, порты и пути выносятся в файл .env, чтобы не дублировать значения в конфигурации:

# .env
APP1_DOMAIN=app1.example.com
APP2_DOMAIN=app2.example.com
PROXY_NETWORK=proxy

В docker-compose.yml переменные подставляются через ${VAR}:

services:
  nginx:
    image: nginx:alpine
    environment:
      - APP1_DOMAIN=${APP1_DOMAIN}
      - APP2_DOMAIN=${APP2_DOMAIN}
    networks:
      - ${PROXY_NETWORK}

Переменные окружения удобны при переносе конфигурации между стендами: dev, staging, production отличаются только содержимым .env.

Настройка Nginx в качестве reverse proxy

Nginx запускается в контейнере, конфигурационный файл монтируется через volume. Базовая структура:

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    networks:
      - proxy

Конфигурация описывает серверные блоки с директивами server_name, listen и location.

Маршрутизация по доменным именам (виртуальные хосты)

Два домена направляются на два разных контейнера:

server {
    listen 80;
    server_name app1.example.com;

    location / {
        proxy_pass http://app1:80;
        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;
    }
}

server {
    listen 80;
    server_name app2.example.com;

    location / {
        proxy_pass http://app2:80;
        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;
    }
}

Заголовки X-Forwarded-* обязательны: без них приложение за прокси не узнает реальный IP клиента и протокол запроса.

Маршрутизация по портам

Один домен, разные порты для разных сервисов:

server {
    listen 8081;
    server_name app.example.com;

    location / {
        proxy_pass http://app1:80;
    }
}

server {
    listen 8082;
    server_name app.example.com;

    location / {
        proxy_pass http://app2:80;
    }
}

Схема подходит для служебных панелей, к которым обращаются по явному порту: http://app.example.com:8081.

Маршрутизация по URL-путям

Один домен, разные пути ведут на разные контейнеры:

server {
    listen 80;
    server_name app.example.com;

    location /app1/ {
        proxy_pass http://app1:80/;
    }

    location /app2/ {
        proxy_pass http://app2:80/;
    }
}

Обратите внимание на слэш в конце proxy_pass. Если указать http://app1:80 без завершающего слэша, путь /app1/ будет передан приложению целиком. Со слэшем Nginx отрезает /app1/ и передает корень. Это частая причина ошибок 404.

Настройка Traefik в качестве reverse proxy

Traefik подключается к Docker-сокету и читает метки контейнеров. Маршруты описываются не в отдельном файле, а прямо в docker-compose.yml каждого сервиса.

services:
  traefik:
    image: traefik:v3.0
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy

Флаг exposedbydefault=false заставляет Traefik игнорировать контейнеры без явных меток. Это защищает от случайного проброса лишних сервисов.

Маршрутизация по доменным именам с Traefik

Метки на контейнере приложения:

services:
  app1:
    image: nginx:alpine
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app1.rule=Host(`app1.example.com`)"
      - "traefik.http.routers.app1.entrypoints=web"
    networks:
      - proxy

Traefik видит контейнер, читает правило Host и направляет запросы с домена app1.example.com на этот сервис. При добавлении нового контейнера перезапуск Traefik не требуется.

Маршрутизация по портам с Traefik

Для разных портов определяются отдельные entrypoints:

services:
  traefik:
    image: traefik:v3.0
    command:
      - "--entrypoints.web.address=:80"
      - "--entrypoints.admin.address=:8081"
    ports:
      - "80:80"
      - "8081:8081"

  app1:
    image: nginx:alpine
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app1.rule=Host(`app.example.com`)"
      - "traefik.http.routers.app1.entrypoints=admin"
    networks:
      - proxy

Запрос на app.example.com:8081 попадает в entrypoint admin и маршрутизируется на app1.

Маршрутизация по URL-путям с Traefik

Правило PathPrefix направляет запросы по префиксу пути:

services:
  app1:
    image: nginx:alpine
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app1.rule=Host(`app.example.com`) && PathPrefix(`/app1`)"
      - "traefik.http.routers.app1.entrypoints=web"
    networks:
      - proxy

Запросы на app.example.com/app1 и app.example.com/app1/anything уходят на app1. Для подмены пути на корень приложения используется middleware stripprefix. Подробнее о цепочках middleware и сложной маршрутизации в Traefik рассказано в пошаговом руководстве с YAML-примерами.

Типичные ошибки и их решение

Большинство проблем при настройке reverse proxy сводится к четырем причинам: сеть, слэши, заголовки, конфликты портов.

Ошибки сети и связности контейнеров

Симптом: Nginx или Traefik возвращает 502 Bad Gateway. Причина - прокси не может достучаться до контейнера приложения.

Проверьте, что оба контейнера подключены к одной сети:

docker network inspect proxy

В выводе должны быть оба контейнера. Если приложение в другой сети, добавьте его в общую сеть или создайте дополнительное подключение. Обращайтесь к сервису по имени из docker-compose.yml, а не по IP: IP-адреса контейнеров меняются при перезапуске.

Ошибки конфигурации proxy_pass и location

Симптом: приложение отвечает 404 на всех страницах или не находит статические файлы. Причина - неправильная обработка пути.

Правило простое: если location заканчивается на слэш, proxy_pass тоже должен заканчиваться на слэш. Тогда Nginx отрезает путь location и передает остаток. Если слэши не совпадают, путь склеивается некорректно.

Для WebSocket-соединений добавьте заголовки:

location /ws/ {
    proxy_pass http://app1:80;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Без этих заголовков WebSocket-соединение разрывается сразу после установки.

Конфликт портов возникает, когда контейнер приложения публикует тот же порт на хосте, что и прокси. Уберите ports у приложений, оставьте публикацию только у reverse proxy. Внутренние порты контейнеров не конфликтуют между собой.

Заключение: итоги и рекомендации

Reverse proxy в Docker - это единая точка входа для всех веб-приложений на хосте. Nginx подходит для стабильных стеков с ручной конфигурацией, Traefik - для динамических сред с автоматическим обнаружением контейнеров. Оба инструмента поддерживают маршрутизацию по доменам, портам и URL-путям.

Начните с создания общей сети в Docker Compose, затем настройте один сценарий маршрутизации и проверьте его. Не публикуйте порты приложений наружу, весь трафик должен идти через прокси. Проверяйте заголовки X-Forwarded-* и следите за слэшами в proxy_pass.

Для углубления в тему изучите руководство по маршрутизации процессов с готовыми конфигурациями и настройку Nginx Proxy Manager для production.

Поделиться:
Сохранить гайд? В закладки браузера