Mercurial Hosting > d2o
comparison README.md @ 1:3e7247db5c6e
show index.html
| author | Atarwn Gard <a@qwa.su> |
|---|---|
| date | Mon, 09 Mar 2026 01:04:16 +0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:48bdab3eec8a | 1:3e7247db5c6e |
|---|---|
| 1 # d2o | |
| 2 | |
| 3 Минималистичный веб-сервер на Go с конфигурацией в формате ICF. | |
| 4 | |
| 5 ## Структура проекта | |
| 6 | |
| 7 ``` | |
| 8 d2o/ | |
| 9 go.mod | |
| 10 cmd/d2o/ | |
| 11 main.go — точка входа, HTTP-обработчик, сборка листеров | |
| 12 icf/ | |
| 13 icf.go — парсер формата ICF (переиспользуемая библиотека) | |
| 14 fcgi/ | |
| 15 fcgi.go — минимальный FastCGI-клиент | |
| 16 ``` | |
| 17 | |
| 18 ## Сборка и запуск | |
| 19 | |
| 20 ```sh | |
| 21 go build -o d2o ./cmd/d2o/ | |
| 22 ./d2o # читает /etc/d2obase | |
| 23 ./d2o /path/to/config # альтернативный путь | |
| 24 ``` | |
| 25 | |
| 26 --- | |
| 27 | |
| 28 ## Формат конфигурации ICF | |
| 29 | |
| 30 **ICF (Inherited Configuration Format)** — текстовый формат правил вида «паттерн → директивы». | |
| 31 Вдохновлён синтаксисом bash и базами данных CoreDNS. | |
| 32 | |
| 33 ### Основные правила синтаксиса | |
| 34 | |
| 35 ``` | |
| 36 ; Это комментарий | |
| 37 | |
| 38 ; Переменная (без пробелов вокруг =) | |
| 39 KEY=value | |
| 40 | |
| 41 ; Абстрактный блок (миксин) | |
| 42 @name | |
| 43 |> directive arg1 arg2 | |
| 44 | |
| 45 ; Конкретный блок с наследованием миксина | |
| 46 block.id @mixin | |
| 47 |> directive arg1 arg2 | |
| 48 | |
| 49 ; Блок с именованным capture-группой | |
| 50 <sub>.example.com | |
| 51 |> root /srv/$sub | |
| 52 ``` | |
| 53 | |
| 54 ### Переменные | |
| 55 | |
| 56 Объявляются как `KEY=value` на уровне файла. Подставляются через `$KEY` в аргументах директив. | |
| 57 | |
| 58 ``` | |
| 59 WWW=/srv/www | |
| 60 CERT=/etc/acme/example.com | |
| 61 | |
| 62 example.com | |
| 63 |> root $WWW/root | |
| 64 |> tls $CERT.{crt,key} | |
| 65 ``` | |
| 66 | |
| 67 ### Brace expansion | |
| 68 | |
| 69 Аргумент `prefix.{a,b,c}` раскрывается в три отдельных аргумента: `prefix.a`, `prefix.b`, `prefix.c`. | |
| 70 Порядок важен — используется для `tls`, где первый аргумент сертификат, второй ключ. | |
| 71 | |
| 72 ``` | |
| 73 |> tls /etc/acme/example.com.{crt,key} | |
| 74 ; эквивалентно: | |
| 75 |> tls /etc/acme/example.com.crt /etc/acme/example.com.key | |
| 76 ``` | |
| 77 | |
| 78 ### Capture-группы | |
| 79 | |
| 80 В идентификаторе блока `<name>` захватывает любую подстроку до следующего литерала. | |
| 81 `<_>` — анонимный wildcard, ничего не сохраняет. | |
| 82 | |
| 83 ``` | |
| 84 <sub>.example.com | |
| 85 |> root /srv/$sub ; $sub подставляется из захваченного значения | |
| 86 | |
| 87 <_>.static.example.com | |
| 88 |> root /srv/static ; совпадает с чем угодно, capture не нужен | |
| 89 ``` | |
| 90 | |
| 91 Capture жадный слева: `<sub>.example.com` на запрос `a.b.example.com` даст `sub=a.b`. | |
| 92 | |
| 93 ### Кавычки в аргументах | |
| 94 | |
| 95 Аргументы с пробелами берутся в двойные кавычки: | |
| 96 | |
| 97 ``` | |
| 98 |> fcgi unix:/run/php-fpm.sock "*.php" | |
| 99 ``` | |
| 100 | |
| 101 ### Абстрактные блоки и наследование | |
| 102 | |
| 103 `@name` задаёт набор директив без привязки к паттерну. | |
| 104 Конкретный блок наследует их через `block.id @name` — директивы миксина идут первыми, директивы блока их перекрывают. | |
| 105 | |
| 106 ``` | |
| 107 @base | |
| 108 |> port 80 | |
| 109 |> port+tls 443 | |
| 110 | |
| 111 example.com @base | |
| 112 |> root /srv/www ; наследует port 80 и port+tls 443 | |
| 113 | |
| 114 other.com @base | |
| 115 |> root /srv/other ; то же самое | |
| 116 ``` | |
| 117 | |
| 118 ### Матчинг блоков | |
| 119 | |
| 120 - Домен матчится точно (с учётом capture-групп). | |
| 121 - Путь матчится как префикс: блок `example.com/api` сработает на `/api/users`. | |
| 122 - При нескольких совпадениях выигрывает наиболее специфичный (больше совпавших литеральных символов). | |
| 123 - Сначала проверяется `host/path`, потом `host`. | |
| 124 | |
| 125 ``` | |
| 126 example.com | |
| 127 |> root /srv/www | |
| 128 | |
| 129 example.com/api | |
| 130 |> rprx 127.0.0.1:8080 ; перекрывает блок выше для /api/* | |
| 131 ``` | |
| 132 | |
| 133 --- | |
| 134 | |
| 135 ## Конфигурация d2o | |
| 136 | |
| 137 Файл по умолчанию: `/etc/d2obase` | |
| 138 | |
| 139 ### @d2o — настройки сервера | |
| 140 | |
| 141 ``` | |
| 142 @d2o | |
| 143 |> threads 512 ; GOMAXPROCS | |
| 144 ``` | |
| 145 | |
| 146 | Директива | Аргументы | Описание | | |
| 147 |------------|-----------|----------| | |
| 148 | `threads` | N | Количество потоков ОС (GOMAXPROCS) | | |
| 149 | |
| 150 ### port — HTTP-листенер | |
| 151 | |
| 152 ``` | |
| 153 |> port 80 | |
| 154 ``` | |
| 155 | |
| 156 | # | Тип | Описание | | |
| 157 |---|-------|--------------| | |
| 158 | 1 | `int` | Номер порта | | |
| 159 | |
| 160 ### port+tls — HTTPS-листенер | |
| 161 | |
| 162 ``` | |
| 163 |> port+tls 443 | |
| 164 ; сертификат берётся из директивы tls того же блока | |
| 165 ``` | |
| 166 | |
| 167 Знак `+` в имени директивы — обычный символ, не оператор. | |
| 168 | |
| 169 | # | Тип | Описание | | |
| 170 |---|--------|-----------------------------------------------| | |
| 171 | 1 | `int` | Номер порта | | |
| 172 | 2 | `path` | Путь к сертификату (необязателен, если есть `tls`) | | |
| 173 | 3 | `path` | Путь к ключу (необязателен, если есть `tls`) | | |
| 174 | |
| 175 ### tls — пути к сертификату и ключу | |
| 176 | |
| 177 ``` | |
| 178 |> tls /etc/acme/example.com.{crt,key} | |
| 179 ``` | |
| 180 | |
| 181 Используется как источник сертификата для `port+tls` в том же блоке, если пути не указаны явно. | |
| 182 | |
| 183 | # | Тип | Описание | | |
| 184 |---|--------|-------------------| | |
| 185 | 1 | `path` | Путь к сертификату | | |
| 186 | 2 | `path` | Путь к ключу | | |
| 187 | |
| 188 ### root — отдача статики | |
| 189 | |
| 190 ``` | |
| 191 |> root /srv/www/example.com | |
| 192 |> root /srv/www/example.com hide ; листинг запрещён (по умолчанию) | |
| 193 |> root /srv/www/example.com show ; листинг разрешён, index-файл index.html | |
| 194 |> root /srv/www/example.com show index.php index.html ; свои index-файлы | |
| 195 ``` | |
| 196 | |
| 197 | # | Тип | Описание | | |
| 198 |---|--------|---------------------------------| | |
| 199 | 1 | `path` | Корневая директория | | |
| 200 | 2 | `show\|hide` | Режим директорий (по умолчанию `hide`) | | |
| 201 | 3–14 | `filename` | Index-файлы (только с `show`), проверяются по порядку | | |
| 202 | |
| 203 При `show`: сначала ищутся index-файлы по списку, если ни один не найден — отдаётся листинг директории. | |
| 204 При `hide` или без аргумента: запрос к директории возвращает 403. | |
| 205 | |
| 206 ### fcgi — FastCGI | |
| 207 | |
| 208 ``` | |
| 209 |> fcgi unix:/run/php-fpm.sock | |
| 210 |> fcgi unix:/run/php-fpm.sock "*.php" ; только .php файлы | |
| 211 |> fcgi 127.0.0.1:9000 "*.php" | |
| 212 ``` | |
| 213 | |
| 214 | # | Тип | Описание | | |
| 215 |---|---------|----------------------------------------------------| | |
| 216 | 1 | `addr` | Адрес сокета: `unix:/path` или `host:port` | | |
| 217 | 2 | `glob` | Паттерн файлов (по умолчанию `*`, все запросы) | | |
| 218 | |
| 219 Если glob не совпадает, запрос падает в `root` (если задан). | |
| 220 | |
| 221 ### rprx — обратный прокси | |
| 222 | |
| 223 ``` | |
| 224 |> rprx 127.0.0.1:3000 | |
| 225 |> rprx http://127.0.0.1:3000 | |
| 226 ``` | |
| 227 | |
| 228 | # | Тип | Описание | | |
| 229 |---|-------|---------------------------------| | |
| 230 | 1 | `url` | Адрес backend (схема необязательна, по умолчанию `http://`) | | |
| 231 | |
| 232 ### Приоритет директив | |
| 233 | |
| 234 При одновременном наличии нескольких директив порядок обработки: **rprx > fcgi > root**. | |
| 235 | |
| 236 --- | |
| 237 | |
| 238 ## Пример полного конфига | |
| 239 | |
| 240 ``` | |
| 241 ; /etc/d2obase | |
| 242 | |
| 243 ACME=/etc/acme/qwaderton.org | |
| 244 WWW=/srv/www/qwaderton.org | |
| 245 | |
| 246 @d2o | |
| 247 |> threads 512 | |
| 248 | |
| 249 @ports | |
| 250 |> tls $ACME.{crt,key} | |
| 251 |> port 80 | |
| 252 |> port+tls 443 | |
| 253 | |
| 254 qwaderton.org @ports | |
| 255 |> root $WWW/root show index.php index.html | |
| 256 | |
| 257 qwaderton.org/webfeather @ports | |
| 258 |> root $WWW/root/webfeather | |
| 259 |> fcgi unix:/run/php-fpm.sock *.php | |
| 260 | |
| 261 <sub>.qwaderton.org @ports | |
| 262 |> root $WWW/$sub | |
| 263 ``` | |
| 264 | |
| 265 --- | |
| 266 | |
| 267 ## Известные ограничения | |
| 268 | |
| 269 - **Один миксин на блок.** Множественное наследование не поддерживается. | |
| 270 - **Brace expansion без вложенности.** `{a,{b,c}}` не работает. | |
| 271 - **FastCGI — один запрос на соединение.** Keep-alive с FPM не реализован. | |
| 272 - **Нет HTTP→HTTPS редиректа** из коробки — нужно реализовывать отдельным блоком на порту 80. | |
| 273 - **Нет hot reload** конфига — требуется перезапуск процесса. |
