# ๐ฆ Install
Pingclair is distributed as a single Linux binary. This page describes
installation, installed files, and service verification for **v0.2.2**.
## ๐งพ What you need
- A Linux host on `x86_64` or `aarch64`; release binaries exist for both.
- `sudo` or root: the installer writes to `/usr/local/bin`, `/etc/Pingclair`,
`/var/lib/pingclair`, and `/etc/systemd/system`.
- `systemd` for the service path. On a host without it, use Docker or run the
server in the foreground; both are covered below.
- Ports 80 and 443 reachable from the internet if you want public certificates
([HTTPS](/start/https/)). On a cloud instance, that usually means opening them
in the provider's firewall as well.
macOS builds from source and is supported for development. macOS is not a
shipping platform.
## ๐ฆ Install from a release binary
```bash
curl -fsSL https://pingclair.com/install.sh | sudo bash
```
The script reads the release channel at `releases.pingclair.com`, prints the tag
it is about to install, and checks the archive against the SHA-256 that channel
publishes for it โ an archive that does not match is refused, not extracted. If
that host cannot be reached it falls back to the GitHub releases API and the
checksum file published beside the archive, so the install does not depend on
one provider. It then creates the service user, grants that user the capability
to bind low ports, writes the default configuration, installs the unit, and
starts the service.
To run an unreleased fix, build `main` on the host instead:
```bash
curl -fsSL https://pingclair.com/install.sh | sudo bash -s -- --main
```
`--main` clones and compiles the server on the host. It needs Rust 1.99 or newer
and the C toolchain BoringSSL and jemalloc require: `cmake`, `clang`,
`libclang-dev`, `g++`, and `git`. The script installs those packages itself on
both `apt` and `dnf` systems. The first build takes several minutes because
BoringSSL is compiled from source.
## ๐๏ธ Installed files
| Path | What it holds |
| --- | --- |
| `/usr/local/bin/pingclair` | The server binary. |
| `/usr/local/bin/pc` | A symlink to the same binary, for the short form. |
| `/etc/Pingclair/Pingclairfile` | The configuration the service runs. |
| `/etc/Pingclair/Pingclairfile.example` | A commented example, never overwritten by an upgrade. |
| `/var/lib/pingclair/.local/share/pingclair` | The certificate store: the service user's data directory, which is where the binary looks by default. |
| `/var/lib/pingclair/html` | The placeholder site served on port 80. |
| `/var/log/pingclair` | Where a `log` sink writes once you configure one. |
| `/etc/systemd/system/pingclair.service` | The unit, enabled and running. |
After installation, the service uses this default configuration to serve the
welcome page:
```caddyfile
# ๐ฆ Pingclair default configuration file
# Management commands: pc service
:80 {
# Welcome page
file_server /var/lib/pingclair/html
}
```
The service user and the certificate store are created only if they are missing,
and an existing `/etc/Pingclair/Pingclairfile` is never replaced. Re-running the installer upgrades the service while preserving these files
([Upgrading and removing](/start/upgrade/)).
## โ
Verify the installation
Check the installed version:
```bash
pingclair version
```
For the 0.2.2 release, the version is `v0.2.2`. `pc version` reports the same
version. Check the service status next:
```bash
pc service status
```
```text
โ pingclair.service - Pingclair High-Performance Web Server
Loaded: loaded (/etc/systemd/system/pingclair.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-09-22 03:21:55 UTC; 42s ago
Docs: https://pingclair.com/start/service/
Main PID: 27630 (pingclair)
Status: "Serving"
Tasks: 12 (limit: 627)
Memory: 8.2M (peak: 8.5M)
```
The server reports `Status: "Serving"` through the unit's `notify` mechanism
only after every listener is bound.
Send an HTTP request to the server:
```bash
curl -i http://localhost/
```
A `200` with `ETag` and `Last-Modified` means the file server answered, and the
body is the placeholder page in `/var/lib/pingclair/html`.
## ๐ณ Docker
The published image runs config-file mode: its entrypoint is `pingclair` and its
default command is `run /etc/pingclair/Pingclairfile`. The image declares
`/etc/pingclair` and `/var/lib/pingclair` as volumes, and exposes ports 80 and 443.
```yaml
services:
pingclair:
image: ghcr.io/dorianverlaine/pingclair:v0.2.2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
volumes:
- ./conf:/etc/pingclair:ro
- ./site:/srv:ro
- pingclair_tls:/var/lib/pingclair
volumes:
pingclair_tls:
```
```bash
mkdir -p conf site
printf ':80 {\n file_server /srv\n}\n' > conf/Pingclairfile
echo 'hello from the container
' > site/index.html
docker compose up -d
curl -i http://localhost/
```
Three points require attention:
- **Do not add `command:`.** The image default is already
`run /etc/pingclair/Pingclairfile`, and overriding it replaces that command.
- **Mount all of `/var/lib/pingclair`, not only the certificate directory.**
The store keeps state beside the certificates, and a container recreated
with only part of it mounted loses that state.
- **Pin a released tag.** `latest` follows the newest release; production should
name the version, as the example does. Published tags are listed on the
[package page](https://github.com/dorianverlaine/pingclair/pkgs/container/pingclair).
On a host where your user is not in the `docker` group, prefix the commands with
`sudo`, or join the group once with `sudo usermod -aG docker "$USER"` and start a
new login session. On Ubuntu, the `docker compose` plugin comes from the
`docker-compose-v2` package.
## ๐ ๏ธ Build from source
```bash
git clone https://github.com/dorianverlaine/pingclair
cd pingclair
cargo build --release
```
Requirements: Rust 1.99.0 (the version CI pins), `cmake`, `clang`,
`libclang-dev`, `g++`, and `git`. BoringSSL is compiled from source as part of
the build, so the first build takes several minutes.
## โ ๏ธ When the install fails
- **`This script must be run as root`.** The script writes outside your home
directory and installs a unit. Re-run it with `sudo`.
- **`setcap: command not found` on Fedora.** That is the `libcap` package. The
installer adds it, but a hand-built host may lack it, and without the
capability the service cannot bind ports 80 and 443.
- **`Job for pingclair.service failed` right after the install.** Read
`journalctl -u pingclair -n 20`. Common causes are a configuration that does
not validate, or something already listening on port 80.
- **The service is running but nothing answers from outside.** Check the provider's firewall or security
group first, then the host's own rules.
- **The host has no `systemd`.** The binary is installed and usable, but the
installer's service step cannot run. Use Docker, or `pingclair run`.
## ๐งน Removing Pingclair
[Upgrading and removing](/start/upgrade/) describes removal commands and the
directories retained for reinstall or rollback.
## ๐งญ Next steps
- [Quickstart](/start/quickstart/): replace the placeholder with your own
configuration and serve a real site.
- [HTTPS](/start/https/): certificates for a public name.
- [Run it as a service](/start/service/): what the unit does and how to reload
it safely.