# Self-host Provon On Cloudflare

The Cloudflare runtime deploys Provon into your Cloudflare account with independently scalable
Workbench, API, Gateway, OTLP, jobs, and telemetry warehouse surfaces.

This is the advanced self-hosting path. It replaces the Node process and local stores with
Cloudflare platform primitives; it is not a remote front end for a Provon-hosted control plane.

## Architecture

| Surface                    | Entrypoint or config                   | Responsibility                                       |
| -------------------------- | -------------------------------------- | ---------------------------------------------------- |
| Workbench                  | `services/cloudflare-worker/workbench` | SvelteKit UI on Pages                                |
| API Worker                 | `wrangler.api.toml`                    | Identity, sessions, control API, and telemetry reads |
| Gateway Worker             | `wrangler.gateway.toml`                | Model traffic, routing, policy, and trace capture    |
| OTLP Worker                | `wrangler.otel.toml`                   | OTLP authentication, validation, staging, and queue  |
| Jobs Worker                | `wrangler.jobs.toml`                   | Queue consumers, diagnostics, summaries, and cron    |
| Telemetry warehouse Worker | `wrangler.telemetry-warehouse.toml`    | Internal organization routing for telemetry writes   |
| Warehouse Container        | `Dockerfile.telemetry-warehouse`       | Iceberg append, summary replacement, and retention   |

Backing services are D1, R2, R2 Data Catalog, R2 SQL, KV, Queues, Durable Objects, Containers, and
Pages. See [Self-hosting architecture](./self-hosting-architecture.md) for the complete data flow.

## Requirements

- A Cloudflare account with the platform products used by the checked-in Wrangler configs.
- Node.js 22 or newer and pnpm 10.
- Wrangler 4 authentication for the target account.
- Custom domains or routes for the Workbench, API, Gateway, and OTLP surfaces.
- API tokens for deployment, R2 SQL reads, and R2 Data Catalog mutations.
- A secret manager or CI secret store.

Check the installed CLI and account before provisioning:

```bash
pnpm exec wrangler --version
pnpm exec wrangler whoami
```

Cloudflare product availability and limits change independently. Confirm that Containers, R2 Data
Catalog, and R2 SQL are enabled for the target account before committing to this architecture.

## 1. Prepare Wrangler Configs

The `.example.toml` files declare the complete binding topology:

```text
services/cloudflare-worker/wrangler.api.example.toml
services/cloudflare-worker/wrangler.gateway.example.toml
services/cloudflare-worker/wrangler.otel.example.toml
services/cloudflare-worker/wrangler.jobs.example.toml
services/cloudflare-worker/wrangler.telemetry-warehouse.example.toml
```

Create environment-specific configs from them. Keep binding names unchanged; replace resource IDs,
account coordinates, domains, and service names for the target environment.

The tracked `wrangler.*.toml` files are deployment inputs. Do not put secret values in them.

## 2. Provision Storage And Queues

Create the named resources:

```bash
pnpm exec wrangler d1 create provon-meta
pnpm exec wrangler kv namespace create provon-gateway-cache

pnpm exec wrangler r2 bucket create provon-blobs
pnpm exec wrangler r2 bucket create provon-telemetry
pnpm exec wrangler r2 bucket catalog enable provon-telemetry

pnpm exec wrangler queues create provon-ingest
pnpm exec wrangler queues create provon-ingest-dlq
pnpm exec wrangler queues create provon-telemetry-summary
pnpm exec wrangler queues create provon-workflow-runs

pnpm exec wrangler pages project create provon-app --production-branch main
```

Record:

- the D1 database ID;
- the KV namespace ID;
- the R2 Data Catalog URI and warehouse name;
- the Cloudflare account ID.

Do not create separate metadata databases or telemetry buckets for each Worker. The surfaces share
one deployment boundary through bindings.

## 3. Wire The Bindings

Update the environment-specific configs:

### API

- bind `PROVON_META_DB` to `provon-meta`;
- bind `PROVON_BLOB_BUCKET` to `provon-blobs`;
- set the R2 SQL account, bucket, and namespace;
- bind the telemetry warehouse and Jobs Worker services;
- set Workbench origins and cookie policy.

### Gateway

- bind the same D1 database;
- bind `PROVON_GATEWAY_CACHE` to the KV namespace;
- bind Gateway telemetry and workflow producers;
- preserve the checked-in Durable Object classes and migrations.

### OTLP

- bind the same D1 database and blob bucket;
- bind the ingest and telemetry-summary producers;
- bind the telemetry warehouse service;
- use the same R2 SQL coordinates as the API and Jobs Worker.

### Jobs

- bind the same D1 database and blob bucket;
- bind and consume the ingest, telemetry-summary, and workflow queues;
- bind the ingest DLQ;
- bind the Gateway model and telemetry warehouse services;
- preserve the scheduled triggers.

### Telemetry Warehouse

- set `PROVON_R2_CATALOG_URI` and `PROVON_R2_CATALOG_WAREHOUSE` from catalog creation;
- set the R2 object endpoint and account coordinates;
- preserve the Container and Durable Object bindings.

### Workbench

Set `PROVON_API_ORIGIN` to the public API origin in
`services/cloudflare-worker/workbench/wrangler.toml`.

## 4. Configure Public Origins

A typical split-domain layout is:

