unRed

Инженерная документация

Запуск и настройка unRed: маршруты, сертификаты, доступ к сервисам, кэширование и диагностика.

Назначение

unRedirector (unRed) — обратный прокси на Go. Он направляет запросы к бэкендам по имени хоста и пути URL, распределяет нагрузку между серверами и раздаёт локальные файлы. В нём настраиваются TLS, аутентификация, кэширование и контроль доступности бэкендов.

Сценарии использования

Внутренние порталы, API, SST-серверы, WebDAV-хранилища и статические сайты. unRed принимает клиентские соединения и передаёт запросы нужному сервису.

Настройка

Настройки хранятся в JSON. Правила задают соответствие host/path → бэкенд. Маршруты можно обновлять без перезапуска через SIGHUP или online-reread.

Сборка и запуск

Для запуска нужен бинарник с действующей лицензией. Исходники находятся в source/; скрипты сборки в корне проекта добавляют версию и лицензионные параметры. Обычный go build без этих параметров создаёт бинарник, который при запуске без -sstini завершится с ошибкой лицензии.

Подготовьте config.json, доступный бэкенд и входящий TLS-сертификат. Команда ниже запускает готовый бинарник из текущего каталога.

Запуск готового бинарника
./unred.lin -config ./config.json -debug 2

Основные флаги

ФлагНазначение
-config <path>Путь к конфигурации JSON. По умолчанию config.json в рабочем каталоге.
-config-dir <path>Каталог с фрагментами *.json, которые объединяются с основной конфигурацией.
-online-rereadВключает отслеживание изменений файлов конфигурации и автоматическое перечитывание.
-sstini <path>Режим интеграции с SST: сертификат загружается из sst.ini. Источники certs в JSON и каталог certs/ в этом режиме не используются.
-install=1Установка службы systemd с правами root. Пользователем службы становится владелец рабочего каталога; значение флага не задаёт имя пользователя.
-versionВыводит версию и идентификатор коммита, затем завершает процесс.

Конфигурация

При загрузке JSON unRed обновляет маршруты, веса бэкендов и настройки модулей. SIGHUP перечитывает конфигурацию без перезапуска. Если новый файл содержит ошибку, она записывается в журнал, а процесс продолжает работать с предыдущей конфигурацией.

Когда нужен перезапуск Для изменения основных адресов прослушивания, настроек сброса привилегий, режима online-reread и блока http3 перезапустите процесс.

Основные параметры

КлючЧто делает
listen-http, listen-httpsАдреса прослушивания, например :80 и :443. listen-http перенаправляет запросы на основной HTTPS-порт; listen-https обслуживает маршруты.
rulesОбщие правила host[/path] → бэкенд.
rulesURLОбщие правила для всех хостов с точным совпадением пути URL.
configsНастройки отдельных хостов: аутентификация, маршруты, сертификаты, инспекция запросов и CGI.
balancer-weightВеса бэкендов: общий список или отдельные группы primary и backup.
balancerHealthПроверка доступности бэкендов по ошибкам запросов и отдельным контрольным обращениям.
backendTLSПроверка сертификатов бэкенда и клиентский сертификат для соединения с ним.
clientTLSПроверка сертификатов входящих клиентов.
http3Входящий HTTP/3 по QUIC/UDP на HTTPS-портах. По умолчанию выключен. Настройка и требования к сети.
rateLimitОграничения частоты запросов и числа соединений. Счётчики хранятся в памяти процесса.
cacheКэш снимков и кэш HTTP-ответов с учётом заголовков бэкенда.
passthrough_errorsПрефиксы host/path, для которых сохраняются исходные финальные статусы, заголовки и тела ответов бэкенда. Приоритетнее WebDAV-режима.
passthroughDAVВключает распознавание DAV по методу, кэшу адресов бэкендов (5 минут) или заголовку DAV текущего ответа. По умолчанию выключено; настройка хоста переопределяет общее значение.
webdavResponseModetransparent сохраняет финальные DAV-статусы; convert-200 меняет их на 200. Пустое значение в корне означает transparent, в настройках хоста — наследование. Сам режим не включает passthroughDAV.
stripExpect, proxyExpectПолитика Expect: 100-continue.

Маршрутизация и проксирование

Правило связывает имя хоста и, при необходимости, префикс пути URL с бэкендом. Среди совпавших префиксов выбирается самый длинный. Общие rulesURL сопоставляются с путём точно, а configs.<host>.rulesURL — по префиксу.

Значения правил

