Getting started

A single node is one command. A replicated cluster is three more.

Run a single node

Docker

docker pull ghcr.io/nanocached/nanocached-node:latest
docker run --rm --publish 8356:8356 ghcr.io/nanocached/nanocached-node:latest

From source

Requires Rust (the repository pins the toolchain via rust-toolchain.toml, so Rustup sets everything up):

git clone https://github.com/nanocached/nanocached.git
cd nanocached
cargo run --bin nanocached-node -- --host 0.0.0.0 --port 8356

The node listens on 127.0.0.1:8356 by default; override with --host and --port. A release build (cargo build --release) also produces ncd, a thin dispatcher: ncd node start … / ncd discovery start ….

Smoke test

printf 'S 4 5\nnameAliceG 4\nname' | nc 127.0.0.1 8356

Expected response: S, then V 5 / Alice. See the protocol reference for every command.

Build a cluster

A cluster is N cache nodes plus one or more discovery servers. The discovery server is a lightweight membership registry — it is never on the data path; clients fetch the node list from it and talk to nodes directly (how it works).

Start a discovery server:

docker run --rm --publish 8357:8357 ghcr.io/nanocached/nanocached-discovery:latest
# or: cargo run --bin nanocached-discovery -- --port 8357

Start nodes pointing at it:

cargo run --bin nanocached-node -- --port 8356 --discovery 127.0.0.1:8357
cargo run --bin nanocached-node -- --port 8358 --discovery 127.0.0.1:8357

Each node sends a heartbeat every --heartbeat-interval seconds (default 5) declaring --advertise-addr (default --host:--port — set it explicitly when nodes sit behind NAT or in containers). New nodes join with a staged data handoff, so adding a node never drops the keys it takes ownership of.

Replication factor

Discovery owns the cluster's replication factor R (default 2, minimum 1):

cargo run --bin nanocached-discovery -- --port 8357 --replication-factor 2

Every key lives on its top-R nodes as ranked by rendezvous hashing, so any single node death costs no cached data. Effective cluster capacity is total memory ÷ R; --replication-factor 1 restores single-copy behavior. Clients learn R automatically from the node list — no SDK configuration.

Discovery replicas (no single point of failure)

The registry is soft state rebuilt from node announces, so discovery replicas run with zero coordination between them. Give every node — and every SDK client — the same list in the same order:

cargo run --bin nanocached-discovery -- --port 8357
cargo run --bin nanocached-discovery -- --port 8358

cargo run --bin nanocached-node -- --port 8356 \
  --discovery 127.0.0.1:8357,127.0.0.1:8358

Losing any one replica — including the first-listed primary — costs neither cache traffic nor client bootstrap; only joins need the primary up. A restarted replica answers B (busy) for --startup-grace seconds while live members re-announce, so a bootstrapping client never sees a half-recovered node list.

Authentication

Set NANOCACHED_AUTH_SECRET to require clients to authenticate before any other command. It is an environment variable — not a flag — so the secret never shows in ps output. Set it on both roles to protect a cluster:

NANOCACHED_AUTH_SECRET=change-me nanocached-node --port 8356 --discovery 127.0.0.1:8357
NANOCACHED_AUTH_SECRET=change-me nanocached-discovery --port 8357

Nodes reuse the same value to authenticate their own heartbeats. Unset (or empty) disables authentication entirely. Authentication is a second layer of defense, not a substitute for network isolation: without TLS there is no transport encryption, so bind to 127.0.0.1 or a private interface and add TLS when the network is not trusted.

TLS

Pass --tls-cert/--tls-key (PEM) to require TLS on every accepted connection — no plaintext fallback once set:

nanocached-node      --port 8356 --tls-cert cert.pem --tls-key key.pem
nanocached-discovery --port 8357 --tls-cert cert.pem --tls-key key.pem

A node registering with a TLS-secured discovery server also needs --tls-ca (the CA bundle to trust for its heartbeat connection — only those CAs, not the system store, since cluster certificates are typically private):

nanocached-node --port 8356 --tls-cert cert.pem --tls-key key.pem \
  --tls-ca ca.pem --discovery 127.0.0.1:8357

For local development, generate a self-signed certificate that rustls will accept as a leaf (CA:FALSE matters — OpenSSL's default self-signed certs are marked as their own CA and get refused):

openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 1 \
  -subj "/CN=127.0.0.1" \
  -addext "subjectAltName=IP:127.0.0.1" \
  -addext "basicConstraints=critical,CA:FALSE" \
  -addext "keyUsage=critical,digitalSignature,keyEncipherment" \
  -addext "extendedKeyUsage=serverAuth"

Being self-signed, the same cert.pem doubles as the --tls-ca trust anchor for anything connecting to it.

Connect a client

Use any of the six SDKs — each detects whether it reached a node or a discovery server from the handshake itself, so single-node development and clustered production use identical code. See SDKs.

Built-in limits

Limitnanocached-nodenanocached-discovery
Maximum request size1 MiB4 KiB
Maximum concurrent connections1,0241,024
Cache memory bound256 MiB, LRU eviction
Idle connection timeout30 s30 s

The memory bound is approximate (sum of stored key and value bytes); least-recently-used entries are evicted first. Use the capacity planner to size nodes, R, and TTL against a target hit rate.