Skip to content

Домены

Фреймворк поддерживает виртуальные хосты — несколько доменов на одном сервере (или несколько серверов на одном ip:port). Домены задаются массивом строк и могут быть точными именами, содержать подстановочные знаки * или полноценные регулярные выражения.

json
"servers": {
    "s1": {
        "domains": [
            "example.com",
            "www.example.com",
            "*.example.com",
            "mail.*",
            "(api|www).example.com"
        ],
        "ip": "0.0.0.0",
        "port": 80,
        ...
    },
    ...
}

Как происходит сопоставление

Виртуальный сервер выбирается по значению HTTP-заголовка Host. Перед сравнением выполняется нормализация:

  1. Порт отсекается — из example.com:8080 остаётся example.com.
  2. IPv6-литералы обрабатываются по RFC 3986: скобки [::1]:8080 снимаются, для сравнения берётся сам адрес ::1.
  3. IDN-преобразование — домен в UTF-8 (например, пример.рф) конвертируется в Punycode (xn--80akhbyknj4f.xn--p1ai), см. Интернационализированные домены (IDN).

Затем значение поочерёдно сравнивается с доменами каждого сервера, привязанного к тому же ip:port. Совпало первым — выиграло: приоритет между точным именем, wildcard и регулярным выражением отсутствует, порядок определяется только последовательностью в массиве domains. Поэтому более специфичные имена следует размещать выше общих.

Порядок имеет значение

Поскольку *.example.com захватывает и www.example.com, и более глубокие адреса, размещайте точные имена и узкие шаблоны выше wildcard, чтобы они не «перекрывались».

Если подходящий сервер не найден, клиент получит 404 Not Found. Пустой или отсутствующий заголовок Host (он обязателен в HTTP/1.1) приводит к 400 Bad Request.

Подстановочные имена

Звёздочка * допускается только в начале или в конце имени и раскрывается в регулярное выражение .*:

json
"domains": [
    "*.example.com",
    "mail.*"
]
  • *.example.com матчит как www.example.com, так и www.sub.example.com — звёздочка захватывает сразу несколько уровней.
  • mail.* матчит mail.com, mail.org и тому подобное.
  • Имена вида w*.example.com или www.*.example.org недопустимы — звёздочка в середине вызывает ошибку загрузки конфигурации. Такие случаи реализуются регулярным выражением (см. ниже).

Внутри скобочных групп (...) и [...] символы * и . сохраняют regex-смысл (квантификатор и «любой символ» соответственно) и не подвергаются автопреобразованию.

Регулярные выражения

В качестве имени домена можно использовать регулярное выражение, совместимое с PCRE (Perl Compatible Regular Expressions):

json
"domains": [
    "(api|www).example.com",
    "^www(\\d+).example.net$",
    "(.1|.*|a3).example.com"
]

Особенности обработки:

  • Точки экранируются автоматически. Символ . вне скобок превращается в \., поэтому example.com можно писать как есть, без экранирования. Внутри (...) / [...] . сохраняет смысл «любой символ».
  • Автоматическое якорение. Если выражение не содержит ни ^ в начале, ни $ в конце, шаблон автоматически оборачивается в ^...$ (полное совпадение). Указав хотя бы один из якорей, вы полностью отключаете авто-якорение.
  • Чувствительность к регистру. Сопоставление регистрозависимо; браузеры обычно отправляют Host в нижнем регистре.

Интернационализированные домены (IDN)

Поддержка кириллических и иных национальных доменов реализована через libidn2. Домены в конфигурации можно задавать в UTF-8 — при загрузке они конвертируются в Punycode, и то же преобразование применяется к заголовку Host (и TLS SNI) во время сравнения:

json
"domains": [
    "пример.рф",
    "*.пример.рф"
]

Если Host содержит некорректный IDN, который невозможно преобразовать, клиент получит 404 Not Found.

TLS и SNI

На TLS-соединениях виртуальный сервер первоначально выбирается по SNI (Server Name Indication). Как SNI, так и последующий заголовок Host проходят IDN-преобразование и сравниваются с одними и теми же шаблонами.

Согласно RFC 9110, на TLS-соединении с SNI заголовок Host обязан соответствовать серверу, выбранному по SNI. Если они расходятся — клиент получит 404 Not Found.

Краткая справка

СитуацияОтвет
Пустой или отсутствующий Host (HTTP/1.1)400 Bad Request
Ни один домен не совпал404 Not Found
Host не соответствует серверу, выбранному по SNI (TLS)404 Not Found
Некорректный IDN в Host404 Not Found

Выпущено под лицензией MIT.