Skip to content
dorianverlainePublic

About

⚑ High-performance Rust web server and reverse proxy built on Cloudflare Pingora. 🧾 Caddyfile-compatible config Β· πŸ” automatic HTTPS Β· πŸš€ HTTP/1.1, HTTP/2, HTTP/3 Β· βš–οΈ load balancing Β· πŸ“ static files.

Topics

Resources

Contributing

Stars

108 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

1,153 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Pingclair

A Rust web server and reverse proxy built on Cloudflare Pingora.

Documentation Release License


πŸ“– Overview

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.

✨ Highlights

  • HTTP/1.1, HTTP/2, and HTTP/3 β€” Serve all three protocols from one configuration, with QUIC provided by Cloudflare quiche.
  • Automatic HTTPS β€” Obtain public certificates through ACME, operate a persistent internal certificate authority, or load certificates from files.
  • Reverse proxying β€” Route to multiple upstreams with load-balancing policies, active health checks, retries, circuit breakers, and bounded overload queues. HTTP/3 cancellation releases upstream requests even while the origin is idle.
  • Static files and FastCGI β€” Serve files with conditional and range requests, apply gzip or Zstandard compression, and run PHP through FastCGI. Canonical file and directory redirects preserve queries and stay on the same origin.
  • Fail-closed configuration β€” Validate policy before publication and keep the last-known-good configuration when a reload cannot be applied safely.
  • Operational visibility β€” Export Prometheus metrics and structured access logs without requiring an external module. Standard HTTP and Admin metric families use Caddy's caddy_* names; additional runtime metrics retain pingclair_* names. See the metric name mapping.

πŸ“¦ Install

Linux release package

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.

Build from source

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.

πŸš€ Quick start

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.

Command-line modes

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.

πŸ“š Documentation

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.

πŸ“Œ Release status

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:

  • Pingclair implements a practical subset of Caddyfile syntax; it is not a drop-in replacement for every Caddy configuration.
  • Unsupported directives and options fail configuration loading explicitly. The complete current lists are maintained on the project status page.
  • Certificate and runtime state use a local file-backed store. Multiple instances do not share one distributed certificate store.
  • Pingclair is an HTTP server and reverse proxy. It does not provide generic CONNECT tunnels or advertise extended CONNECT support.
  • HTTP/2 server push (push) is a deliberate non-goal: major browsers have removed support for it, so the directive is refused rather than accepted and ignored.
  • Request trailers are not forwarded to an upstream. Applications that depend on request trailers should not be placed behind this release.

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.

🀝 Contributing

Read CONTRIBUTING.md before opening a pull request. It describes the development workflow, test requirements, commit conventions, and architectural constraints.

Useful project resources:

  • Issue tracker for confirmed defects and feature requests.
  • Discussions for design questions and general project conversation.
  • Changelog for released and unreleased behavior changes.
  • CLA for the one-time contributor agreement.

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.

πŸ“„ License

Pingclair is licensed under the Apache License 2.0. See NOTICE for attribution requirements and third-party notices.

About

⚑ High-performance Rust web server and reverse proxy built on Cloudflare Pingora. 🧾 Caddyfile-compatible config Β· πŸ” automatic HTTPS Β· πŸš€ HTTP/1.1, HTTP/2, HTTP/3 Β· βš–οΈ load balancing Β· πŸ“ static files.

Topics

Resources

Contributing

Stars

108 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages