AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
A reverse proxy and static file server written in Rust, with HTTP/1.1, HTTP/2, HTTP/3, automatic HTTPS, and a Caddyfile-compatible configuration language.
Developer toolsRust · ShellGitHub @dorianverlaineOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
A modern, high-performance web server and reverse proxy built on Pingora Cloudflare Pingora's raw performance, wrapped in Caddy's minimalist developer experience
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
A Rust web server and reverse proxy built on Cloudflare Pingora.
Pingclair serves static content and proxies HTTP applications through one
configuration model. It supports HTTP/1.1 and HTTP/2 over TCP, HTTP/3 over
QUIC, automatic HTTPS, health-aware load balancing, and configuration reloads.
The primary configuration format is the Pingclairfile, a deliberately bounded
implementation of commonly used Caddyfile syntax. Unsupported Caddy features
are rejected during configuration loading rather than accepted as no-ops.Read the full README ↗A Rust web server and reverse proxy built on Cloudflare Pingora.
Pingclair serves static content and proxies HTTP applications through one configuration model. It supports HTTP/1.1 and HTTP/2 over TCP, HTTP/3 over QUIC, automatic HTTPS, health-aware load balancing, and configuration reloads.
The configuration format is the Pingclairfile (Pingclairfile, *.pingclair),
a deliberately bounded implementation of commonly used Caddyfile syntax.
Where the Caddyfile defines a behaviour, Pingclair follows it, and unsupported
Caddy features are rejected during configuration loading rather than accepted
as no-ops. A capability Caddy has no word for is spelled where Caddy keeps that
kind of option, under nginx's name when nginx has the concept — deny,
send_timeout, keepalive_requests, negotiate markdown
(examples/extensions.pingclair).
The latest release is v0.2.3, the newest patch on the 0.2 line. Review the
project status before using it for a
production deployment. Pingclair is pre-1.0: a minor version is where breaking
changes live, and a patch release promises nothing breaks.
🔌 The 0.3 development line on main supports TCP forwarding with TLS
ClientHello SNI/ALPN and source-IP routing. TLS passes through unchanged; it is
not terminated.
Opt-in connection access logs and l4_* metrics report traffic and session outcomes.
L4 admission defaults to 1024 sessions per listener (max_connections) and
a fixed process ceiling of 4096 sessions, including preread and upstream dialing.
Static hostname pools rotate new connections across resolved addresses, with
bounded fallback only before TCP establishment.
Explicit dynamic A/AAAA sources refresh in the background and enforce TTL,
stale deadlines and destination policy. DNS failure leaves unrelated local routes
available, and established tunnels keep their connected streams.
TCP routing is written in a layer4 block among the global options
(examples/layer4.pingclair), with nginx's
stream-module names for its timeouts and buffers.
See the L4 boundaries for syntax and current limits.
caddy_* names; additional runtime metrics retain
pingclair_* names. See the metric name mapping.The installer downloads the latest published release, verifies its SHA-256
checksum, creates an unprivileged service account, and installs the pingclair
and pc commands:
curl -fsSL https://pingclair.com/install.sh | sudo bash
The current release is v0.2.3, a patch on the 0.2 line. The v0.1.x line is
unmaintained and should not be used for a new deployment.
After installation, inspect the service before loading a configuration:
pc service status
pingclair version
The installer starts a systemd service with its configuration at
/etc/Pingclair/Pingclairfile. After replacing the placeholder configuration,
validate and reload it with:
sudo pingclair validate /etc/Pingclair/Pingclairfile
sudo pc service reload
🔁 Reload, not restart, is the zero-downtime way to apply a configuration:
the running process swaps it in while every connection keeps being served.
A restart (systemctl restart pingclair) has a brief gap instead. The old
process stops accepting the moment it receives SIGTERM, lets running
requests finish for at most grace_period (default 30 s), and exits; only
then can systemd start the new one, and new connections are refused in
between. With only short requests running, that gap measured 40 to 210 ms on
Linux; a long download or event stream holds it open until it finishes or
grace_period runs out. HTTP/3 clients that connect during the gap wait for
the new process instead of being refused. Restart for what a reload cannot
do, such as moving a listener to another address or upgrading the binary.
🪵 A reload can add a named access-log channel and attach sites to it in the same configuration. Logging begins with the new routes; no restart is needed.
🔐 On a listener with client authentication, an unchanged compiled policy keeps
existing connections usable across reloads. Changing the mode, loaded CA
certificates, pinned leaves, or site authentication mapping makes old connections
answer 421 until the client reconnects. Replacing a certificate file at the same
path counts as a change. Policies that verify against system trust still require
reconnection on every reload because their lazily loaded roots cannot be compared
completely at configuration time.
🧩 Ownership of the running configuration moves with the first configuration
change made through the Admin API's /load: while the process is still
serving the file it started with, SIGUSR1 reloads that file; after an API
load the file may no longer describe what is running, so SIGUSR1 reloads
are ignored until the process restarts. Keep changing the configuration
through the Admin API, or restart to hand ownership back to the file.
See the installation guide for Docker, service management, verification, removal, and troubleshooting.
Building the current branch requires the repository's pinned Rust toolchain:
git clone https://github.com/dorianverlaine/pingclair.git
cd pingclair
cargo +1.99.0 install --locked --path pingclair
The source build needs a C/C++ toolchain, CMake, Clang, and the development headers used by BoringSSL and bindgen. The installation guide lists the packages for supported Linux distributions and documents the container image when a host build is not appropriate.
Source builds describe the checked-out commit, which may contain changes not present in the latest release. Consult the changelog before upgrading a running deployment from a source build.
Create a file named Pingclairfile:
http://localhost:8080 {
respond "Hello from Pingclair"
}
Validate it before starting the server. Validation reads and matches explicit TLS certificate/key pairs without opening listeners:
pingclair validate Pingclairfile
Run Pingclair in the foreground:
pingclair run Pingclairfile
Without a path, run looks for Pingclairfile, then Caddyfile, in the working
directory. If neither exists, it starts with no HTTP sites and only the admin API
at 127.0.0.1:2019, matching caddy run. --resume loads an available admin
autosave before using the file or empty configuration. Explicit missing paths
still fail, and validate still requires a configuration file or stdin.
On Unix, an empty process accepts its first plaintext HTTP listener generation
through /load; later loads can update routes on those addresses. First TLS
listeners and subsequent listener topology changes require a restart.
Both run and validate accept a positional path or --config / -c.
Use --adapter caddyfile or --adapter json to override the filename extension;
JSON must use Pingclair's schema. Other adapter names are rejected.
Verify the response from another terminal:
curl --noproxy '*' http://localhost:8080/
The response is:
Hello from Pingclair
For a reverse proxy, replace respond with an upstream:
http://localhost:8080 {
reverse_proxy localhost:3000
}
The listener admits 512 downstream connections per worker thread when no
ceiling is written, matching nginx's worker_connections default. Set the
whole listener's ceiling when the workload needs more:
http://localhost:8080 {
limits {
max_connections 2048
}
reverse_proxy localhost:3000
}
At the ceiling, an excess HTTP/1.1 connection receives 503 Service Unavailable; an HTTP/2 connection that has not completed its handshake is
closed, as it is in nginx. A configured max_connections is not multiplied by
the worker-thread count.
For a public hostname, Pingclair can obtain and renew the certificate and serve HTTP/1.1, HTTP/2, and HTTP/3:
example.com {
tls auto
reverse_proxy localhost:3000
}
Public automatic HTTPS requires the hostname to resolve to the server and the required TCP and UDP ports to be reachable. Follow the HTTPS guide before enabling it on a live host.
For temporary local use, Pingclair also provides direct commands that do not require a Pingclairfile:
pingclair file-server --listen :8080 --root .
pingclair reverse-proxy --from :8080 --to localhost:3000
Configuration-file mode is recommended for services because it is reviewable, validatable, and reloadable. A configuration can be inspected without starting the server:
pingclair adapt --config Pingclairfile --pretty
The quickstart covers validation, adaptation, startup, verification, and migration into the system service.
The documentation site is the authoritative source for installation, configuration, deployment behavior, compatibility boundaries, and performance methodology.
| Topic | Description |
|---|---|
| Install | Release packages, Docker, source builds, verification, and removal. |
| Quickstart | Write, validate, inspect, run, and verify a Pingclairfile. |
| HTTPS | Public ACME, DNS-01, internal certificates, and certificate files. |
| Pingclairfile | Addresses, matchers, route ordering, snippets, and imports. |
| Directives | Supported directives, syntax, defaults, and failure behavior. |
| Command line | Commands, flags, service control, and configuration tools. |
| Project status | Release support, unsupported names, known limitations, and upcoming changes. |
| Benchmarks | Current results, test conditions, and interpretation limits. |
The repository changelog records upgrade-relevant changes on
main and between releases. It should be read before changing a deployed
version.
Documentation is published in English and Traditional Chinese. The English pages define the terminology when translations differ; both editions describe the same commands and configuration surface.
The latest published version is v0.2.3. main carries the 0.3 development
line, so the source tree contains behavior the published release does not;
release documentation describes the published release, not main.
Important boundaries include:
CONNECT tunnels or advertise extended CONNECT support.push) is a deliberate non-goal: major browsers have
removed support for it, so the directive is refused rather than accepted
and ignored.Known defects, release-specific limitations, and differences between the
latest release and main are tracked on the
project status page and in the
changelog. Performance results are published only with their
measurement conditions on the
benchmarks page.
Read CONTRIBUTING.md before opening a pull request. It describes the development workflow, test requirements, commit conventions, and architectural constraints.
Useful project resources:
Security-sensitive reports should follow the repository's published security policy when one is available. Do not include credentials, private keys, access tokens, or private infrastructure details in a public issue.
Pingclair is licensed under the Apache License 2.0. See NOTICE for attribution requirements and third-party notices.