Run your own ULDA Server
Run a local server and connect your first client. The server stores opaque resources, validates witness transitions and delivers updates to subscribed clients.
Before you start
Install Docker with Linux container support, Docker Compose, Git and Node.js 22 or later. Keep local port 3000 available.
The commands below use the repository's local development and test stack, including a PostgreSQL fixture. Start with a new database volume. For an existing installation, follow the adoption procedure.
Run exactly one ULDA Server writer per database. PostgreSQL is a separate service; independent resources can still progress asynchronously within the single server process.
Prepare the project
Clone the source used by this guide:
git clone https://github.com/ulda-io/ulda-server.git
cd ulda-server
git checkout 5469821
This source revision contains the deployment instructions reviewed for Server 1.0.0.
- PowerShell
- Bash
Copy-Item .env.example .env
node scripts/create-local-secrets.mjs
cp .env.example .env
node scripts/create-local-secrets.mjs
The generator creates three random password files under the ignored secrets/ directory without displaying or overwriting them. Protect this directory with host filesystem permissions. Do not regenerate the files for an existing database: changing a file does not rotate its database password.
Start the local stack
Run each command from the repository root and check that it succeeds before continuing:
docker compose build
docker compose up -d postgres
docker compose run --rm -e ULDA_DB_SETUP=1 db-setup
docker compose up -d --no-build
docker compose ps -a
The setup job creates separate migration and runtime roles. The migration job applies the schema before the server starts. A completed migration container with exit code 0 is expected.
The server binds to 127.0.0.1:3000 by default. The PostgreSQL port is not published.
Check readiness
- PowerShell
- Bash
curl.exe -i http://127.0.0.1:3000/ready
curl -i http://127.0.0.1:3000/ready
Wait for HTTP 200 and a healthy server container before connecting a client. Readiness includes a storage check; a running process alone is not enough.
If startup fails, inspect the service status and logs:
docker compose ps -a
docker compose logs server migrate
Connect the SDK
Install ulda-auth@1.1.0 in your client application. The local constructor explicitly opts into loopback HTTP:
import { Ulda } from 'ulda-auth';
const ulda = new Ulda('http://127.0.0.1:3000', {
allowInsecureLocalhost: true,
});
try {
await ulda.ready;
console.log('Connected to ULDA Server');
} finally {
await ulda.close();
}
Follow Your first encrypted note to create a catalog and save data.
For a browser application, set CORS_ORIGINS in the server's .env to the application's exact origin, including its port, then recreate the server container. For example, a Vite application might use http://localhost:5173. CORS configuration is not authentication.
Stop and restart
docker compose down
docker compose up -d --no-build
The database volume survives down. Adding -v deletes the volume and its data.
Move to production
The published uldaio/ulda-server:1.0.0 image contains the application, PostgreSQL adapter and migration tools. It does not contain a running database or reverse proxy.
For a deployed service, supply:
- A dedicated, operator-managed PostgreSQL database and exactly one server writer.
- A trusted HTTPS/WSS endpoint, with certificates and WebSocket forwarding.
- Separate runtime and migration credentials, backups, monitoring and appropriate access controls.
Use the production deployment guide, which connects to an existing database network. The local PostgreSQL fixture is not a production release artifact. Review the image and pin its immutable digest for production.
Continue with configuration, operations and security requirements.