Skip to main content

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.

CheckOutcome
Direct I/OWrites 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 warmupStats and opens every .wal file under shard_* so a restart does not start on cold inodes. Failure is a warning.
Clock syncAsks the kernel via adjtimex() whether an NTP daemon is disciplining the clock. Unsynchronised is a warning, not a refusal.
Compaction temp dirOnly 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.
PortsRefuses if something already answers on the client port or the replication port on 127.0.0.1. Both are checked, even in standalone.
Immutable configRefuses 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 budgetRefuses if --memory-consumption-percent is outside 1-95. Warns under 512 MB of detected memory or under 100 MB per shard.
TLSWith 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.