Mercurial Hosting > d2o
diff README.md @ 1:3e7247db5c6e
show index.html
| author | Atarwn Gard <a@qwa.su> |
|---|---|
| date | Mon, 09 Mar 2026 01:04:16 +0500 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Mon Mar 09 01:04:16 2026 +0500 @@ -0,0 +1,273 @@ +# d2o + +Минималистичный веб-сервер на Go с конфигурацией в формате ICF. + +## Структура проекта + +``` +d2o/ + go.mod + cmd/d2o/ + main.go — точка входа, HTTP-обработчик, сборка листеров + icf/ + icf.go — парсер формата ICF (переиспользуемая библиотека) + fcgi/ + fcgi.go — минимальный FastCGI-клиент +``` + +## Сборка и запуск + +```sh +go build -o d2o ./cmd/d2o/ +./d2o # читает /etc/d2obase +./d2o /path/to/config # альтернативный путь +``` + +--- + +## Формат конфигурации ICF + +**ICF (Inherited Configuration Format)** — текстовый формат правил вида «паттерн → директивы». +Вдохновлён синтаксисом bash и базами данных CoreDNS. + +### Основные правила синтаксиса + +``` +; Это комментарий + +; Переменная (без пробелов вокруг =) +KEY=value + +; Абстрактный блок (миксин) +@name +|> directive arg1 arg2 + +; Конкретный блок с наследованием миксина +block.id @mixin +|> directive arg1 arg2 + +; Блок с именованным capture-группой +<sub>.example.com +|> root /srv/$sub +``` + +### Переменные + +Объявляются как `KEY=value` на уровне файла. Подставляются через `$KEY` в аргументах директив. + +``` +WWW=/srv/www +CERT=/etc/acme/example.com + +example.com +|> root $WWW/root +|> tls $CERT.{crt,key} +``` + +### Brace expansion + +Аргумент `prefix.{a,b,c}` раскрывается в три отдельных аргумента: `prefix.a`, `prefix.b`, `prefix.c`. +Порядок важен — используется для `tls`, где первый аргумент сертификат, второй ключ. + +``` +|> tls /etc/acme/example.com.{crt,key} +; эквивалентно: +|> tls /etc/acme/example.com.crt /etc/acme/example.com.key +``` + +### Capture-группы + +В идентификаторе блока `<name>` захватывает любую подстроку до следующего литерала. +`<_>` — анонимный wildcard, ничего не сохраняет. + +``` +<sub>.example.com +|> root /srv/$sub ; $sub подставляется из захваченного значения + +<_>.static.example.com +|> root /srv/static ; совпадает с чем угодно, capture не нужен +``` + +Capture жадный слева: `<sub>.example.com` на запрос `a.b.example.com` даст `sub=a.b`. + +### Кавычки в аргументах + +Аргументы с пробелами берутся в двойные кавычки: + +``` +|> fcgi unix:/run/php-fpm.sock "*.php" +``` + +### Абстрактные блоки и наследование + +`@name` задаёт набор директив без привязки к паттерну. +Конкретный блок наследует их через `block.id @name` — директивы миксина идут первыми, директивы блока их перекрывают. + +``` +@base +|> port 80 +|> port+tls 443 + +example.com @base +|> root /srv/www ; наследует port 80 и port+tls 443 + +other.com @base +|> root /srv/other ; то же самое +``` + +### Матчинг блоков + +- Домен матчится точно (с учётом capture-групп). +- Путь матчится как префикс: блок `example.com/api` сработает на `/api/users`. +- При нескольких совпадениях выигрывает наиболее специфичный (больше совпавших литеральных символов). +- Сначала проверяется `host/path`, потом `host`. + +``` +example.com +|> root /srv/www + +example.com/api +|> rprx 127.0.0.1:8080 ; перекрывает блок выше для /api/* +``` + +--- + +## Конфигурация d2o + +Файл по умолчанию: `/etc/d2obase` + +### @d2o — настройки сервера + +``` +@d2o +|> threads 512 ; GOMAXPROCS +``` + +| Директива | Аргументы | Описание | +|------------|-----------|----------| +| `threads` | N | Количество потоков ОС (GOMAXPROCS) | + +### port — HTTP-листенер + +``` +|> port 80 +``` + +| # | Тип | Описание | +|---|-------|--------------| +| 1 | `int` | Номер порта | + +### port+tls — HTTPS-листенер + +``` +|> port+tls 443 +; сертификат берётся из директивы tls того же блока +``` + +Знак `+` в имени директивы — обычный символ, не оператор. + +| # | Тип | Описание | +|---|--------|-----------------------------------------------| +| 1 | `int` | Номер порта | +| 2 | `path` | Путь к сертификату (необязателен, если есть `tls`) | +| 3 | `path` | Путь к ключу (необязателен, если есть `tls`) | + +### tls — пути к сертификату и ключу + +``` +|> tls /etc/acme/example.com.{crt,key} +``` + +Используется как источник сертификата для `port+tls` в том же блоке, если пути не указаны явно. + +| # | Тип | Описание | +|---|--------|-------------------| +| 1 | `path` | Путь к сертификату | +| 2 | `path` | Путь к ключу | + +### root — отдача статики + +``` +|> root /srv/www/example.com +|> root /srv/www/example.com hide ; листинг запрещён (по умолчанию) +|> root /srv/www/example.com show ; листинг разрешён, index-файл index.html +|> root /srv/www/example.com show index.php index.html ; свои index-файлы +``` + +| # | Тип | Описание | +|---|--------|---------------------------------| +| 1 | `path` | Корневая директория | +| 2 | `show\|hide` | Режим директорий (по умолчанию `hide`) | +| 3–14 | `filename` | Index-файлы (только с `show`), проверяются по порядку | + +При `show`: сначала ищутся index-файлы по списку, если ни один не найден — отдаётся листинг директории. +При `hide` или без аргумента: запрос к директории возвращает 403. + +### fcgi — FastCGI + +``` +|> fcgi unix:/run/php-fpm.sock +|> fcgi unix:/run/php-fpm.sock "*.php" ; только .php файлы +|> fcgi 127.0.0.1:9000 "*.php" +``` + +| # | Тип | Описание | +|---|---------|----------------------------------------------------| +| 1 | `addr` | Адрес сокета: `unix:/path` или `host:port` | +| 2 | `glob` | Паттерн файлов (по умолчанию `*`, все запросы) | + +Если glob не совпадает, запрос падает в `root` (если задан). + +### rprx — обратный прокси + +``` +|> rprx 127.0.0.1:3000 +|> rprx http://127.0.0.1:3000 +``` + +| # | Тип | Описание | +|---|-------|---------------------------------| +| 1 | `url` | Адрес backend (схема необязательна, по умолчанию `http://`) | + +### Приоритет директив + +При одновременном наличии нескольких директив порядок обработки: **rprx > fcgi > root**. + +--- + +## Пример полного конфига + +``` +; /etc/d2obase + +ACME=/etc/acme/qwaderton.org +WWW=/srv/www/qwaderton.org + +@d2o +|> threads 512 + +@ports +|> tls $ACME.{crt,key} +|> port 80 +|> port+tls 443 + +qwaderton.org @ports +|> root $WWW/root show index.php index.html + +qwaderton.org/webfeather @ports +|> root $WWW/root/webfeather +|> fcgi unix:/run/php-fpm.sock *.php + +<sub>.qwaderton.org @ports +|> root $WWW/$sub +``` + +--- + +## Известные ограничения + +- **Один миксин на блок.** Множественное наследование не поддерживается. +- **Brace expansion без вложенности.** `{a,{b,c}}` не работает. +- **FastCGI — один запрос на соединение.** Keep-alive с FPM не реализован. +- **Нет HTTP→HTTPS редиректа** из коробки — нужно реализовывать отдельным блоком на порту 80. +- **Нет hot reload** конфига — требуется перезапуск процесса. \ No newline at end of file
