> ## Documentation Index
> Fetch the complete documentation index at: https://browser-mcp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-host the community edition

> Build an artifact, configure secrets, and operate a single server with PostgreSQL.

## Production prerequisites

Use a dedicated hostname, HTTPS termination, a backed-up PostgreSQL database, and a secret manager. Restrict network access during first-account bootstrap. Use the [Helm guide](/helm) for Kubernetes; the Compose file is a loopback-bound local development setup, not a hardened public deployment.

## Build-time editions

```bash theme={null}
bun install --frozen-lockfile
(cd frontend && bun install --frozen-lockfile)
EDITION=community bun scripts/build.ts
```

The build produces `dist/server.js`, `dist/migrate.js`, and `dist/web/`. Migrations are included by the bundled migration entrypoint; production does not invoke source files or rely on a source checkout.

```bash theme={null}
# Supply production environment securely before these commands.
bun dist/migrate.js
bun dist/server.js
```

Run migrations successfully before exposing the new server version. Never run multiple independent migration processes intentionally.

## Container build

```bash theme={null}
docker build --build-arg EDITION=community -t browser-mcp:local-community .
```

Bun and dependencies are installed in a build stage, with root and frontend lockfiles installed separately. The runtime contains only the generated distribution, runs as the unprivileged `bun` user, listens on port 3000, and starts `bun dist/server.js`. To run migrations, override the command to `bun dist/migrate.js` using the same image and database settings.

Do not supply auth secrets as Docker build arguments. `EDITION` is not a runtime switch. Prefer versioned release tags and pin a verified digest for production; no `latest` tag is required by the chart.

## Required environment

| Variable                  | Meaning                                                                                                                      |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `DATABASE_URL`            | PostgreSQL connection string. Use a dedicated database, restricted credentials, and verified TLS for remote databases.       |
| `PUBLIC_URL`              | Canonical public origin, such as `https://browser.example.com`, with no trailing slash or path.                              |
| `AUTH_SECRET`             | Independently generated, strong random authentication secret.                                                                |
| `SETTINGS_ENCRYPTION_KEY` | Independently generated encryption key for stored OIDC secrets and pending device credentials; retain securely with backups. |

Generate the two keys independently with `openssl rand -hex 32`. Never use documented placeholders in production. See [configuration](/configuration) for all build and runtime settings.

## Reverse proxy

Forward HTTP and WebSocket upgrades to port 3000, preserving the public host and scheme. Permit `/ws/browser`, `/b/*/mcp`, `/api/*`, and dashboard assets. Do not cache authenticated API or MCP responses. Allow long-lived WebSockets; extension heartbeats occur every 20 seconds. Do not log `Authorization`, cookies, device proofs, or request/response bodies.

Expose only the proxy publicly. Restrict PostgreSQL to the app and administrative backup paths. Health checks are `/healthz` (process) and `/readyz` (database connectivity); readiness is not a substitute for migration success.

## Bootstrap and OIDC

The first community registration becomes administrator atomically. Protect the installation until you have registered. Afterward, public password signup is disabled. Configure your organization's provider in the [OIDC admin settings](/authentication) to admit later users.

## Backups and upgrades

Back up PostgreSQL and preserve `SETTINGS_ENCRYPTION_KEY` and auth secrets in a separate secret store. Test restores. A database backup without the encryption key cannot restore encrypted settings. Keep the previous image digest, but remember that rolling back an image **does not** undo schema changes.

The single-server design has planned downtime on every restart or upgrade. Reconnect browsers afterward and verify a harmless MCP command before reopening access. See [operations](/operations).