ЗначениеПоведение
http://..., https://...Передача запроса указанному HTTP- или HTTPS-бэкенду.
file://Раздача локальных файлов. Правила rulesURL в настройках хоста могут указывать подкаталог.
!https://...Передача запроса HTTPS-бэкенду с удалением совпавшего префикса пути. Например, правило для /api передаст /api/users как /users.
ключ из balancer-weightВыбор бэкенда с учётом заданных весов.
Пример маршрутов
{
  "rules": {
    "portal.example.com": "http://127.0.0.1:3000",
    "portal.example.com/static": "file://",
    "portal.example.com/api": "api-pool"
  },
  "balancer-weight": {
    "api-pool": {
      "primary": {
        "http://10.0.0.11:8080": 80,
        "http://10.0.0.12:8080": 20
      },
      "backup": {
        "http://10.0.0.21:8080": 100
      }
    }
  }
}

Ответы бэкенда

Для 3xx передаются исходные заголовки и допустимое тело; у 304 тела нет. Заголовки, относящиеся к отдельному соединению, удаляются. Завершающие заголовки сохраняются для gRPC. Для WebDAV режим convert-200 меняет финальный статус на 200, если запрос не совпал с passthrough_errors. Правила WebDAV.

Expect: 100-continue

По умолчанию заголовок Expect удаляется перед отправкой бэкенду. Чтобы передавать Expect: 100-continue и ожидать предварительный ответ бэкенда, установите одновременно stripExpect: false и proxyExpect: true.

Балансировка и доступность бэкендов

balancer-weight задаёт веса бэкендов общим списком или в группах primary и backup. Проверка доступности по умолчанию выключена. При включённом balancerHealth запросы направляются на доступные бэкенды.

Проверка по ошибкам запросов

Ошибки соединения увеличивают счётчик отказов. После maxFails ошибок бэкенд исключается из выбора на failTimeoutMs миллисекунд.

Периодические проверки

unRed отправляет GET-запросы по заданному пути с настроенным таймаутом и проверяет код ответа. Результат учитывается вместе с ошибками обычных запросов.

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

TLS и аутентификация

Входящие TLS-соединения

Сертификат выбирается по имени сервера, переданному клиентом через SNI. Файлы задаются в секции certs или загружаются из certs/<host>.crt и certs/<host>.key. В режиме -sstini используется сертификат SST.

ВозможностьПараметры
Сертификат для имени сервераcerts: {"example.com": {"cert": "...", "key": "..."}}
Проверка отзыва сертификата через OCSPcerts.<host>.ocsp.auto или ocsp.file
Обновление сертификатов через certbotconfigs.<host>["https-cert"]
Клиентские сертификатыclientTLS.mode: off, request, require, verify-if-given, require-and-verify
Проверка TLS-сертификата бэкендаbackendTLS.verify, caFile, serverName, clientCert, clientKey

Аутентификация

Аутентификация настраивается в configs.<host>.auth. Доступны проверка токена bearer и проверка Basic-данных через внешнюю программу (basic-binary), управляемую службу (basic-binary-port-controlled) или удалённый сервис (remote-hostport).

ВозможностьПараметры
Передача результата авторизации бэкендуauth.forwardPayload, auth.forwardPayloadMax (по умолчанию ограничение 8 КиБ)
Имя пользователя в заголовке ответа клиентуauth.responseUserHeader (например, "X-Auth-User"). Пустое значение отключает заголовок.
Кэш результатов аутентификацииauth.cache.positiveTtlSec, auth.cache.negativeTtlSec
Заголовки аутентификации Переданные клиентом заголовки идентификации X-SSL-Client-* удаляются перед обращением к бэкенду. При clientTLS.forwardHeaders: true прокси добавляет сведения из TLS-сертификата клиента. Параметр auth.responseUserHeader задаёт заголовок с именем прошедшего аутентификацию пользователя в ответе клиенту.

HTTP/3 и QUIC

unRed принимает HTTP/3-соединения по UDP. HTTP/1.1 и HTTP/2 продолжают работать по TCP. Для HTTP/3 действуют те же маршруты, аутентификация, ограничения запросов и режимы WebDAV. С бэкендами прокси соединяется по HTTP/1.1 или HTTP/2.

Параметр в http3По умолчаниюДействие
enabledfalseОткрыть UDP на адресах и портах работающих HTTPS-листенеров.
advertiseAltSvcfalseСообщать клиенту об HTTP/3 через заголовок Alt-Svc в HTTPS-ответах HTTP/1.1 и HTTP/2.
maxStreamsPerConn0 → 100Предел входящих двунаправленных потоков в одном QUIC-соединении.
idleTimeoutSec0 → 30Таймаут простоя QUIC-соединения в секундах.

