Configuration model
Pingclair compiles the Pingclairfile when it loads the configuration. Address parsing and matcher compilation are completed before requests are processed, and unsupported or invalid settings are rejected at load time. This page describes configuration loading and reload behavior in v0.2.2.
🗂️ A file is global options followed by site blocks
Section titled “🗂️ A file is global options followed by site blocks”{ email admin@example.com}
example.com { encode zstd gzip reverse_proxy 10.0.0.10:8080 10.0.0.11:8080}
:8080 { file_server ./public}- Global options go in an unnamed block at the top of the file. They configure what is not specific to one site: the ACME account email, the Admin API, automatic HTTPS, trusted proxies, and DNS refresh for hostname upstreams. The directive reference lists them.
- Site blocks are named by address: a host, a port, or both. The port is part of the address rather than a separate directive, so the address and the listener cannot disagree.
- Directives are the statements inside a site block. Some take arguments, some take a nested block, and some take both.
- Comments start with
#and run to the end of the line. - Values that contain spaces are quoted. Durations carry a unit:
30sis thirty seconds, and a bare30is refused where a duration is expected.
🧭 Matchers select the requests a directive applies to
Section titled “🧭 Matchers select the requests a directive applies to”A named matcher is declared with @name and used by writing that name after
the directive:
example.com { @api path /api/* header @api Cache-Control "no-store"
@assets path /assets/* header @assets Cache-Control "public, max-age=31536000, immutable"}A handle block groups the directives for one route. Only one handle block
answers a request, and a handle with no matcher matches requests not handled by the other blocks:
example.com { handle /assets/* { file_server ./assets }
handle { respond "Page Not Found" 404 }}🚦 Which route answers a request
Section titled “🚦 Which route answers a request”Routes are ranked by directive, and the first matching route answers. redir, handle, and route precede respond; respond precedes reverse_proxy, php_fastcgi, and file_server. Within one directive, single paths sort by length after removing a trailing *, then exact before the corresponding wildcard, then file order. Multiple-path and pathless matchers follow single-path routes.
Use exclusive handle blocks to separate routes, or route to retain written order. Path comparisons ignore ASCII letter case and decode percent escapes once; use path_regexp when case matters. handle, handle_path, and route accept only *, a path beginning with /, or @name before the block, and refuse a bare token such as *.php.
🧩 Snippets and imports reuse configuration
Section titled “🧩 Snippets and imports reuse configuration”A snippet is a reusable fragment declared as (name) { ... } and inserted with
import name. The caller can pass arguments and a block; the snippet receives
the block where it writes {block}:
(site) { https://{args[0]} { {block} }}
import site example.com { reverse_proxy 127.0.0.1:3000}Snippets defined in an imported file are visible to the imports that follow it. A placeholder inside a directive’s argument list is refused: Caddy re-reads the line after inserting the snippet, and Pingclair’s parser cannot. Pingclair therefore rejects the construct instead of inferring its intended meaning.
🛡️ Validation rejects unsupported settings
Section titled “🛡️ Validation rejects unsupported settings”pingclair validate compiles the file and applies the checks that need more
than syntax: directive arguments, matcher syntax, whether certificate and key
files exist, and policy constraints such as which peers may set client-identity
headers.
A configuration that fails these checks does not run. Three rules decide what fails:
- An unimplemented name is refused by name. Pingclair recognizes every name the Caddyfile format defines. A name it does not implement produces a message identifying the unsupported feature, and the configuration is rejected.
- Unsupported options are rejected.
encode bris a compile error, because there is no streaming Brotli encoder; the server does not automatically substitute gzip. - Correct syntax that points at missing files is still an error. The server
repository’s
examples/full_featured.pingclairis valid syntax, andvalidatestill rejects it on a machine where the certificate paths it names do not exist.
The server runs the same checks when it loads a file, including on a reload.
🔁 A reload swaps the configuration without a restart
Section titled “🔁 A reload swaps the configuration without a restart”A reload reads the file again, compiles it, and swaps the result in while the process keeps running. If the new file fails to compile, the previous configuration keeps serving. There are three ways to initiate a reload:
pc service reload(orsystemctl reload pingclair) sendsSIGUSR1through the installed unit.sudo kill -USR1 "$(systemctl show -p MainPID --value pingclair)"sends the same signal directly.pingclair reloadgoes through the Admin API and prints the reload result. It needs theadminglobal option.
systemctl reload can only report that the signal was delivered, so the
reload result appears on the unit’s status line and in the journal.
Some changes cannot be applied by a reload, and the server refuses the reload and keeps the old configuration rather than applying part of it:
- Listener changes. Adding, removing, or moving an address, or switching a listener between plaintext and TLS, requires a restart, because listening sockets are created at startup. On Unix, an admin-only startup may load its first plaintext HTTP generation; TLS and later topology changes require a restart.
- Global options. Options established at startup, such as
trusted_proxies, apply to the whole process, so changing those policies requires a restart. Process-log settings can reload. - Certificate topology. Adding a TLS hostname, or changing how a site gets its certificate, requires a restart.
The refusal names the change, for example listener topology changed (added: …, removed: …), and sudo pc service restart applies it.
Run it as a service describes each reload outcome.
🧭 Related pages
Section titled “🧭 Related pages”- Pingclairfile: the language in full.
- Directive reference: every directive and option.
- Architecture: what runs the compiled configuration.
