Directives
Each entry states the syntax, the default when the directive is absent, and
where the directive may appear. Version attestation, the Since: line that
would state when a directive was introduced, is not published yet.
📖 This page documents a starting subset. Directives that are accepted but not
yet documented here are still validated by pingclair validate; a directive the
server does not implement is refused by name rather than accepted silently.
encode
Section titled “encode”Syntax: encode <format> [<format> ...]Default: no compressionContext: site blockCompresses responses. Arguments are listed in preference order, so the first
format the client accepts is used. Supported formats are zstd and gzip.
Asking for Brotli is a compile error rather than a silent downgrade to gzip: the proxy has no streaming Brotli encoder, so the option cannot be honored.
example.com { encode zstd gzip file_server ./public}file_server
Section titled “file_server”Syntax: file_server [<root>]Default: disabledContext: site blockServes files from disk, with MIME type detection, range requests, and ETag and
Last-Modified validation. The optional argument sets the root for this
directive alone. When it is omitted, the site root set by root is used.
localhost:8080 { file_server ./public}header
Section titled “header”Syntax: header [<matcher>] <field> <value> header [<matcher>] { <field> <value> # set +<field> <value> # append -<field> # remove set <field> <value> # set, spelled explicitly }Default: noneContext: site blockAdds, replaces, or removes response headers. A bare field name sets the header;
prefixing the field with + appends and with - removes.
example.com { header { X-Frame-Options "DENY" X-Content-Type-Options "nosniff" Strict-Transport-Security "max-age=31536000; includeSubDomains" -X-Powered-By }}Syntax: log [<name>] { <options> }Default: no access sinkContext: site block, global optionsConfigures an access log sink. A bare log enables the default sink for the
site; log <name> { ... } configures a named logger, and log <name> without a
block refers to a channel declared in the global options.
Block options include the destination and format (output, format), the
hostnames selector, include and exclude filters, sampling, and file
rotation settings (mode, dir_mode, roll_*).
example.com { log { output file /var/log/pingclair/access.log }}Records are batched before they are written, and a sink that cannot keep up
drops records and counts them in pingclair_access_log_dropped_total. Writing
every request to a system journal also carries the journal receiver’s cost.
reverse_proxy
Section titled “reverse_proxy”Syntax: reverse_proxy [<matcher>] <upstream> [<upstream> ...] reverse_proxy [<matcher>] { ... }Default: noneContext: site blockForwards requests to one or more upstreams. The default load-balancing policy is
round robin. Hostname upstreams are re-resolved on the interval set by
dns_refresh, so a backend that restarts on a new address is followed without
an operator action; a failed lookup keeps the previous address in rotation.
:80 :8080 { reverse_proxy { lb_policy least_conn to 10.0.0.1:8080 { weight 3 } to 10.0.0.2:8080 to 10.0.0.3:8080 { backup } health_check { path /health interval 5s timeout 2s status 200 204 consecutive_failure 3 consecutive_success 2 } }}Active health checks run out of band, so a failed backend leaves rotation
before a user request reaches it, and rejoins after the configured number of
successful probes. A backup upstream is used only when every primary upstream
is unavailable.
Syntax: root [<matcher>] <path>Default: noneContext: site blockSets the site root. file_server can take a root of its own, but setting it
here is what lets the file server and other file-handling directives agree on a
single location.
example.com { root * /srv/public file_server}Syntax: tls <mode> tls { <options> }Default: automatic HTTPS for public namesContext: site blockControls how certificates are obtained.
| Mode | Behavior |
|---|---|
tls auto |
Obtains public certificates over ACME and renews them. |
tls internal |
Issues from a persistent local certificate authority. The root is published at $PINGCLAIR_TLS_STORE/internal/root.crt and must be trusted by clients. |
tls { cert ...; key ... } |
Uses the certificate and key files named in the block. |
The block form also enables HTTP/3 with http3, and supports DNS-01 issuance
with dns cloudflare <token>, which is the only DNS provider implemented.
Naming another provider is refused at startup rather than accepted and ignored,
because DNS-01 is what makes wildcard certificates possible.
example.com { tls { cert /etc/pingclair/certs/example.com.pem key /etc/pingclair/certs/example.com.key http3 } reverse_proxy localhost:3000}🌍 Global options
Section titled “🌍 Global options”Global options are written in the unnamed block at the top of the file.
| Option | Syntax | Notes |
|---|---|---|
admin |
admin <address> [<token>] |
Admin API listener. Without a token, only loopback connections are accepted. |
auto_https |
auto_https on | off | disable_redirects |
Controls automatic HTTPS and the port 80 redirect. |
dns_refresh |
dns_refresh <duration> |
Re-resolution interval for hostname upstreams. off pins the addresses resolved at startup. |
email |
email <address> |
ACME account email used for issuance. |
trusted_proxies |
trusted_proxies <cidr> [<cidr> ...] |
Which peers may assert client identity headers. Changes require a restart. |
{ email admin@example.com admin 127.0.0.1:2019 dns_refresh 30s}