HTTP/3 использует TLS 1.3, сертификаты HTTPS, SNI, OCSP и настройки клиентских сертификатов clientTLS. Ранние данные 0-RTT выключены: запросы обрабатываются после завершения TLS-согласования.

Порты и сеть

Разрешите UDP на основном и дополнительных HTTPS-портах, включая порты из правил. Например, адрес :9443 использует TCP 9443 и UDP 9443. Порты listen-http и правила с http:// обслуживают только TCP.

Alt-Svc объявляется только после открытия UDP-порта и указывает его фактический номер. При NAT внешний UDP-порт должен совпадать с объявленным. Если UDP недоступен или номера портов отличаются, оставьте advertiseAltSvc: false.

Перечитывание и диагностика

Изменение блока http3 требует перезапуска. UDP-порты из правил добавляются и удаляются при перечитывании маршрутов; перевод порта с HTTPS на обычный HTTP закрывает UDP. Ошибка открытия UDP при старте завершает процесс. При обновлении правил такая ошибка записывается в журнал, а остальные порты продолжают работать.

В /unRed/Listeners HTTP/3-адреса имеют proto: "http3". При SIGINT или SIGTERM HTTP/3 и основной HTTPS-сервер получают до 10 секунд на завершение запросов.

Для маршрутов с inspect: true и запросов CONNECT через HTTP/3 возвращается 501; используйте для них прежние HTTP-протоколы. WebSocket работает через TCP. Перенаправление произвольных UDP-пакетов — отдельная функция.

Пример HTTP/3 с сертификатом и бэкендом.

Кэширование

Кэш снимков включается через cache.enabled и применяется к URI, содержащим shot. Для кэширования HTTP-ответов с учётом заголовков бэкенда дополнительно включите cache.respectUpstreamCacheControl: true.

КлючНазначение
cache.maxAgeMsВремя хранения снимков в кэше, в миллисекундах.
respectUpstreamCacheControlУчитывает Cache-Control, Vary, ETag и Last-Modified при кэшировании HTTP-ответов.
cacheKeyVaryЗаголовки запроса, значения которых добавляются в ключ кэша.
staleWhileRevalidateMsСколько миллисекунд можно отдавать просроченный ответ, пока он обновляется в фоне, если бэкенд не указал свой срок.
purgeAuthTokenСекрет для POST /unRed/CachePurge. Пустое значение отключает очистку через этот адрес.
maxBodyBytesМаксимальный размер тела для HTTP-кэша. По умолчанию 4 МиБ; более крупные ответы передаются без сохранения.

Протоколы

WebSocket

После согласования Upgrade прокси передаёт сообщения между клиентом и бэкендом в обоих направлениях.

gRPC

Ответы application/grpc* сохраняют завершающие HTTP/2-заголовки, включая статус gRPC. Тела ошибок не заменяются, HTTP-кэш не сохраняет такие ответы.

WebDAV

При passthroughDAV: true unRed определяет WebDAV по методу запроса и заголовкам бэкенда. В режиме webdavResponseMode: "transparent" клиент получает исходный финальный статус, заголовки и тело ответа. Например, 207 с XML остаётся 207, ошибка 423 остаётся 423.

В режиме convert-200 все финальные статусы WebDAV-ответов заменяются на 200, включая 207, редиректы и ошибки. Содержимое тела сохраняется. Этот режим нужен клиентам, которые ожидают HTTP 200 независимо от результата операции. Для обычных WebDAV-клиентов используйте transparent.

103 Early Hints

Включите earlyHints.enabled: true и earlyHints.passthrough: true, чтобы передавать клиенту промежуточные ответы 103 до основного ответа. Они могут содержать Link: rel=preload для предварительной загрузки ресурсов.

Перенаправление TCP, включая TURN

tcpRelay.listeners открывает дополнительные TCP-порты и передаёт поток в обоих направлениях. Например, порты 3478 и 5349 позволяют подключаться к TURN/TURNS-бэкенду по TCP. Эта настройка применяется только к TCP.

WebDAV: правила применения

DAV распознаётся по методу (например, PROPFIND или LOCK), по заголовку DAV в ответе этого бэкенда за последние пять минут или в текущем ответе. Первый OPTIONS с заголовком DAV уже обрабатывается выбранным режимом. Обычный GET без этих признаков не становится DAV автоматически.

