Running a single node
Standalone mode: one process, no replication, no S3 election. For development and for workloads that accept single-machine durability.
celeriant \
--standalone \
--data-root /var/lib/celeriant \
--num-shards 4
Clients connect on --client-port (default 10000). Prometheus metrics and /health are on --metrics-port (default 9090).
Every server flag also reads a CELERIANT_-prefixed environment variable (--data-root is CELERIANT_DATA_ROOT), and the server loads a .env file from its working directory if one exists. See Configuration.
The data directory
--data-root defaults to data, relative to the working directory. Set it. It holds the node's private_key (its node id derives from it), server_meta.toml, the WAL compression dictionary, an optional api_keys.toml, and one shard_* directory per shard.
It must sit on a filesystem that honours O_DIRECT: XFS or ext4, not tmpfs or overlayfs.
What the server checks at boot
The server runs these before it opens a port. A refusal logs the reason and exits with status 1.
| Check | Outcome |
|---|---|
| Direct I/O | Writes a probe file with an unaligned O_DIRECT write. It needs EINVAL; if the write succeeds, the filesystem is silently buffering: refuse. The probe tests behaviour, not the filesystem type. It then needs a 512-byte aligned write to succeed; a filesystem that demands larger alignment is also refused. |
| Filesystem metadata warmup | Stats and opens every .wal file under shard_* so a restart does not start on cold inodes. Failure is a warning. |
| Clock sync | Asks the kernel via adjtimex() whether an NTP daemon is disciplining the clock. Unsynchronised is a warning, not a refusal. |
| Compaction temp dir | Only when --compaction-temp-dir is set. Refuses if it is on a different filesystem from --data-root, because compaction swaps segments with an atomic rename. |
| Ports | Refuses if something already answers on the client port or the replication port on 127.0.0.1. Both are checked, even in standalone. |
| Immutable config | Refuses if shard count, routing rule, timestamp precision, epoch offset, coordinator-shard reservation or WAL compression settings differ from what server_meta.toml recorded on first boot. |
| Memory budget | Refuses if --memory-consumption-percent is outside 1-95. Warns under 512 MB of detected memory or under 100 MB per shard. |
| TLS | With TLS on, refuses if cert paths are missing or the kernel TLS module is not loaded. See TLS and mTLS. |
Shards
--num-shards defaults to the CPU count, one core per shard. It is fixed at first boot. Change it later and the server refuses to start, so choose it explicitly: a handful for development, the core count for production.
Durability
A write is fdatasync'd to local disk before it is acknowledged. An acknowledged write survives a process crash or power loss on hardware that honours flush. It does not survive the disk failing, because there is no second copy. To survive losing a node, run a two-node cluster.
Containers
The image is published at ghcr.io/celeriant/celeriant for amd64 and arm64, tagged by release (0.2.0) and latest. Pin a release tag in production. There are no prebuilt binaries; outside a container, build with cargo build --release -p celeriant.
The container needs seccomp=unconfined and unlimited memlock for io_uring. The image's working directory is /, so pass --data-root and mount a volume there, or the data lands in the container's overlayfs layer, which does not honour O_DIRECT.
docker run -d --name celeriant \
--security-opt seccomp=unconfined --ulimit memlock=-1:-1 \
-p 10000:10000 -p 9090:9090 \
-v celeriant-data:/var/lib/celeriant \
ghcr.io/celeriant/celeriant \
--standalone --data-root /var/lib/celeriant --num-shards 4
To build the image yourself: docker build -t celeriant . from the source root.