Upgrading and removing
Version 0.2.0 changes how existing configurations route, bind, compress, and identify clients. These changes also apply when upgrading from 0.2.0-rc.N. The patch releases 0.2.1 and 0.2.2 change no configuration. Read the complete Before you upgrade list and its linked entries before replacing a binary. The summary below covers the changes most likely to affect a deployment.
⚠️ What changes in 0.2.0
Section titled “⚠️ What changes in 0.2.0”| Review | What to change or expect |
|---|---|
| Routing | Directive order decides the first matching route. A catch-all redir, route, or handle can precede a specific respond. Use exclusive handle blocks or explicit route order. |
| Paths | ASCII case is ignored and escapes are decoded once. handle_path and URI stripping also ignore case. Braces are literal; use path_regexp for captures and case-sensitive routing. Equal-length sibling paths retain file order. |
| Block matchers | handle, handle_path, and route accept only *, /path, or @name. Replace handle *.php with a named path *.php matcher. |
| Listeners | bind applies even with explicit addresses and ports, including the automatic redirect. listen retains its IP address. bind and default_bind allow one address. Sites on one port share a listener; a bind-restricted site beside a wildcard listener is refused. |
| Addresses | A named site with a port and no scheme uses HTTPS. Write http:// for plaintext. Scheme-only addresses use global ports. [::1] names a site, and 0.0.0.0 with [::] on one port folds to IPv6. |
| Client identity | In servers, write trusted_proxies static … once per scope. List CF-Connecting-IP in client_ip_headers when needed. Use client_ip and {client_ip} for the forwarded client; remote_ip and {remote_host} mean the peer. {remote_ip} is refused. |
| Request limits | There is no default body-size ceiling. Set request_body { max_size … } if needed. Header completion and pauses between body reads default to 60 seconds; uploads with long pauses may need a longer limits { body_timeout … }. |
| Error pages | handle_errors now handles gateway, timeout, and 413 errors too. Its root and file_server serve the page with the error status. Restrict a catch-all block by status if appropriate. |
| Encoding | No compression without encode. Blocks, gzip levels (default 5), response matchers, and minimum length take effect. encode off cannot have a block. Static responses always vary by encoding; proxy responses do so on encode sites. Re-encoding weakens proxy ETags; static and sidecar validators change. no-transform disables encoding. |
| Response cache | Freshness includes upstream age. All caching routes must agree on max_size; reload applies budget changes. flush_interval -1 bypasses admission. Every Vary line participates in variants; invalid Vary and Vary: * prevent storage. |
| Admin API | Missing config reads return 200 null. Reads mask secrets, so restore them before loading an export. Config writes honor path-qualified If-Match; after 412, read the path and its ETag again. Reads remain available through reload. |
| Metrics | Add global metrics to collect. Scrapes are empty without it. Update dashboards to the renamed caddy_* families. |
| CLI | Use --config/-c and --adapter caddyfile|json; do not also supply a positional path. With no default file, run starts admin-only. Give an explicit path if absence must fail. validate now parses TLS files and checks key pairs. |
| TLS | The internal CA moves to pki/authorities/local/ without migration: trust the new root again. Exact names no longer inherit wildcard client_auth; add an explicit block if required. Manual TLS requires a named site. |
| Upstreams | Weight 0 drains, weights above 100 and all-zero primary pools fail validation. lb_try_duration bounds new attempts, not an active response. Retries after delivery are limited to idempotent methods. |
| Protocols | CONNECT receives 405 and closes H1; a target without a usable port receives 400. Malformed HTTP/1 targets and chunked bodies receive 400 and close. FastCGI HEAD has no body, oversized parameters receive 431, and malformed bodies abort the response. |
| Lifecycle | Occupied HTTP, admin, and H3 UDP ports prevent startup. SIGTERM drains within grace_period. Restart still has a connection gap; reload is preferable for policy changes. |
The known release defects still apply.
A 502 or 504 generated by the built-in proxy error path carries
Proxy-Status; a custom handle_errors response does not. A missed keepalive
reuse is logged at DEBUG rather than ERROR.
📦 Preserve the previous installation
Section titled “📦 Preserve the previous installation”Back up the configuration, the current binary, and the entire TLS store before
upgrading. Preserve their ownership and protect backups containing private
keys. The installer keeps /etc/Pingclair/Pingclairfile, the certificate store
at /var/lib/pingclair/.local/share/pingclair, and the site’s files. It replaces
the binary, example configuration, and systemd unit, then restarts the service.
A configured storage file_system path takes precedence over the usual store.
Keep the old store backup for rollback: trusting the new internal root does not make old clients trust it, and rolling back only the binary does not restore the old root or configuration format.
🛡️ Check before switching
Section titled “🛡️ Check before switching”Run the new binary’s validate against the production configuration while
it is still staged, before replacing the running binary. It opens no listeners,
but its user must be able to read every certificate and key the file names.
Then test the affected routes, case variants, forwarded client identity, error
pages, uploads, compression, and metrics in a staging deployment.
A source build of main reports v0.0.0-dev+<sha> (or v0.0.0-dev without a
checkout); a release binary reports its tag, such as v0.2.2. Check the tag and
published checksum when installing. A dev version string is not evidence that
the stable release is installed.
⬆️ Install the stable release
Section titled “⬆️ Install the stable release”The installer selects the stable channel:
curl -fsSL https://pingclair.com/install.sh | sudo bashpingclair versionpc service statusConfirm that pingclair version reports v0.2.2, the service is running, and
your routes respond as expected.
The installer has no version-pinning flag. For containers, pin the intended tag:
services: pingclair: image: ghcr.io/dorianverlaine/pingclair:v0.2.2docker compose pulldocker compose up -ddocker compose logs pingclairKeep the configuration and TLS store volumes. latest follows stable releases;
alpha previews do not advance it. Host ports must be free before startup.
⏪ Roll back
Section titled “⏪ Roll back”Stop the new service, restore the backed-up binary, configuration, and TLS store with their original ownership, then validate with the restored binary before starting. A configuration written by 0.2.0 may not load in an earlier version. Do not overwrite a running certificate store with a partial backup.
🧹 Remove the installation
Section titled “🧹 Remove the installation”sudo pc service stopsudo systemctl disable pingclairsudo rm /etc/systemd/system/pingclair.servicesudo systemctl daemon-reloadsudo rm /usr/local/bin/pingclair /usr/local/bin/pcThese commands preserve /etc/Pingclair, /var/lib/pingclair, and
/var/log/pingclair, including certificates and site files. Delete retained
data only when it is no longer needed for reinstall or rollback.
🧭 Next steps
Section titled “🧭 Next steps”- Install: installation layout and prerequisites.
- Run it as a service: reload, restart, and logs.
- Project status: remaining release limitations.
