Docs / Get started
Quickstart
Run one node on your own machine, then three nodes on one bucket with TLS, and connect a client.
- Works
- One node on loopback with a local directory; three nodes on one qualified bucket with TLS; psql, psycopg 3, node-postgres, pgjdbc and HTTP clients.
- Differs
- The local
fs:store is for development only. It says nothing about how a real bucket behaves. - Missing
- A public download, a macOS or Windows server binary, a managed service.
- Operational impact
- Creating a database reserves an immutable ID. Dropping a database does not reclaim its data in pre-beta.
- Evidence
- Steps follow the project's beta guide. The beta acceptance run has not passed yet.
You need a build first. There is no public download yet. Pre-beta builds are a release directory (binary, checksums, build record, example config and systemd unit) handed to invited testers. Join the waitlist.
#What you need
- The release directory, all files from the same release.
- Linux x86_64 with glibc 2.34 or newer (Ubuntu 22.04, Debian 12, RHEL 9 or later). The binary does not run on macOS.
- For part 2: three hosts that can reach each other on TCP 7101, and one bucket.
Check and install the binary:
sha256sum --check --ignore-missing SHA256SUMS
install -d -m 0755 "$HOME/.local/bin"
install -m 0755 gauntlet-*-linux-x86_64 "$HOME/.local/bin/gauntlet"
export PATH="$HOME/.local/bin:$PATH"
gauntlet --version # must list "engines: turso"#Part 1: one node on loopback
This runs one node against a directory on local disk. It needs no bucket and no certificates, because every listener is on 127.0.0.1.
mkdir -p "$HOME/gauntlet-dev" && cd "$HOME/gauntlet-dev"
export GAUNTLET_CLIENT_TOKEN=$(openssl rand -hex 32)
export GAUNTLET_PEER_TOKEN=$(openssl rand -hex 32)
export GAUNTLET_ADMIN_TOKEN=$(openssl rand -hex 32)
gauntlet --cache-dir "$PWD/cache" --cache-mib 512 serve \
--store "fs:$PWD/bucket" --id n1 \
--listen 127.0.0.1:7101 --pg-listen 127.0.0.1:7151 \
--memory-mib 4096--memory-mib 4096 is the smallest budget allowed. The node checks its store before it serves:
curl -s http://127.0.0.1:7101/health # "ok": the process answers
curl -si http://127.0.0.1:7101/ready # 200 when it can serve, 503 when it cannotIn a second terminal, with the same three tokens exported, create a database and get its token:
export GAUNTLET_URL=http://127.0.0.1:7101
gauntlet admin create-database app > app-create.json # keep this file
gauntlet admin list
TOKEN=$(gauntlet admin token app)Connect. The database token is the password, for any user name:
PGPASSWORD=$TOKEN psql "host=127.0.0.1 port=7151 dbname=app user=app" \
-c "CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT NOT NULL)" \
-c "INSERT INTO items VALUES (1, 'first')" \
-c "SELECT * FROM items"Stop the node with Ctrl-C. Start it again with the same command and the row is still there: everything it needs is under bucket/. The cache/ directory is disposable. A restart with the same --id takes 17–18 s to become ready, because it waits out the previous run's 15 s lease.
#Part 2: three nodes on one bucket
The examples use hosts n1.example.net, n2.example.net and n3.example.net, and an admin machine that is none of them.
#Choose a bucket
Gauntlet needs more than the S3 API. It needs atomic create-if-absent (If-None-Match: *), read-after-write consistency and a strongly consistent, ordered LIST. gauntlet qualify tests this for you, and every node start runs the same checks again. A bucket that fails is refused.
| Provider | Status |
|---|---|
| Tigris | Run by the project. Recommended: one region, next to the hosts |
| Cloudflare R2 | Run by the project. Conditional writes were slower in the project's runs, so commits are slower |
| AWS S3 | Unverified. No run is recorded. Qualify it first |
| MinIO | Unverified. No run is recorded. Qualify it first |
Details, including the environment variables, are in deploy and qualify a bucket.
#Secrets, certificates and config
On the admin machine, write one secrets file that every node uses, test the bucket, and issue certificates from the deployment's private CA:
umask 077
cat > secrets.env <<ENV
GAUNTLET_S3_ENDPOINT=https://t3.storage.dev
GAUNTLET_S3_REGION=auto
GAUNTLET_S3_BUCKET=my-gauntlet-bucket
GAUNTLET_S3_ACCESS_KEY_ID=<access key id>
GAUNTLET_S3_SECRET_ACCESS_KEY=<secret access key>
GAUNTLET_CLIENT_TOKEN=$(openssl rand -hex 32)
GAUNTLET_PEER_TOKEN=$(openssl rand -hex 32)
GAUNTLET_ADMIN_TOKEN=$(openssl rand -hex 32)
ENV
(set -a; . ./secrets.env; gauntlet qualify --store 's3:#qualify-check')
gauntlet tls init --out ca
for n in 1 2 3; do
gauntlet tls issue --ca ca --node n$n --dns n$n.example.net --dns localhost --out n$n
doneWrite /etc/gauntlet/gauntlet.toml on each host. Only id and advertise differ between nodes:
store = "s3:#gauntlet/beta" # GAUNTLET_S3_* plus this prefix; same on every node
id = "n1" # unique per node
listen = "0.0.0.0:7101" # HTTP: clients, admin and peers
advertise = "n1.example.net:7101" # a name in this node's certificate
pg-listen = "0.0.0.0:7151" # PostgreSQL wire protocol
tls-cert = "/etc/gauntlet/tls/node.crt"
tls-key = "/etc/gauntlet/tls/node.key"
tls-peer-ca = "/etc/gauntlet/tls/ca.crt"
cache-dir = "/var/lib/gauntlet/cache"
cache-mib = 8192
memory-mib = 16384
log-format = "json"Start all three with the packaged systemd unit. They find each other through leases in the bucket. A node answers neither /health nor /ready until its start-up bucket check passes.
#Create a database
export GAUNTLET_URL=https://n1.example.net:7101 GAUNTLET_TLS_CA=ca/ca.crt
set -a; . ./secrets.env; set +a
umask 077
gauntlet admin create-database app > app-create.json
TOKEN=$(gauntlet admin token app)If create-database reports an unknown outcome, retry with gauntlet admin create-database --reservation app-create.json. Never retry by name: that reserves a second ID.
#Connect
Any node serves any database. Use the database name as dbname, any user name, and the database token as the password.
PGPASSWORD=$TOKEN psql "host=n1.example.net port=7151 dbname=app user=app \
sslmode=verify-full sslrootcert=ca/ca.crt channel_binding=require" \
-c "SELECT 1"Driver examples are in PostgreSQL wire; the JSON API is in HTTP.
#Next
- Read transactions: your client must handle
40001and40003. - Take a first backup and practise a restore.
- Read the limits before you put data in.