The bundled compose file binds port 2099 to
127.0.0.1 only, so the dashboard is reachable on the host machine but not over the LAN. See Exposing on the LAN to change this.Installation
- Quick install (recommended)
- Docker Compose
- Docker Run (BYO PostgreSQL)
One command. The installer downloads the compose file into
Useful flags:
~/manifest, generates the secrets, and brings up the stack. First boot pulls the app image and Postgres, so give it up to a couple of minutes.Prefer to review the script before running it?
Prefer to review the script before running it?
--dir <path> to install elsewhere, --port <n> to serve on a port other than 2099, --dry-run to preview, --yes to skip the confirmation prompt.Re-running the installer against an existing install directory resumes it. The compose file and your generated secrets are left untouched.When the installer finishes, open http://localhost:2099 and sign up for an account. Then connect a provider and send your first request — see First request.First request
Signing up leaves you with an empty instance. Three steps to a routed request.1
Connect a provider
In the dashboard sidebar, open Providers and pick how you want to connect:
- Usage-based — paste an API key (OpenAI, Anthropic, Gemini, DeepSeek, …)
- Subscriptions — reuse a plan you already pay for (ChatGPT, Claude, GLM Coding Plan, …)
- Local — Ollama, LM Studio, or llama.cpp running on the host
2
Copy your agent's key
Every agent has its own key, shown when you create it and again under the agent’s Settings. It starts with
mnfst_.3
Send a request
The endpoint is OpenAI-compatible, so any SDK or agent that accepts a base URL works — point it at
http://localhost:2099/v1 with the mnfst_ key. To check it end to end:"model": "auto" asks Manifest to route the request. Any other name is treated as an explicit choice, and falls back to your routing config if it matches nothing you have connected.Errors raised by Manifest itself carry an
M### code, a plain-English cause, and a link to the matching page under manifest.build/docs/errors. The three you are most likely to see on a fresh install:Verifying the image signature
Published images are signed with cosign keyless signing (Sigstore). Verify before pulling:Custom port
If port 2099 is taken, setPORT in .env. That is the whole change:
${PORT:-2099} for both the published host port and the backend’s internal listener, and BETTER_AUTH_URL defaults to http://localhost:${PORT:-2099} — so one line covers all three, with no YAML edit. The install script writes it for you if you pass --port 8080.
For a docker run install there is no .env, so pass the mapping and the URL explicitly. The container keeps listening on 2099 and Docker remaps it:
Upgrading from a pre-2099 install? Your existing stack keeps running on port 3001 with no changes — the backend’s own fallback is still
3001, so the new image works against your old compose file. If you want to refresh your compose file but stay on the legacy port (to avoid reconfiguring OAuth callbacks, reverse proxies, or bookmarks), set PORT=3001 in .env and the bundled compose file will honour it for both the host binding and the internal listener.Exposing on the LAN
By default the compose file binds port 2099 to127.0.0.1 only. The dashboard is reachable from the host but not from other machines on the network. To expose it on the LAN:
1
Change the port binding
Edit
docker-compose.yml and change the ports line from "127.0.0.1:2099:2099" to "2099:2099".2
Set BETTER_AUTH_URL
In
.env, set BETTER_AUTH_URL to the host you’ll reach the dashboard on, e.g. http://192.168.1.20:2099 or https://manifest.mydomain.com. This must match the URL in the browser or Better Auth will reject the login with “Invalid origin”.3
Apply
Image tags
Every release is published with the following tags:
Images are built for both
linux/amd64 and linux/arm64.
Upgrading
Manifest ships a new image on every release. To upgrade an existing compose install:pgdata volume is preserved across upgrades. Pin to a specific major version (e.g. manifestdotbuild/manifest:5) in docker-compose.yml if you want control over when major upgrades happen.
Backup and persistence
The stack uses two named volumes:
The database volume is the one to back up. Losing the recordings volume costs you stored message bodies and nothing else, and those expire on a retention schedule regardless.
Back up (from the host, with the stack running):
Environment variables
Core
The first two are required and the installer generates both, so a default install boots without you setting anything.
Everything else is optional: rate limits, provider timeouts, email delivery for alerts and password resets, OAuth logins, connection-pool sizing, recording storage and retention, Auto-fix, and Sentry. See Environment variables for the full list with defaults.
NODE_ENV and SEED_DATA are fixed by the bundled compose file and are not knobs for a self-hosted install. The image is a production artifact, and the demo-data seeder refuses to run under NODE_ENV=production whatever SEED_DATA says — use the first-run setup wizard to create your admin account.BIND_ADDRESS is likewise set by the image (0.0.0.0, so the container is reachable through Docker’s port mapping); restrict exposure with the ports line in docker-compose.yml, not this variable.Stop and clean up
Data and privacy
Manifest always keeps metadata about each request — model, provider, tier, token counts, cost, latency. Message bodies are separate and optional: with message recording on for an agent, prompts and completions are stored too, in the recordings volume rather than the database. New agents have it enabled. See Data and telemetry.Telemetry
Once a day, each install sends an anonymous aggregate report: version, provider mix, token and cost totals. Never prompts, keys, or anything tied to a user. SetMANIFEST_TELEMETRY_DISABLED=1 in your .env to turn it off.
Full field list, what’s never sent, and how to point it at your own endpoint: Data and telemetry.