Оба параметра задаются в корне и в configs.<host>. Для passthroughDAV отсутствие или null означает наследование, явное false отключает детектор. Для webdavResponseMode пустая строка наследует общее значение. При выборе хоста порт отбрасывается; поддерживаются имена с шаблонами, например *.example.com. Режим без включённого детектора не действует. Неизвестное значение режима вызывает ошибку загрузки; при ошибке перечитывания остаётся прежняя конфигурация.

Приоритет и ответы без тела Совпавший passthrough_errors всегда сохраняет исходный статус, даже при convert-200. Если тип запроса или ответа — application/grpc*, преобразования нет, включая 503 text/plain в ответ на gRPC-запрос. Ответы на HEAD и исходные 204/304 остаются без тела; при преобразовании 304 в 200 для запросов, кроме HEAD, выставляется Content-Length: 0. HEAD сохраняет исходный Content-Length представления.

На хостах с включённым DAV-детектором и при совпадении passthrough_errors оба кэша HTTP-ответов обходятся. Прокси передаёт редиректы бэкенда клиенту, не следуя им самостоятельно. В сохраняемых ответах исходный Content-Type не переопределяется по содержимому тела. Заголовки ответа передаются клиенту, кроме тех, которые относятся к отдельному соединению. Статусы, заголовки и содержимое тела сохраняются на уровне HTTP; разбиение на TCP-пакеты и HTTP-фрагменты может меняться.

Политика работает в обычной HTTP-ветке при inspect: false. Локальные отказы аутентификации, ограничения запросов и ошибки соединения сохраняют свои коды. Эта политика не применяется к inspect, отдельным TCP-туннелям и WebSocket. Примеры transparent и convert-200.

Мониторинг и диагностика

Встроенные страницы и счётчики доступны через HTTPS. Начальная страница /unRed содержит ссылки на модули диагностики.

Ограничьте доступ к служебным адресам сетевыми правилами или внешним прокси с аутентификацией. Настройка configs.<host>.auth защищает маршруты приложений и не распространяется на эти адреса.

АдресЧто показывает
/unRedСписок модулей и состояние лицензии.
/unRed/StatusСостояние процесса и журнал с обновлением через WebSocket.
/unRed/LoadЗагрузка CPU, использование памяти и число потоков с обновлением через WebSocket.
/unRed/trafficОбъём HTTP-трафика и потоковых соединений по адресам.
/unRed/cert-statusСостояние сертификатов и сроки действия в виде HTML-страницы.
/unRed/cert-status-jsonСостояние сертификатов в формате JSON.
/unRed/configuredRoutesДействующая таблица маршрутов, включая резервные бэкенды с пометкой [backup].
/unRed/configuredAuthНастройки аутентификации по хостам.
/unRed/configDumpДействующая конфигурация для проверки результатов перечитывания.
/unRed/CacheStatsСчётчики HTTP-кэша и крупнейшие записи.
/unRed/RateLimitСчётчики зон ограничения запросов.
/unRed/BalancerHealthСостояние каждого бэкенда по результатам проверок доступности.
/unRed/TCPRelayСчётчики TCP-портов: принятые и открытые соединения, ошибки подключения к бэкенду.
/unRed/ListenersСлушающие адреса и порты: HTTPS, HTTP, HTTP-перенаправления и HTTP/3 по UDP.

В разработке

Планируемые возможности.

ВозможностьНазначениеСтатус
HTTP/2 server pushОтправка ресурсов клиенту до отдельного запроса.В разработке
Преобразование содержимого ответовОбщие правила замены текста, HTML-вставок и обработки тела ответа.В разработке
Общие счётчики и состояние бэкендовСогласованные ограничения запросов и проверки доступности между несколькими процессами unRed.В разработке
Передача UDPПеренаправление UDP-пакетов, включая STUN, TURN и RTP.В разработке
Установка службы WindowsРегистрация и запуск unRed как службы Windows встроенной командой.В разработке
Единая панель мониторингаМаршруты, сертификаты, трафик и состояние бэкендов на одном экране.В разработке
Экспорт в PrometheusПередача метрик в формате Prometheus в дополнение к встроенным JSON-счётчикам.В разработке
Настройка служебных страницВключение и отключение страниц состояния и нагрузки, изменение адресов статистики и очистки кэша.В разработке
Расширенные параметры gRPCУправление включением gRPC и таймаутами чтения, записи и простоя потока.В разработке