The server is open source under Apache-2.0 and there is no paid tier for running it yourself. It is one HTTP service plus Postgres.
Ports
The server binds a single HTTP port, PORT, default 3010. That one port serves the REST and auth API, the per-note sync WebSocket at /sync, and the vault channel at /vault-sync. It is the only port a deployment needs to expose, and the only one the desktop app dials from version 0.1.42 onward, because it derives both WebSocket URLs from the server URL by appending the path, whatever the port.
HOCUSPOCUS_PORT, default 3011, still listens for anything dialling the dedicated Hocuspocus port directly, but nothing in the repository needs it reachable.
Desktop builds before 0.1.42 rewrote an explicit :3010 to :3011 for per-note sync. On a single-port deploy that port is unreachable, so folder structure synced while note content never uploaded. Updating the app fixes it; no server change is needed.
Ways to deploy
- Plain Docker. The image builds from the repository root, because 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 dependencies.
- Docker Compose. The bundle in deploy/compose brings the whole stack up in one command, and its README covers TLS, backups and upgrades.
- Railway, in one click. It provisions Postgres, generates its own signing secret, runs the migrations and hands you an HTTPS URL.
- Coolify, for a self-managed PaaS.
cd deploy/compose
cp .env.example .env # POSTGRES_PASSWORD, JWT_SECRET, BETTER_AUTH_URL
docker compose up -dEnvironment variables
The ones you will actually set on a first deployment:
DATABASE_URL, the Postgres connection string.JWT_SECRET, the signing secret. Generate a real one.BETTER_AUTH_URL, the public URL of the server.PORT, the single HTTP port, default 3010.CORS_ORIGINS, the origins allowed to call the API.SYNC_TOKEN_TTL_SECONDS, the lifetime of the short-lived per-document sync tokens.
There are more, covering the Postgres pool size, compaction thresholds, Redis, backfill concurrency and the batch limits. The deployment document has the full reference table.
Attachments
Attachments can live in the database or in S3-compatible object storage. The deployment document covers turning S3 on, the bucket CORS policy it needs, attachment garbage collection, and a migration that moves existing attachments across. It re-hashes every blob's bytes and refuses to move any row it cannot verify.
This page is written from docs/DEPLOY.md in the repository. That document goes further, and it is the one that changes first.
