Baalda

Deploy the server

What the server is, the one port it needs, and four ways to run it: Docker, Compose, Railway or Coolify.


The server is open source under Apache-2.0 and there is no paid tier for running it yourself. It is one Node service plus Postgres. Attachment bytes can live in Postgres too, so a working deployment can be two containers.

Ports

VariableDefaultWhat it serves
PORT3010The REST and auth API, the per-note sync WebSocket at /sync, and the vault channel at /vault-sync. This is the only port a deployment needs to expose.
HOCUSPOCUS_PORT3011A legacy dedicated port for the editing socket, used in local development and by much older clients. Not required in production.

Option A: plain Docker

Build the image from the repository root, not from the server directory. The server is one workspace of a pnpm monorepo and needs the workspace root's package.json, pnpm-lock.yaml and pnpm-workspace.yaml to resolve its dependencies.

bash
docker build -f app/apps/server/Dockerfile -t baalda-server .
docker run -p 3010:3010 \
  -e DATABASE_URL=postgres://… \
  -e JWT_SECRET="$(openssl rand -base64 32)" \
  -e BETTER_AUTH_URL=https://notes.example.com \
  baalda-server

Option B: Docker Compose

The bundle in deploy/compose brings up the server and Postgres together, and its README covers TLS, backups and upgrades.

deploy/compose
cd deploy/compose
cp .env.example .env    # POSTGRES_PASSWORD, JWT_SECRET, BETTER_AUTH_URL
docker compose up -d

Option C: Railway

One click provisions Postgres, generates its own signing secret, runs the migrations as a pre-deploy step with a healthcheck, and hands you an HTTPS URL. The repository carries the infrastructure definition, so a deployment is reproducible rather than clicked together.

Option D: Coolify

For a self-managed platform. Same image, same variables, with the deployment document covering the specifics of wiring the database and the healthcheck.

After it is up

  1. 1Check GET /health. It answers with the version and the feature list the desktop app reads.
  2. 2Set the server URL in the app, or send your team https://<your-server>/open/connect.
  3. 3Decide where attachment bytes live before people upload much: Postgres needs nothing, S3 needs a bucket and a CORS policy.
  4. 4Set up outbound email if you want password reset, verification and mailed invitations.
Update the server before the desktop app, not after. A newer app against an older server shows a notice that the backend is behind, and some features stay off until the server catches up.

This page is written from docs/DEPLOY.md and README.md in the repository. Those documents go further, and they are the ones that change first.

Read it on GitHub