# Self-Hosting an OBEP Relay

OBEP is self-hostable: the reference relay in [`obep/relay-reference`](../obep/relay-reference/)
is a conformant relay you can run yourself. You do not need OpenErrand.

## Run the reference relay

```bash
corepack enable && pnpm install
PORT=8787 pnpm --filter @obep/relay-reference start
# ws://localhost:8787   health: http://localhost:8787/health
```

Front it with a TLS-terminating reverse proxy (nginx/Caddy) for `wss://` in production;
the reference relay speaks `ws://` and trusts the proxy.

## REST surface

| Endpoint | Auth | Purpose |
|---|---|---|
| `GET /health` | none | liveness |
| `GET /relay-key` | none | the relay's Ed25519 public key (for task-token verification) |
| `POST /pairing-tokens` | `Bearer <apiKey>` | issue a single-use pairing token for `{ userId }` |
| `GET /audit/:tenantId` | `Bearer <apiKey>` | that tenant's audit records (cross-tenant ⇒ 403) |

WebSocket (`/`) speaks the OBEP wire protocol (hello/pair/task.start/command/context/status).

## Provisioning

The reference relay keeps tenants, API keys, playbooks, and bindings **in memory**
(see [`Registry`](../obep/relay-reference/src/registry.ts)). For production, implement
the `AuditStore` interface against Postgres and add durable tenant/key/playbook storage —
the protocol contract is unchanged. Register programmatically:

```ts
import { startRelay } from "@obep/relay-reference";
const relay = await startRelay({ port: 8787 });
relay.registry.registerTenant("tenantA", tenantPublicKeyB64);
await relay.registry.registerApiKey("tenantA", apiKey);
relay.registry.registerPlaybook(signedPlaybook);
```

Authoring playbooks (sign with the tenant key; the relay holds only the public key):

```bash
P=obep/cli/src/index.ts
node --import tsx $P keygen --out keys
node --import tsx $P sign examples/playbooks/portal-upload.json --key keys/tenant.key --out signed.json
```

## Prove your relay is conformant

Implement `RelayProvisioner` against your relay and run the open conformance suite —
it must pass all checks (see [`runConformance`](../obep/conformance/src/runner.ts)).
This is how a customer's security team verifies *any* relay without trusting it.

## Enterprise installs

Pin the relay endpoint via Chrome managed config (`chrome.storage.managed.relayUrl`) so a
compromised page can't redirect the extension to a rogue relay. See
[Enterprise deployment](./ENTERPRISE_DEPLOYMENT.md) for managed config and auto-pairing.
