From be60440ca0c8769ee52b7fc5c718df4182618b96 Mon Sep 17 00:00:00 2001 From: Matt Van Horn Date: Sun, 28 Jun 2026 13:30:04 -0700 Subject: [PATCH] docs: document manual Wrangler deploy path for Cloudflare self-hosting (#44) Fixes #27 Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> --- docs/SELF_HOSTING_CLOUDFLARE.md | 133 +++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/docs/SELF_HOSTING_CLOUDFLARE.md b/docs/SELF_HOSTING_CLOUDFLARE.md index e4f8001..a699eb4 100644 --- a/docs/SELF_HOSTING_CLOUDFLARE.md +++ b/docs/SELF_HOSTING_CLOUDFLARE.md @@ -2,10 +2,11 @@ This guide covers: -1. Initial setup after clicking Deploy to Cloudflare -2. How to update to the latest OpenSEO version -3. How to add teammates -4. How to connect the OpenSEO MCP server through Cloudflare Access +1. [Initial setup after clicking Deploy to Cloudflare](#initial-setup) +2. [Manual deploy with Wrangler](#manual-deploy-with-wrangler) +3. [How to connect the OpenSEO MCP server through Cloudflare Access](#connect-the-mcp-server-through-cloudflare-access) +4. [How to update to the latest OpenSEO version](#how-to-update-to-the-latest-openseo-version) +5. [How to add teammates](#give-teammates-access-to-openseo) ## Initial setup @@ -20,6 +21,8 @@ Click the deploy button, there are lots of fields on the deploy form, but you on 3. Click `Create and Deploy`. 4. Wait 1-2 minutes for deployment to finish. +If deploy fails with `Cannot provision a KV Namespace with the title "open-seo" because it already exists`, use the [manual deploy with Wrangler](#manual-deploy-with-wrangler) flow instead. + ### 2) Configure authentication and secrets In the Cloudflare dashboard: @@ -53,6 +56,128 @@ Without a lifecycle rule, cached objects under `dataforseo-cache/` will accumula If login fails, re-check the three secrets and Access toggle. +## Manual deploy with Wrangler + +Use this flow if the Deploy to Cloudflare button fails with `Cannot provision a KV Namespace with the title "open-seo" because it already exists`. The reliable path is to create Cloudflare resources yourself, put their IDs into `wrangler.jsonc`, then deploy with Wrangler. + +### 1) Clone your OpenSEO repo + +Fork `every-app/open-seo` on GitHub if you want a repo you control for future updates, then clone it locally: + +```bash +git clone https://github.com/YOUR_GITHUB_USER/open-seo.git +cd open-seo +corepack enable +pnpm install +``` + +If you do not need a fork, clone the upstream repo instead: + +```bash +git clone https://github.com/every-app/open-seo.git +cd open-seo +corepack enable +pnpm install +``` + +### 2) Log in to Cloudflare + +```bash +pnpm exec wrangler login +``` + +### 3) Create Cloudflare resources + +Use unique names so they do not collide with resources that already exist in your Cloudflare account. Replace `YOUR_SUFFIX` with something unique to you, for example your GitHub username or company name. + +```bash +pnpm exec wrangler kv namespace create open-seo-YOUR_SUFFIX +pnpm exec wrangler kv namespace create open-seo-oauth-YOUR_SUFFIX +pnpm exec wrangler d1 create open-seo-YOUR_SUFFIX +pnpm exec wrangler r2 bucket create open-seo-YOUR_SUFFIX +``` + +Save the IDs and names printed by Wrangler: + +- The first KV namespace ID is for the `KV` binding. +- The second KV namespace ID is for the `OAUTH_KV` binding. +- The D1 `database_id` is for the `DB` binding. +- The R2 bucket name is for the `R2` binding. + +### 4) Edit `wrangler.jsonc` + +Open `wrangler.jsonc` and replace only your Cloudflare resource values. Keep the binding names exactly as shown below, because the application code expects those names. + +```jsonc +"kv_namespaces": [ + { + "binding": "KV", + "id": "YOUR_KV_NAMESPACE_ID", + }, + { + "binding": "OAUTH_KV", + "id": "YOUR_OAUTH_KV_NAMESPACE_ID", + }, +], +"d1_databases": [ + { + "binding": "DB", + "database_name": "open-seo-YOUR_SUFFIX", + "database_id": "YOUR_D1_DATABASE_ID", + "migrations_dir": "drizzle", + }, +], +"r2_buckets": [ + { + "bucket_name": "open-seo-YOUR_SUFFIX", + "binding": "R2", + }, +], +``` + +Do not use `wrangler deploy --update-config` for this step. Edit `wrangler.jsonc` manually so `"migrations_dir": "drizzle"` stays in the D1 database config. + +### 5) Deploy + +```bash +pnpm run deploy +``` + +### 6) Configure authentication and secrets + +In the Cloudflare dashboard: + +1. Go to `Compute` -> `Workers & Pages` -> your OpenSEO Worker. +2. Open `Settings`. +3. In `Domains & Routes`, enable `Cloudflare Access` for the `workers.dev` route. +4. Save the values shown by Cloudflare Access. + +Then set the same values as Worker secrets with Wrangler: + +```bash +pnpm exec wrangler secret put TEAM_DOMAIN +pnpm exec wrangler secret put POLICY_AUD +pnpm exec wrangler secret put DATAFORSEO_API_KEY +``` + +Use the domain from `JWKS_URL` for `TEAM_DOMAIN`, for example `https://your-team.cloudflareaccess.com`. Use the Access application audience value for `POLICY_AUD`. + +### 7) Optional: add an R2 lifecycle rule + +DataForSEO API responses are cached in R2 under the `dataforseo-cache/` prefix. This step is optional, but recommended to automatically clean up expired cache objects: + +```bash +pnpm exec wrangler r2 bucket lifecycle add open-seo-YOUR_SUFFIX dataforseo-cache-expiry dataforseo-cache/ --expire-days 7 +``` + +### 8) Validate setup + +1. Open your Worker URL again. +2. Sign in with Cloudflare Access. +3. OpenSEO should load after login. + +If login fails, re-check the three secrets, the Access toggle, and the binding values in `wrangler.jsonc`. + ## Connect the MCP server through Cloudflare Access Use the same Cloudflare Access application that protects your OpenSEO Worker.