Self-host Dots
Run Dots with one command: bundled Postgres, bundled object store, in-process identity plane, and secrets generated on first boot.
The supported self-host path is the committed self-contained stack. It runs the web app, API, worker, Postgres, an object store, and the in-process identity plane without an external identity vendor, a storage account, or a secret manager. File uploads work out of the box.
If you want an instance running today rather than the full reference, Quickstart: Self-hosting Dots is the short route through the same stack.
1. Start The Stack
No configuration is required. From the repository root:
docker compose -f deploy/self-contained/docker-compose.yml up --build
On first boot a one-shot secrets service generates the database password, the
session-signing secret, the workspace company id, and the object store's
credentials into a persistent volume, and the rest of the stack sources them.
They are generated once and never rotated when containers are recreated, so
there is nothing for you to record or rotate. A one-shot init service then
applies migrations and provisions the storage bucket.
Open http://localhost:3000 and sign up. The first signup becomes the owner
and provisions the workspace — no owner credentials ship with the stack, and none
need to be set.
2. Configure Only What You Want To Change
Everything above works with no env file. To add a chat provider or override a
default, copy deploy/self-contained/.env.selfcontained.example to .env beside
the compose file; anything you set there wins over the generated defaults. Never
commit the filled-in .env.
The one value most evaluators set is a chat provider — OPENROUTER_API_KEY or
OPENCLAW_GATEWAY_URL. Without one the stack still boots, still passes its health
probe, and still serves login; only conversations degrade until a provider is set.
PUBLIC_APP_URL defaults to http://localhost:3000. Plain HTTP is accepted for
loopback hosts only, so a local evaluation needs no TLS; serving the stack at a
real hostname requires setting it to an https:// origin.
3. Verify The Instance
- Open
http://localhost:3000/api/v1/healthzand confirm a successful response. - Sign in through the Dots login page. The session is issued and verified by the in-process identity plane.
- Create a Dotabase with a File property, upload a small file, and reopen it. The persisted URL lasts six days; reads mint a fresh one-hour URL from the durable object path.
- Confirm the worker remains healthy and background work continues after the first request.
For Railway, use deploy/self-contained/railway.json. It declares the same app,
worker, and bundled-Postgres capability, but it is bring-your-own storage and
brings no object store of its own: set the secret-bearing variables — including the
owner credentials and the DOTS_S3_* set if you want uploads — in the Railway
dashboard; do not commit them.
Connectors: Bring Your Own Key
Connectors — notion, github, fathom, fireflies — are optional and bring-your-own.
No connector key ships with the stack and none is relayed on your behalf, so with
none configured the instance still boots, serves, and onboards exactly as above.
With no key configured, the Integrations surface reports no configured key and a
gateway call returns COMPOSIO_GATEWAY_UNAVAILABLE. Nothing else is affected.
There are two ways to supply a key, and on a self-hosted instance the per-user path is the better default:
- A personal key — recommended, no server configuration. Each person saves
their own Composio API key under Settings → Workspace → Integrations. A
personal key overrides the deployment key for that person, so their connections
run under their own Composio account. This works on an instance that has no
deployment key at all, which is why nothing in
.envis required to make connectors usable. - A deployment-wide key. Set
COMPOSIO_API_KEYin.envto give everyone a shared default that a personal key still overrides per person. It does not stand alone: with it set, the four Auth Config ids from the same Composio project —COMPOSIO_AUTH_CONFIG_NOTION,COMPOSIO_AUTH_CONFIG_GITHUB,COMPOSIO_AUTH_CONFIG_FATHOM, andCOMPOSIO_AUTH_CONFIG_FIREFLIES— are required too, and the app refuses to start while any of them is missing or blank, naming the ones it needs.
Bring Your Own Infrastructure
You may replace bundled Postgres or storage independently:
- Managed Postgres: supply
DATABASE_URLandDIRECT_URL, keepDOTS_RAW_POSTGRES=0, and preserve the provider's TLS requirements.DOTS_RAW_POSTGRES=1is an explicit capability declaration for the bundled plain-Postgres service; unset or0keeps init from installing the raw-Postgres compatibility schema or disabling TLS. - S3-compatible storage: point the complete
DOTS_S3_*set at your own endpoint instead of the bundled object store.DOTS_STORAGE_DRIVER=diskalso accepts uploads, but stores them on the app process's local filesystem; container-local files are ephemeral and separate app/worker services do not share them. - SMTP and social sign-in are optional additions. Core email/password identity remains in-process.
Keep migrations and init inside a protected deployment job, verify the target connection before running them, and fail the deployment if init or the health probe fails.
To watch the running instance from your own tooling, Self-host Telemetry covers exporting traces and metrics over OTLP to a collector you control.
Self-host Dots · This page in the graph
- referencestoSelf-host Telemetry
- mentionstoConversations
- mentionstoCreate A Dotabase
- referencestoQuickstart: Self-hosting Dots
- mentionstoDots
- referencestoREST API Overview
- referencestoAccess And Tenancy
- referencesfromSelf-host Telemetry
- referencesfromAdmin Overview
- referencesfromQuickstart: Self-hosting Dots
- documented byfromSelf-Hosted Schema and Migrations
- documented byfromOne-Shot Self-Host Initialization
- referencesfromQuickstart