Currently in testing: the GitHub code will be opened once complete.

Ticketing Server Deployment

Environment
Shell
Mode
bash
Client connection example
rust
Quick test with nc
bash

Environment Variables

Server configuration is done entirely through environment variables. Keys are case-insensitive, an empty value counts as unset, and flag-style values are only true for 1/true/yes/on. The Docker image is scratch-based, so config is injected purely through environment variables with no config file.

Environment variableDefaultDescription
PORT5225Listen port in single mode. Ignored in cluster mode, where the port from CLUSTER_SELF is used instead
SOCKET_BIND0.0.0.0Listen address
CLIENT_TOKENS(none)Comma-separated list of client auth tokens. If unset, an empty token is allowed
CLUSTER_SELF(none)This node's advertised address, host:port. Presence enables cluster mode
CLUSTER_PEERS(none)Comma-separated list of every node's advertised address. Exactly 3 or 5, same order on every node, must include self
CLUSTER_TOKENS(none)Comma-separated list of peer-to-peer auth tokens
TLS_CERT / TLS_KEY(none)Paths to the certificate/private key PEM files — set both together to enable TLS
TLS_CA(none)CA for verifying peer certificates — falls back to the system trust store if unset
TLS_SKIP_VERIFYfalseSkip peer certificate verification — test only
DOCKERfalsePins the internal listen ports to 5225/6225 in cluster mode — set by default in the official image
DEBUGDepends on build1/true enables debug logging

For the complete rules (port derivation, advertised addresses, zero-downtime token rotation, etc.) see Configuration (Env Vars).

Single vs. Cluster

  • Single (1 node): without CLUSTER_*, the node runs standalone. Fastest, but there's a brief blip on restart, and state is in-memory so it's lost on restart (lease is the safety net).
  • Cluster (non-stop): 3 or 5 nodes. The nodes share a single lock state via Raft consensus — only the leader handles requests, and every state change is only finalized after a majority commit. If the leader dies, a new one is elected within 0.5-1 second, and as long as a majority stays alive, the lock state and service keep running. See How It Works and Protocol (Cluster) for the full explanation.
  • Each cluster node listens on the client port plus a Raft port (client port + 1000) — open both ports in your firewall.

Kubernetes cluster deployments use a StatefulSet + headless Service. Give each pod a stable DNS name (ticketing-0.ticketing…, ticketing-1.ticketing…), put those names into CLUSTER_PEERS, and auto-inject each pod's CLUSTER_SELF via the downward API (metadata.name).

Non-Stop Restart (Rolling)

There's one core rule — a majority must always stay alive (at most 1 of 3 down at a time).

  1. Restart followers first, one at a time. Once a restarted node catches up via replication or a snapshot, move on to the next.
  2. Finally, take down the leader — a new one is elected within 0.5-1 second, and clients switch over transparently.
  3. Bringing a downed node back up rejoins it as a follower.

See Rolling Restart Procedure for the detailed steps.

Reference