Lockwell home
Guide

Getting started

Run Lockwell with Docker, install an SDK, store your first file, and hand the browser a direct upload URL, in about five minutes.

Download .md

Lockwell is an object store you host yourself. Your app talks to it through one SDK: files in, files out, per-customer isolation built in.

Early access

Lockwell is closed source during early access. The package versions on this page are historical builds; early-access customers receive current packages, the deployment repository and a licence with their access. Request access at hello@rusticstack.com. An MIT-licensed source release is planned.

This page gets you to a working result: run the server, store a file, read it back, and let a browser upload directly. Concepts can wait; when a term is new, Concepts in plain words defines it in a sentence.

1. Run Lockwell

One container, one volume, no external database.

git clone https://github.com/RusticStack/lockwell-deploy.git
cd lockwell-deploy
cp .env.example .env
docker compose up -d --build

Before up, open .env and replace the two CHANGE_ME values with long random strings. They become your first access key, and the container refuses to start while the placeholders are still in place.

Check it is alive:

curl -fsS http://localhost:9000/health

You now have two listeners and one credential:

  • http://localhost:9000: the public listener (object I/O)
  • http://localhost:9001: the admin listener (management, kept private)
  • the access key from .env, already bootstrapped with full data access

Already running Lockwell somewhere? Skip ahead and use your own endpoint and key.

2. Install the SDK

npm i @kelphect/sdk

Registries, prerequisites, and client options live on the Installation page.

This quickstart intentionally uses the HTTP-native JSON client. LNW/1 is an experimental, opt-in binary transport on a separate TLS 1.3 listener; use the Native Wire guide and its server-only SDK guides after the listener and runtime have passed their qualification gates.

3. Store a file and read it back

Point the native client at the public listener with the key from .env. It mints and refreshes its own short-lived token; you never touch auth plumbing.

import { NativeClient } from "@kelphect/sdk";

const native = new NativeClient({
  endpoint: "http://localhost:9000",
  accessKeyId: process.env.LOCKWELL_ROOT_ACCESS_KEY_ID,
  secretKey: process.env.LOCKWELL_ROOT_SECRET_KEY,
});

await native.createBucket("inbox");
await native.putObject("inbox", "hello.txt", "hi there", { contentType: "text/plain" });

const got = await native.getObject("inbox", "hello.txt");
console.log(got.body.toString()); // "hi there"

That is a private, encrypted object store taking writes. Streaming, ranges, listing, versions, and the rest of the object API start at Upload & download.

4. Let the browser upload directly

Sign a short-lived PUT URL on your server and hand only the URL to the browser. The file bytes go straight to Lockwell, and your key never leaves the server.

// Server-side: the signed URL comes back as a path; join it to the endpoint.
const signed = await native.signUrl({
  method: "PUT",
  bucket: "inbox",
  key: "photo.jpg",
  ttlSeconds: 300,
});
const url = new URL(signed.url, "http://localhost:9000").toString();

// Browser-side:
await fetch(url, { method: "PUT", body: file });

The URL is bound to one method and one object, expires on its TTL, and can never exceed the signing key's scope. The full flow, including the download direction, is on Signed URLs.

That's it

You ran the server, stored a file, read it back, and took a browser upload. One SDK, no second store, no glue code.

Going multi-tenant

The quickstart used the bootstrap root key. For a real app you give each customer their own tenant and a key scoped to it, so customers are isolated by the credential itself.

That is the job of the admin API and the app kit (provisionTenant, clientForTenant). The admin API needs an admin token, which is minted offline because the CLI and the daemon cannot hold the embedded store at the same time:

docker compose stop lockwell
docker compose run --rm lockwell lockwell admin-token create --name my-app --role owner
docker compose start lockwell
# prints an lwadm_... token exactly once. Store it as LOCKWELL_ADMIN_TOKEN.

Then follow The app kit for the provision-and-go flow, and Tenancy & auth for the model behind it.

Next steps

On this page