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
| Variable | Default | What it serves |
|---|---|---|
PORT | 3010 | The 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_PORT | 3011 | A 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.
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-serverOption B: Docker Compose
The bundle in deploy/compose brings up the server and Postgres together, and its README covers TLS, backups and upgrades.
cd deploy/compose
cp .env.example .env # POSTGRES_PASSWORD, JWT_SECRET, BETTER_AUTH_URL
docker compose up -dOption 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
- 1Check
GET /health. It answers with the version and the feature list the desktop app reads. - 2Set the server URL in the app, or send your team
https://<your-server>/open/connect. - 3Decide where attachment bytes live before people upload much: Postgres needs nothing, S3 needs a bucket and a CORS policy.
- 4Set up outbound email if you want password reset, verification and mailed invitations.
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 GitHubWas this page helpful?
