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-provisioningDATAFORSEO_API_KEY: Required for third-party SEO data servicesACCESS_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_DOMAINformat using the regex insrc/shared/selfhost-checks.ts - Verifies Cloudflare Access domain reachability
- Confirms required secrets like
DATAFORSEO_API_KEYare 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_DOMAINis 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:
- Add collaborators to the Access policy via
ACCESS_ALLOWED_EMAILSin.env.selfhost - If you opted out of auto-provisioning, manually configure your Cloudflare Access application in the dashboard
- 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.selfhostfrom the example template, settingTEAM_DOMAINand required API keys - Run
scripts/selfhost-preflight.tsto 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_EMAILSor the Cloudflare dashboard - Disable telemetry with
OPENSEO_TELEMETRY_DISABLED=1if 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →