Install
Ursula installs two ways: pull the pre-built Docker image from GHCR, or build from source. Standalone release binaries are on the way; the source build is plain Rust plus the standard C toolchain that Cargo expects, with no embedded KV dependency.
Ursula ships two binaries you will use side by side:
ursula: the server daemon. Runs on every node in the cluster.ursulactl: the operator CLI. Lives on your control machine and talks to each node's HTTP surface. See ursulactl for the verbs it exposes.
Docker image
Every release publishes a multi-arch image containing ursula, ursulactl, and the ursulagw gateway:
docker pull ghcr.io/tonbo-io/ursula:0.2.0
docker run --rm -p 4437:4437 ghcr.io/tonbo-io/ursula:0.2.0
The image runs as a non-root user and exposes port 4437. latest tracks the main branch; pin a version tag for anything you keep running. For Kubernetes, the Helm chart wires this image up for you.
Prerequisites
Required:
- the pinned Rust nightly toolchain from
rust-toolchain.tomland Cargo - a C compiler (for transitive native crates)
pkg-config
On macOS, install rustup so Cargo selects the pinned nightly from rust-toolchain.toml:
brew install rustup pkg-config
rustup-init -y
On Debian or Ubuntu:
sudo apt-get update
sudo apt-get install -y build-essential pkg-config curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Clone and build
git clone https://github.com/tonbo-io/ursula.git
cd ursula
cargo build --release -p ursula -p ursula-ctl
The resulting binaries land at target/release/ursula and target/release/ursulactl. Ship ursula to every node; keep ursulactl wherever you run operational tooling (laptop, CI runner, bastion host).
To work on the whole workspace:
cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo build --workspace compiles every crate. For just the server use cargo build -p ursula; for just the CLI use cargo build -p ursula-ctl.
Verify
./target/release/ursula --help
./target/release/ursulactl --help
Both should print supported CLI flags. From the repository root, ./target/release/ursula --preset default still performs config-file discovery and will load ./ursula.toml when present. Use that command when you want the bundled ./ursula.toml with the default preset; for a true no-file smoke test, run from a directory with no Ursula config file or temporarily move/rename ./ursula.toml first.
./target/release/ursula --preset default &
For a single local node, ursulactl needs a one-node manifest to talk to:
cat > /tmp/local.json <<'JSON'
{"nodes": [{"id": 1, "http_url": "http://127.0.0.1:4437", "host": "127.0.0.1"}]}
JSON
./target/release/ursulactl status --config /tmp/local.json
Or, for a quick eyeball without writing a manifest, hit the HTTP surface directly:
curl -X PUT http://127.0.0.1:4437/demo
curl -X PUT http://127.0.0.1:4437/demo/hello
curl -X POST -H 'Content-Type: text/plain' --data 'hi' http://127.0.0.1:4437/demo/hello
curl 'http://127.0.0.1:4437/demo/hello?offset=-1'
Kill the background process when you're done.
Next
- Quick start: drive the HTTP API end-to-end
- Run locally: durability modes and flags
- Deploy a cluster: static gRPC Raft cluster
- Deploy on Kubernetes: one
helm installfrom the published chart - ursulactl: the verbs you'll use once the cluster is up
- Configure S3: shared cold storage