# Technical Requirements for Self-Hosting OpenSEO on Cloudflare Workers

> Learn the technical requirements to self-host OpenSEO on Cloudflare Workers. You'll need Node.js, pnpm, Cloudflare R2, DataForSEO API key, and a configured .env file.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-08-15

---

**To self-host OpenSEO on Cloudflare Workers, you need Node.js 22.6 or newer, pnpm, a Cloudflare account with R2 enabled, a DataForSEO API key, and a configured `.env.selfhost` file containing allowed user emails and external service credentials.**

The `every-app/open-seo` repository deploys as a Cloudflare Worker using a serverless edge architecture that relies on Cloudflare-native storage and external SEO data providers. Successfully self-hosting requires specific runtime versions, API accounts, and environment variables that are validated during the deployment process. This guide details the exact technical prerequisites, resource bindings, and configuration steps defined in the source documentation and `wrangler.jsonc`.

## Prerequisites and Runtime Dependencies

Before deploying, your local environment must meet the following specifications:

- **Node.js 22.6 or newer** — The [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) explicitly declares `"engines": { "node": ">=22.6" }` for build-time compatibility.
- **pnpm package manager** — Install via `corepack enable`. The deployment scripts in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) (such as `pnpm deploy:selfhost`) depend on pnpm.
- **Cloudflare account with R2 enabled** — You must have a Cloudflare account with **R2** object storage activated. According to [`docs/SELF_HOSTING_CLOUDFLARE.md`](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_CLOUDFLARE.md), a payment method is required on file even for the free tier to enable R2.

## External Service Accounts

Self-hosting OpenSEO requires active accounts with the following third-party providers:

- **DataForSEO account** — Required for SEO data APIs. You must generate an API key and reference it as `DATAFORSEO_API_KEY` in your environment file, as documented in [`docs/DATAFORSEO_API_KEY.md`](https://github.com/every-app/open-seo/blob/main/docs/DATAFORSEO_API_KEY.md).
- **Alchemy CLI** — Used for bootstrapping the state-store Worker and managing infrastructure. You will run `pnpm alchemy login` to authenticate with the `access:write` OAuth scope before deploying.

## Environment Configuration and Required Variables

Create a `.env.selfhost` file by copying `.env.selfhost.example`. At minimum, the file must define:

- `ACCESS_ALLOWED_EMAILS` — A comma-separated list of email addresses permitted to access the application through Cloudflare Access.
- `DATAFORSEO_API_KEY` — Your DataForSEO API credentials.

Optional variables include:
- `TEAM_DOMAIN` and `POLICY_AUD` — For customizing Cloudflare Access policies.
- `OPENSEO_TELEMETRY_DISABLED=1` — Set this to disable anonymized usage telemetry, as noted in [`docs/SELF_HOSTING_CLOUDFLARE_OPERATIONS.md`](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_CLOUDFLARE_OPERATIONS.md).

## Cloudflare Resources and Architecture

The OpenSEO Worker binds to several Cloudflare resources defined in `wrangler.jsonc`. During deployment via `pnpm deploy:selfhost`, the Alchemy CLI automatically provisions:

- **D1 database** — A SQLite-compatible database (binding `d1_databases`) for application state.
- **KV namespaces** — Two separate namespaces: `KV` for general caching and `OAUTH_KV` for OAuth state management.
- **R2 bucket** — An `open-seo` bucket for static assets and file storage.

The Worker entry point is [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts), configured as the `main` handler in `wrangler.jsonc`. Database migrations located in [`drizzle.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle.config.ts) and the `drizzle/` directory target the D1 instance.

## Deployment Workflow

Execute the following commands in sequence to provision resources and deploy the Worker:

```bash

# Clone and prepare the repository

git clone https://github.com/every-app/open-seo.git
cd open-seo
corepack enable
pnpm install

# Authenticate with Cloudflare (required once)

pnpm alchemy login
pnpm alchemy cloudflare bootstrap

# Configure environment variables

cp .env.selfhost.example .env.selfhost

# Edit .env.selfhost to set:

#   ACCESS_ALLOWED_EMAILS="admin@example.com"

#   DATAFORSEO_API_KEY="your-api-key"

# Deploy the self-host stage

pnpm deploy:selfhost --yes

```

The `deploy:selfhost` command creates D1 tables, provisions KV and R2 bindings, runs database migrations, and configures a Cloudflare Access application to gate entry.

To update an existing deployment after pulling new code:

```bash
git pull
pnpm install
pnpm deploy:selfhost --yes

```

To completely remove the deployment and clean up resources:

```bash
pnpm alchemy destroy --env-file .env.selfhost --stage selfhost

```

## Post-Deployment Operations

After initial deployment, you may need to configure additional access controls and monitoring.

### Telemetry Management

By default, OpenSEO transmits anonymized usage telemetry. To opt out, set `OPENSEO_TELEMETRY_DISABLED=1` in `.env.selfhost` and redeploy.

### MCP Client Access

To enable Managed Client Protocol (MCP) clients, you must turn on **Managed OAuth** within the Cloudflare Access application settings. Details are provided in [`docs/SELF_HOSTING_CLOUDFLARE_OPERATIONS.md`](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_CLOUDFLARE_OPERATIONS.md).

## Summary

- **Node.js 22.6+** and **pnpm** are required local dependencies.
- A **Cloudflare account with R2 enabled** and a **DataForSEO API key** are mandatory external requirements.
- The `.env.selfhost` file must define `ACCESS_ALLOWED_EMAILS` and `DATAFORSEO_API_KEY` at minimum.
- Cloudflare resources (D1, KV, R2) are automatically provisioned by the Alchemy CLI during `pnpm deploy:selfhost`.
- The Worker entry point is [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts), with database migrations managed via [`drizzle.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle.config.ts).
- Telemetry can be disabled via environment variable, and MCP access requires additional Cloudflare Access configuration.

## Frequently Asked Questions

### Can I self-host OpenSEO without a DataForSEO account?

No. The application depends on DataForSEO for search engine ranking and keyword data. Without a valid `DATAFORSEO_API_KEY` defined in `.env.selfhost`, the Worker cannot fetch SEO metrics, causing functionality to fail.

### What Cloudflare plan is required for self-hosting OpenSEO?

The free tier is sufficient, but you must add a payment method to your Cloudflare account to activate **R2** storage. The deployment uses R2 for static assets, D1 for the database, and KV for caching, all of which operate within free tier limits for low-to-moderate traffic.

### How do I update my self-hosted OpenSEO deployment?

Pull the latest changes from the `every-app/open-seo` repository, run `pnpm install` to update dependencies, and execute `pnpm deploy:selfhost --yes` to apply changes. The Alchemy CLI will update the Worker and run any pending database migrations without destroying existing data.

### Where is application data persisted in a Cloudflare Workers environment?

Data persists in **Cloudflare D1** (a SQLite-compatible edge database) for structured data, **R2** for static files and assets, and **KV** for session caching and OAuth state. These bindings are defined in `wrangler.jsonc` and injected into the Worker at runtime.