| Surface   | Example                          |
| --------- | -------------------------------- |
| Workbench | `https://app.provon.example`     |
| API       | `https://api.provon.example`     |
| Gateway   | `https://gateway.provon.example` |
| OTLP      | `https://otel.provon.example`    |

Set on the API Worker:

```toml
[vars]
PROVON_AUTH_TRUST_HOST = "true"
PROVON_AUTH_COOKIE_DOMAIN = ".provon.example"
PROVON_WORKBENCH_ORIGINS = "https://app.provon.example"
```

Register sign-in and Connector OAuth callbacks on the public API origin:

```text
https://api.provon.example/api/auth/callback/github
https://api.provon.example/api/auth/callback/google
https://api.provon.example/v1/integrations/github/callback
```

Use exact browser origins in `PROVON_WORKBENCH_ORIGINS`. Do not use `*` for a credentialed
Workbench.

## 5. Set Secrets

Generate one stable `AUTH_SECRET` and set the same value on every runtime that reads sessions or
encrypted project credentials:

```bash
pnpm exec wrangler secret put AUTH_SECRET --config services/cloudflare-worker/wrangler.api.toml
pnpm exec wrangler secret put AUTH_SECRET --config services/cloudflare-worker/wrangler.gateway.toml
pnpm exec wrangler secret put AUTH_SECRET --config services/cloudflare-worker/wrangler.otel.toml
pnpm exec wrangler secret put AUTH_SECRET --config services/cloudflare-worker/wrangler.jobs.toml
```

Enter the same secret through each interactive prompt. Do not pass it as a command argument or store
it in TOML.

Set the R2 SQL read token on surfaces that query telemetry:

```bash
pnpm exec wrangler secret put PROVON_R2_SQL_TOKEN --config services/cloudflare-worker/wrangler.api.toml
pnpm exec wrangler secret put PROVON_R2_SQL_TOKEN --config services/cloudflare-worker/wrangler.otel.toml
pnpm exec wrangler secret put PROVON_R2_SQL_TOKEN --config services/cloudflare-worker/wrangler.jobs.toml
```

Set the Data Catalog read-write token on the warehouse runtime:

```bash
pnpm exec wrangler secret put PROVON_R2_DATA_CATALOG_TOKEN \
  --config services/cloudflare-worker/wrangler.telemetry-warehouse.toml
```

Add identity-provider, model-provider, billing, and Connector secrets only to the runtimes that use
them. See [Self-hosting configuration](./self-hosting-configuration.md).

## 6. Validate And Deploy

Run the Worker validation chain:

```bash
pnpm test:cf
```

Inspect telemetry maintenance commands before applying them:

```bash
pnpm configure:cf:telemetry-maintenance
pnpm configure:cf:telemetry-maintenance:apply
```

The maintenance configuration adds:

- expiration for staged OTLP payloads;
- Data Catalog snapshot expiration with an idempotency-safe minimum;
- Iceberg compaction.

Deploy the complete stack:

```bash
pnpm deploy:cf
```

The command applies D1 migrations first, then deploys the telemetry warehouse, OTLP, Gateway, Jobs,
API, and Workbench surfaces. It stops before publishing new Worker code when the metadata migration
fails.

Never rename or rewrite a migration that reached a persistent environment. Add a forward migration
for the next schema change.

## 7. Verify Each Surface

Verify runtime health:

```bash
curl --fail --silent https://api.provon.example/healthz
curl --fail --silent https://gateway.provon.example/healthz
curl --fail --silent https://otel.provon.example/healthz
```

Then run separate end-to-end checks:

1. Open the Workbench and sign in.
2. Create a project API key through the API surface.
3. Send OTLP to the OTel origin and wait for the trace to become queryable through the API.
4. Send a model request to the Gateway origin and confirm its provider-attempt trace.
5. Run one workflow or diagnostic Rule and confirm the Jobs Worker consumes it.
6. Confirm scheduled retention and stale-reservation maintenance logs.

A `2xx` OTLP response means the payload was accepted and queued. It does not prove that the Jobs
Worker, warehouse Container, R2 Data Catalog, or R2 SQL read path completed.

## Local Cloudflare Development

Create `.dev.vars` from `.dev.vars.example`, then run:

```bash
pnpm dev:cf
```

This starts the API Worker as the primary Wrangler process and includes the OTel, Gateway, and Jobs
Workers as auxiliary services. Start the Workbench separately:

```bash
pnpm dev:pages
```

Use surface-specific `dev:worker:*` scripts when isolating one Worker. Local emulation is not a
substitute for a staging environment that exercises real Queues, R2 SQL, Data Catalog, Containers,
and Service Bindings.

## Current Constraints

- Local `self/*` model execution is Node-only.
- Telemetry reads require the Cloudflare R2 SQL backend.
- The default read model uses trace summaries and requires the telemetry-summary queue on writer
  surfaces.
- The warehouse Container and its Service Binding are required for Iceberg mutations.
- Cloudflare resource cost, quotas, regions, and recovery guarantees remain account-level operator
  responsibilities.

## Next Steps

- [Configuration](./self-hosting-configuration.md)
- [Security](./self-hosting-security.md)
- [Operations](./self-hosting-operations.md)
- [Telemetry architecture](./telemetry.md)
- [Troubleshooting](./troubleshooting.md)
