Перейти к содержимому
ИТ-администрирование

Как разместить несколько сайтов и сервисов за одним внешним IP

Как работает reverse proxy, зачем нужен split DNS, где выпускаются и продлеваются сертификаты, что ломает WebSocket и крупные загрузки, и что резервировать в конфигурации.

5 минут чтенияКоманда RKTSocial

Внешний IP-адрес обычно один, а сервисов, которые нужно опубликовать, — десятки: корпоративное облако, вики, система задач, мониторинг, сайты. Пробрасывать каждому свой порт неудобно и небезопасно: адреса вида `example.com:8443` неудобны людям, а каждый открытый порт — отдельная точка входа.

Рабочая схема — один вход, маршрутизация по доменному имени.

Как это работает

Все домены указывают на один внешний адрес. На нём стоит reverse proxy — он принимает соединение, завершает TLS, смотрит на имя запрошенного узла и передаёт запрос нужному внутреннему сервису.

                     ┌──────────────────────────┐
cloud.example.com ─┐ │  reverse proxy           │ ─→ 127.0.0.1:8080  облако
wiki.example.com  ─┼→│  один внешний адрес,     │ ─→ 127.0.0.1:8081  вики
git.example.com   ─┤ │  TLS, маршрутизация      │ ─→ 127.0.0.1:8082  git
shop.example.com  ─┘ │  по имени узла           │ ─→ 127.0.0.1:3000  сайт
                     └──────────────────────────┘

Ключевой момент: имя узла передаётся в заголовке запроса, поэтому один адрес и один порт 443 обслуживают любое количество сервисов. Внутренние приложения при этом слушают только локальный интерфейс и наружу не выставлены вовсе.

Что нужно настроить

  1. Шаг 1

    DNS: все имена на один адрес

    Для каждого сервиса заводится своя A-запись, указывающая на внешний адрес. Отдельных адресов не требуется.

  2. Шаг 2

    Сертификаты

    Выпускаются на конкретные имена. Проверка обычно проходит по HTTP: proxy отдаёт файл подтверждения из общего каталога, поэтому правило для него настраивается один раз для всех доменов.

  3. Шаг 3

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

    На каждый домен — свой блок конфигурации с адресом внутреннего сервиса. Ошибка здесь приводит к тому, что запрос уходит не туда, — об этом ниже.

  4. Шаг 4

    Заголовки для приложения

    Внутренний сервис должен знать исходное имя узла, адрес клиента и протокол. Без них ломаются редиректы и в логах видно только адрес proxy.

  5. Шаг 5

    Отдельные правила для особых случаев

    WebSocket, крупные загрузки, длинные ответы — им нужны свои настройки таймаутов и лимитов.

  6. Шаг 6

    Split DNS для внутренней сети

    Чтобы адреса совпадали внутри офиса и снаружи.

Split DNS: одинаковые адреса внутри и снаружи

Проблема: сотрудник в офисе открывает `wiki.example.com`, запрос уходит на внешний адрес и возвращается обратно через провайдера. В части конфигураций такой разворот не работает вовсе, и внутри сети сервис оказывается недоступен.

Решение — split DNS: внутренний DNS-сервер отдаёт для тех же имён внутренний адрес proxy, внешний отдаёт внешний.

Откуда запросЧто отдаёт DNSМаршрут
Из офисаВнутренний адрес proxyНапрямую внутри сети
ИзвнеВнешний адресЧерез провайдера на тот же proxy

Так и сотрудники, и удалённые пользователи, и документация используют один адрес. Без этого появляются два комплекта ссылок, и половина из них где-нибудь не работает.

Типичные проблемы

Запрос попадает не на тот сервис

Если для запрошенного имени нет подходящего блока конфигурации, proxy отдаёт запрос первому подходящему по своим правилам — обычно первому в порядке загрузки. Внешне это выглядит как «мой домен показывает чужой сайт».

Особенно неприятен вариант, когда чужой блок отвечает постоянным редиректом: такой ответ кешируется браузерами и поисковиками, и последствия переживают исправление конфигурации.

Профилактика: заводить конфигурацию домена до того, как на него переключается DNS, и явно задавать блок по умолчанию для необслуживаемых имён.

Сломанный WebSocket

Чаты, панели мониторинга и совместное редактирование используют постоянное соединение. Без передачи заголовков смены протокола соединение обрывается, а приложение выглядит «подвисающим» без ошибок в интерфейсе.

Ограничение размера загрузки

У proxy есть лимит размера тела запроса, обычно небольшой по умолчанию. Пользователь пытается загрузить файл в облако и получает ошибку, хотя само приложение настроено правильно. Лимит нужно выставлять на обеих сторонах.

Истёкший сертификат

Автопродление настроено, но после обновления сертификата proxy не перечитал конфигурацию и продолжает отдавать старый. Или продление тихо не сработало, и об этом никто не узнал до предупреждения в браузере.

Профилактика: хук перезагрузки после продления и отдельная проверка в мониторинге по сроку действия сертификата, а не по факту запуска задания.

Потеря реального адреса клиента

Если не передавать исходный адрес, приложение видит только адрес proxy. Ломаются ограничения по количеству запросов, геолокация и разбор инцидентов по логам.

Безопасность

  • Внутренние сервисы слушают только локальный интерфейс. Иначе публикация через proxy не мешает обратиться к ним напрямую по порту.
  • Разделять публичное и внутреннее. Часть сервисов не должна быть доступна из интернета вовсе — их публикуют только внутри сети или через VPN.
  • Ограничение частоты запросов на публичных адресах: снижает эффект перебора и простых атак.
  • Заголовки безопасности задаются приложением или proxy, но в одном месте — дублирование приводит к тому, что заголовок уходит дважды.
  • Отключить выдачу версии сервера и листинг каталогов.
  • Логи по каждому домену отдельно — иначе разбор инцидента превращается в поиск по общей куче.

Что резервировать

Конфигурация публикации — это тоже данные, и их потеря означает, что схему придётся собирать заново по памяти.

  • конфигурационные файлы proxy целиком, включая общие фрагменты;
  • сертификаты и закрытые ключи, вместе с настройками автопродления;
  • зоны DNS — внутренние и внешние;
  • перечень «домен → внутренний сервис → порт» в понятном человеку виде.

Последний пункт часто недооценивают. При восстановлении с нуля именно эта таблица экономит больше всего времени: конфигурацию можно собрать заново, а вот вспомнить, какой сервис на каком порту жил, — сложно.

Как убедиться, что эти копии действительно разворачиваются, — в материале о тестовом восстановлении.

Порядок публикации нового сервиса

  1. Поднять сервис локально, привязать к локальному интерфейсу.
  2. Завести A-запись домена на внешний адрес и внутреннюю запись в split DNS.
  3. Создать блок конфигурации proxy до переключения трафика.
  4. Выпустить сертификат, проверить автопродление и хук перезагрузки.
  5. Проверить: HTTPS отвечает, HTTP уходит редиректом, WebSocket работает, крупный файл загружается.
  6. Добавить сервис в мониторинг: доступность, срок сертификата, время ответа.
  7. Внести в резервное копирование конфигурацию и обновить таблицу «домен → сервис».

Шестой пункт закрывает самый частый сценарий: сервис опубликовали, а узнают о его недоступности от пользователей. Что именно стоит проверять — в разборе мониторинга серверов.