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)