Mercurial Hosting > d2o
comparison man/d2obase.5.md @ 6:54ab94198677
abstract mixins + building sctipt + documentation
| author | Atarwn Gard <a@qwa.su> |
|---|---|
| date | Tue, 10 Mar 2026 10:22:02 +0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 5:07b6f06899e0 | 6:54ab94198677 |
|---|---|
| 1 % D2OBASE(5) | |
| 2 % March 2026 | |
| 3 | |
| 4 # NAME | |
| 5 d2obase - syntax and configuration guide for the d2o web server | |
| 6 | |
| 7 # DESCRIPTION | |
| 8 The **ICF** (Inheritance Config Format) uses a stream-oriented approach to web serving. It focuses on reducing "boilerplate" by using variables, reusable mixins, and execution pipelines. | |
| 9 | |
| 10 # SYNTAX | |
| 11 A configuration file consists of variable assignments, mixin definitions, and site blocks containing pipelines. | |
| 12 | |
| 13 ## Variables | |
| 14 Variables are defined as `KEY=VALUE`. They are global and can be referenced later using the `$` prefix (e.g., `$DOM`). | |
| 15 | |
| 16 Variable names may only contain characters `[A-Za-z0-9_]`. Values are substituted at the point of declaration, so a variable can reference only those variables defined above it in the file. | |
| 17 | |
| 18 ## Mixins (Templates) | |
| 19 A mixin is defined with the `@` prefix. It stores a set of pipeline directives that can be "splatted" into a site block to avoid repetition. | |
| 20 | |
| 21 @name | |
| 22 |> directive argument | |
| 23 | |
| 24 Mixins can inherit from other mixins: | |
| 25 | |
| 26 @child @parent | |
| 27 |> directive argument | |
| 28 | |
| 29 The parent's directives are inserted before the child's, so the child can override them. Circular references are silently ignored. | |
| 30 | |
| 31 ## Pipelines and Directives | |
| 32 The core of the configuration is the pipeline. Each line starting with `|>` is a directive executed in top-down order. | |
| 33 | |
| 34 Directives follow the format: `|> directive [arguments...]`. | |
| 35 | |
| 36 ### Argument Expansion | |
| 37 Directives support curly brace expansion `{}`. For example: | |
| 38 `file.{crt,key}` expands to two separate arguments: `file.crt` and `file.key`. | |
| 39 | |
| 40 Only one pair of braces per argument is expanded. Nested braces are not supported. | |
| 41 | |
| 42 ## Site Blocks | |
| 43 A site block starts with a domain name (or a variable containing one), followed by optional mixins, and a pipeline. | |
| 44 | |
| 45 example.org @setup | |
| 46 |> directive argument | |
| 47 | |
| 48 ### Pattern Matching | |
| 49 The domain part of a site block is matched exactly. The path part (if present, separated by `/`) is matched by prefix. | |
| 50 | |
| 51 Named capture groups can be used in patterns with `<name>` syntax. The captured value is available as `$name` in the block's directives. | |
| 52 | |
| 53 <sub>.example.org | |
| 54 |> root /srv/www/$sub | |
| 55 | |
| 56 #### Block Specificity | |
| 57 | |
| 58 When multiple blocks match a request, the most specific one wins. Specificity is the number of literal characters matched in the pattern - capture groups `<n>` do not contribute to the score. Host and path are scored separately; host score is weighted heavier (`score = host_score × 1000 + path_score`). | |
| 59 | |
| 60 For example, given these two blocks: | |
| 61 | |
| 62 app.example.org | |
| 63 |> rprx http://127.0.0.1:8080 | |
| 64 | |
| 65 <sub>.example.org | |
| 66 |> root /srv/www/$sub | |
| 67 | |
| 68 A request for `app.example.org` matches both, but `app.example.org` wins - it matched 15 literal characters against 11 for `<sub>.example.org` (`.example.org` only). Order of declaration in the file does not matter. | |
| 69 | |
| 70 ## Comments | |
| 71 Lines beginning with `;` are ignored. Inline comments start with ` ;` (space before semicolon). | |
| 72 | |
| 73 ; full line comment | |
| 74 KEY=value ; inline comment | |
| 75 | |
| 76 # DIRECTIVES | |
| 77 | |
| 78 ## Listening | |
| 79 | |
| 80 **port** *number* | |
| 81 : Listen for plain HTTP on the given port. | |
| 82 | |
| 83 **port+tls** *number* [*cert* *key*] | |
| 84 : Listen for HTTPS on the given port. Certificate and key paths are optional if a **tls** directive is present in the same block. | |
| 85 | |
| 86 **tls** *cert* *key* | |
| 87 : Set the default certificate and key for **port+tls** directives in this block that do not specify their own paths. | |
| 88 | |
| 89 ## Serving | |
| 90 | |
| 91 **root** *path* [**show**] | |
| 92 : Serve static files from *path*. Without **show**, directory listing is forbidden (403). With **show**, an HTML directory listing is returned. | |
| 93 | |
| 94 **ndex** *file...* | |
| 95 : List of index filenames to try when a directory is requested, checked left to right. If a matching file passes the **fcgi** pattern, it is handled by FastCGI instead of served directly. | |
| 96 | |
| 97 **fcgi** *address* [*pattern*] | |
| 98 : Forward matching requests to a FastCGI server. *address* is either `unix:///path/to/socket` or `host:port`. *pattern* is a glob matched against the request path (default `*`). When used together with **root**, only requests matching the pattern are forwarded; everything else is served as static. | |
| 99 | |
| 100 **rprx** *address* | |
| 101 : Reverse-proxy all requests to *address*. The `http://` scheme is assumed if not specified. | |
| 102 | |
| 103 **rdir** *code* *url* | |
| 104 : Redirect to *url* with the given HTTP status code. If *code* is omitted or zero, 302 is used. | |
| 105 | |
| 106 ## Global (in `@d2o` block only) | |
| 107 | |
| 108 **threads** *n* | |
| 109 : Set `GOMAXPROCS` to *n*. | |
| 110 | |
| 111 # EXAMPLES | |
| 112 Below is a complex setup using global variables, a shared mixin for PHP sites, and subdomain handling: | |
| 113 | |
| 114 DOM=qwaderton.org | |
| 115 ACME=/etc/acme | |
| 116 WWW=/srv/www/$DOM | |
| 117 | |
| 118 @ports | |
| 119 |> port 80 | |
| 120 |> port+tls 443 $ACME/$DOM.{crt,key} | |
| 121 |> ndex index.php index.html | |
| 122 | |
| 123 @ports+fcgi @ports | |
| 124 |> fcgi unix:///run/php-fpm.sock *.php | |
| 125 | |
| 126 $DOM @ports+fcgi | |
| 127 |> root $WWW show | |
| 128 | |
| 129 <sub>.$DOM @ports+fcgi | |
| 130 |> root $WWW/$sub | |
| 131 | |
| 132 app.$DOM @ports | |
| 133 |> rprx http://127.0.0.1:8080 | |
| 134 | |
| 135 qwa.su | |
| 136 |> port 80 | |
| 137 |> port+tls 443 $ACME/qwa.su.{crt,key} | |
| 138 |> rdir 307 https://qwaderton.org/ | |
| 139 | |
| 140 We use this configuration on our web server (as it is at the time of writing this manual). | |
| 141 | |
| 142 If you need something simplier to start quickly, use this config: | |
| 143 | |
| 144 DOM=mydomain | |
| 145 TLS=/etc/acme/$DOM | |
| 146 WWW=/srv/www/$DOM | |
| 147 | |
| 148 $DOM | |
| 149 |> port 80 | |
| 150 |> port+tls 443 $TLS.{crt,key} | |
| 151 |> root $WWW show | |
| 152 | |
| 153 # CAVEATS | |
| 154 1. ICF does not support strings with spaces - there are **no quotes or escapes**. Every character except space is treated as part of a token, including `!`, `*`, `/`, and so on. Glob patterns passed to **fcgi** are forwarded as-is to the server. | |
| 155 | |
| 156 2. Variables are evaluated top-down at the point of declaration. Forward references do not work: if `B=$A` appears before `A=value`, `B` will contain the literal `$A`. | |
| 157 | |
| 158 3. Only one pair of curly braces is expanded per argument. `file.{a,b}.{x,y}` does not produce four arguments - only the first `{}` pair is expanded. | |
| 159 | |
| 160 4. A directive outside of any block (a `|>` line before the first block header) is a parse error and will prevent the server from starting. | |
| 161 | |
| 162 5. Duplicate ports across blocks are silently deduplicated - the first declaration wins. TLS certificate paths from a later block with the same port are ignored. | |
| 163 | |
| 164 # SEE ALSO | |
| 165 **d2o**(1) |
