# Self-hosting

Run Authlane as one hardened application with PostgreSQL and Redis.

The application container serves the dashboard, hosted connect UI, API, OAuth callbacks, and
background workers. A one-shot migration container prepares PostgreSQL.

## Prerequisites

Use Node.js 22-compatible images, PostgreSQL 16, Redis 7, a maintained TLS ingress, and independent
random values for every secret and keyring.

## Implement the workflow

```bash
cp .env.example .env
openssl rand -hex 32
docker compose up --build -d
curl --fail http://127.0.0.1:3000/health
```

Set `APP_URL`, `BETTER_AUTH_URL`, and CORS values to exact public HTTPS origins. Keyring entries use
`key-id:64-hex-key` with the current key first; Better Auth entries use `version:secret` with the
current version first.

Use `DATABASE_URL` for the NOBYPASSRLS application role and `SYSTEM_DATABASE_URL` for the narrowly
granted worker. Keep PostgreSQL and Redis on private networks and require TLS when traffic leaves a
private host.

Point the SDKs at your deployment. Both default to the hosted control plane at
`https://app.authlane.io`, so this is the one place the option is needed:

```typescript
import { Authlane } from '@authlane/sdk';

const authlane = new Authlane({
  apiKey: process.env.AUTHLANE_API_KEY!,
  // Only a self-hosted deployment needs this; the default is https://app.authlane.io.
  baseUrl: process.env.AUTHLANE_BASE_URL,
});
```

```python
import os

from authlane import Authlane

with Authlane(
    api_key=os.environ["AUTHLANE_API_KEY"],
    # Only a self-hosted deployment needs this; the default is https://app.authlane.io.
    base_url=os.environ["AUTHLANE_BASE_URL"],
) as authlane:
    services = authlane.services.list()
```

## Choose an authentication mode

Authlane defaults to `AUTHLANE_AUTH_MODE=email-password` for backwards-compatible self-hosting and
the local demo. This mode keeps password sign-in, email verification when Resend is configured, and
TOTP for sensitive dashboard changes.

For a passwordless installation, set:

```bash
AUTHLANE_AUTH_MODE=magic-link
AUTHLANE_ALLOW_SIGNUP=true
RESEND_API_KEY=<runtime-only Resend sending key>
EMAIL_FROM=Authlane <auth@mail.authlane.io>
```

Production `magic-link` mode fails at startup when `RESEND_API_KEY` or `EMAIL_FROM` is missing. Verify
the sender domain's DKIM and SPF records before switching traffic. Links are single-use, stored only
as hashes, and expire after ten minutes. `AUTHLANE_ALLOW_SIGNUP=false` lets existing users sign in but
prevents a link from creating a new account.

Never paste a production sending key into source control, build arguments, issue trackers, logs, or
chat. If a key is disclosed, revoke it and create a replacement before deployment.

## Configure the optional AI Sandbox

The direct tool runner needs no model provider key. To use the production-like Vercel AI SDK agent,
set one or more runtime-only provider keys:

```bash
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
GOOGLE_GENERATIVE_AI_API_KEY=
```

Only organization owners and admins can use Sandbox. Keys stay server-side and the selected model
provider receives the ephemeral prompt and any tool context according to its own data policy. See
[Test connections in Sandbox](/docs/guides/sandbox) for the execution boundary and audit behavior.

Optional local monitoring starts with:

```bash
docker compose --profile monitoring up -d
```

Prometheus authenticates to `/metrics` with `METRICS_BEARER_TOKEN`; Grafana binds to `127.0.0.1` by
default.

## Expected result

The migration container exits successfully and one non-root Authlane runtime serves every product
surface. PostgreSQL and Redis are not public.

## Handle errors

Check migration-role permissions, RLS runtime grants, Redis authentication, exact origin values,
and retained keyring versions before changing application code.

## Security boundary

Terminate TLS at a maintained ingress, keep the final root filesystem read-only, drop Linux
capabilities, and never give the runtime migration privileges.

## Next step

Complete [security operations](/docs/guides/security-operations) and run the
[performance benchmark](/docs/guides/performance).
