How to Self-Host OpenSEO on Cloudflare Workers: Complete Deployment Guide

You can self-host OpenSEO entirely on Cloudflare's edge platform by creating a .env.selfhost configuration, running the pre-flight validation script, and deploying with pnpm deploy:selfhost --yes to create a Worker with KV storage and built-in Access authentication.

OpenSEO by every-app/open-seo is designed to run as a Cloudflare Worker, leveraging edge computing for SEO analysis. This guide walks you through the exact steps to deploy your own instance using the repository's built-in self-hosting toolchain.

Prepare Your Environment Configuration

Begin by creating your environment file from the provided template. Copy /.env.selfhost.example to .env.selfhost and configure the required variables:

  • TEAM_DOMAIN: Your Cloudflare Access domain (e.g., https://your-team.cloudflareaccess.com)
  • POLICY_AUD: The Access application audience ID for auto-provisioning
  • DATAFORSEO_API_KEY: Required for third-party SEO data services
  • ACCESS_ALLOWED_EMAILS: Comma-separated list of collaborator emails

To disable telemetry reporting, set either OPENSEO_TELEMETRY_DISABLED=1 or DO_NOT_TRACK=1 in your environment file.

Validate Configuration with Pre-Flight Checks

Before deploying, run the validation script located at scripts/selfhost-preflight.ts. This script performs critical checks:

  • Validates the TEAM_DOMAIN format using the regex in src/shared/selfhost-checks.ts
  • Verifies Cloudflare Access domain reachability
  • Confirms required secrets like DATAFORSEO_API_KEY are present

The pre-flight check aborts early if misconfigurations are detected, preventing failed deployments. The validation logic ensures your domain matches the pattern ^https?:\/\/.+\.cloudflareaccess\.com$ as implemented in src/shared/selfhost-checks.ts:

export function validateTeamDomain(input: string) {
  const trimmed = input.trim();
  if (!/^https?:\/\/.+\.cloudflareaccess\.com$/.test(trimmed)) {
    return { ok: false, error: "add the https:// prefix to ..." };
  }
  return { ok: true, origin: trimmed };
}

Deploy the Worker Stack

Execute the deployment command from the repository root:

pnpm install
pnpm deploy:selfhost --yes

This command triggers the Vite build process configured in vite.config.ts, which uses the Cloudflare Vite plugin to bundle your TypeScript into a single Worker:

import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";

export default defineConfig({
  plugins: [
    cloudflare({
      inspectorPort: false,
      viteEnvironment: { name: "ssr" },
    }),
  ],
});

The deployment automatically provisions:

  • A Workers AI model binding via @cloudflare
  • A Workers KV namespace for persisting user data
  • A Cloudflare Access application with an "Allow" policy (if TEAM_DOMAIN is provided)

The Worker entry point at src/start.ts initializes the application:

import { env } from "cloudflare:workers";
import { initApp } from "./app";

export default {
  async fetch(request, env) {
    const app = initApp(env);
    return app.handle(request);
  },
};

Post-Deployment Access Configuration

After deployment, complete the authentication setup:

  1. Add collaborators to the Access policy via ACCESS_ALLOWED_EMAILS in .env.selfhost
  2. If you opted out of auto-provisioning, manually configure your Cloudflare Access application in the dashboard
  3. Test the deployment by visiting https://<your-worker>.workers.dev/api/heartbeat

The middleware in src/middleware/ensure-user/cloudflareAccess.ts enforces Access authentication on protected routes.

Why Cloudflare Workers?

Edge Execution places SEO crawling and analysis jobs geographically close to target sites, reducing latency. Built-in KV & AI provides serverless storage via Workers KV and AI-assisted features through Workers AI without external servers. Zero-Ops Scaling allows the Worker to automatically handle traffic spikes during intensive crawling or rank-checking workloads.

Common Pitfalls and Troubleshooting

Issue Symptom Fix
Access login failures Users cannot authenticate via Cloudflare Access Verify emails are listed in ACCESS_ALLOWED_EMAILS or check manual Access policy configuration
Missing API keys DataForSEO returns 401 errors Ensure DATAFORSEO_API_KEY is defined in .env.selfhost; the pre-flight script flags missing keys
Telemetry enabled Logs show telemetry transmission Set OPENSEO_TELEMETRY_DISABLED=1 or DO_NOT_TRACK=1 and redeploy

Summary

  • Create .env.selfhost from the example template, setting TEAM_DOMAIN and required API keys
  • Run scripts/selfhost-preflight.ts to validate your Cloudflare Access configuration before deploying
  • Deploy using pnpm deploy:selfhost --yes, which bundles via Vite and provisions KV and AI bindings
  • Manage collaborator access through ACCESS_ALLOWED_EMAILS or the Cloudflare dashboard
  • Disable telemetry with OPENSEO_TELEMETRY_DISABLED=1 if desired

Frequently Asked Questions

What environment variables are required to self-host OpenSEO on Cloudflare Workers?

You must configure TEAM_DOMAIN for Cloudflare Access integration, DATAFORSEO_API_KEY for SEO data services, and ACCESS_ALLOWED_EMAILS for user authentication. The /.env.selfhost.example file provides the complete template with optional variables like POLICY_AUD for automatic Access application provisioning.

How does the pre-flight check validate my Cloudflare Access configuration?

The script scripts/selfhost-preflight.ts imports validateTeamDomain from src/shared/selfhost-checks.ts to verify your TEAM_DOMAIN matches the required Cloudflare Access URL pattern. It also checks domain reachability and confirms all required secrets are present in your .env.selfhost file.

Can I disable telemetry when self-hosting OpenSEO?

Yes. Set OPENSEO_TELEMETRY_DISABLED=1 or DO_NOT_TRACK=1 in your .env.selfhost file before deploying. The telemetry logic in src/server/lib/self-host-telemetry.ts checks these variables and skips reporting when either flag is enabled.

How do I update my OpenSEO Worker after changing environment variables?

Simply rerun pnpm deploy:selfhost --yes from the repository root. The deployment script detects the selfhost stage and applies updated configuration values from .env.selfhost to your Cloudflare Worker.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →