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