Open SEO Configuration Options: Complete Guide to Environment Variables and Deployment Settings

Open SEO runtime behavior is controlled entirely through environment variables read at startup, with 15+ configuration options spanning authentication modes, database backends, external APIs, and telemetry settings.

All Open SEO settings live in environment variables that are validated at startup by the runtime helper in src/server/lib/runtime-env.ts. This self-hosted SEO analytics platform supports Cloudflare Workers, Docker, and traditional server deployments—each requiring different configuration combinations. Below is the authoritative breakdown of every major setting, its source file, and how to use it.

Authentication Mode Configuration

The AUTH_MODE variable is the single most important setting—it determines how Open SEO handles all user authentication.

AUTH_MODE

Available in src/lib/auth-mode.ts, this enum controls the entire auth strategy:

Value Use Case User Identity
cloudflare_access (default) Cloudflare Access protected deployments Derived from Cloudflare Access JWT
local_noauth Trusted local development or Docker Fixed admin user admin@localhost
hosted Self-hosted with email/password login Better Auth managed users

# For local Docker development

AUTH_MODE=local_noauth

# For production Cloudflare Workers

AUTH_MODE=cloudflare_access

# For self-hosted with user management

AUTH_MODE=hosted

Cloudflare Access Settings (cloudflare_access mode)

When using Cloudflare Access, two additional variables are required in src/lib/auth.ts:

  • TEAM_DOMAIN — Your Cloudflare Access organization URL (e.g., https://myteam.cloudflareaccess.com)
  • POLICY_AUD — The audience tag from your Cloudflare Access application configuration

Both values are used to verify incoming JWT signatures against the correct Access organization.

Better Auth Settings (hosted mode)

For email/password authentication, Open SEO integrates with Better Auth. Configure these in src/lib/auth.ts:

  • BETTER_AUTH_URL — URL of your Better Auth service (e.g., https://auth.your-domain.com)
  • BETTER_AUTH_SECRET — Random secret generated on first start, used to sign JWTs

Without these, hosted mode will fail validation during scripts/selfhost-preflight.ts checks.

Database Configuration Options

Open SEO supports two database backends, selected implicitly by which connection variables you provide.

Cloudflare D1 (Default for Workers)

Defined in drizzle-prod.config.ts, these three variables enable Cloudflare's serverless database:

  • CLOUDFLARE_ACCOUNT_ID — Hex string from Cloudflare dashboard
  • CLOUDFLARE_API_TOKEN — API token with D1 edit permissions
  • CLOUDFLARE_DATABASE_ID — UUID of your D1 database instance

# Cloudflare dashboard → Workers → Settings → Variables

CLOUDFLARE_ACCOUNT_ID=your_account_id_here
CLOUDFLARE_API_TOKEN=your_token_here
CLOUDFLARE_DATABASE_ID=your_database_uuid_here

PostgreSQL (Docker or Self-Hosted)

For traditional deployments, drizzle-pg.config.ts accepts a standard connection string:

  • POSTGRES_DATABASE_URL — Full PostgreSQL URI: postgresql://user:pass@host:port/database

This is the recommended approach when running Open SEO in Docker Compose or on a VM with managed Postgres.

External API Integrations

DataForSEO (DATAFORSEO_API_KEY)

Located in docs/DATAFORSEO_API_KEY.md, this enables keyword research, backlink analysis, and site audit features. The value must be Base64-encoded email:password:


# Generate from your DataForSEO account credentials

DATAFORSEO_API_KEY=$(echo -n "your@email.com:yourpassword" | base64)

Without this variable, all DataForSEO-backed endpoints return 503 Service Unavailable.

Cloudflare Turnstile (TURNSTILE_SITE_KEY)

Set in src/lib/auth-turnstile.ts, this enables bot protection on sign-up and login pages. Required when AUTH_MODE=hosted and you want to prevent automated registration.

Telemetry and Analytics Configuration

Self-Host Telemetry Control

Two variables in scripts/selfhost-preflight.ts control usage reporting:

  • OPENSEO_TELEMETRY_DISABLED=true — Explicit opt-out
  • DO_NOT_TRACK=true — Alternative opt-out (honored if first variable unset)

When neither is set, Open SEO sends lightweight usage statistics to help the development team prioritize features.

PostHog Analytics (POSTHOG_HOST, POSTHOG_PUBLIC_KEY)

Configured in src/lib/selfhost-telemetry.ts, these route product analytics to your own PostHog instance instead of the default telemetry endpoint:

POSTHOG_HOST=https://ph.yourcompany.com
POSTHOG_PUBLIC_KEY=phc_your_public_key_here

Server and Site Configuration

Development Server (PORT)

In vite.config.ts, this sets the listening port for local development and Docker containers:

PORT=3000  # default

Site URL (VITE_SITE_URL / SITE_URL)

Used by web/src/lib/seo.ts for sitemap generation and SEO utilities. Should match the URL you're auditing:

VITE_SITE_URL=https://example.com

Note: Both variable names are accepted; VITE_SITE_URL takes precedence for Vite environments.

Configuration Loading and Validation

Open SEO uses a runtime helper in src/server/lib/runtime-env.ts that mirrors the Cloudflare Workers binding API:

export function getOptionalEnvValue(name: keyof Cloudflare.Env) {
  return typeof process !== "undefined"
    ? process.env?.[name]
    : undefined;
}

All variables are typed in worker-configuration.d.ts. During startup, scripts/selfhost-preflight.ts validates:

  1. AUTH_MODE is a valid enum value
  2. Required variables for the selected auth mode are present
  3. Database connection variables match exactly one backend (D1 XOR Postgres)

Failure produces a clear error message naming the missing variable.

Deployment Scenario Reference

Scenario Key Variables File Template
Docker local dev AUTH_MODE=local_noauth, POSTGRES_DATABASE_URL, PORT .env.local
Cloudflare Workers AUTH_MODE=cloudflare_access, TEAM_DOMAIN, POLICY_AUD, D1 variables Dashboard bindings
Hosted SaaS AUTH_MODE=hosted, BETTER_AUTH_URL, BETTER_AUTH_SECRET Generated by platform
Self-hosted Postgres AUTH_MODE=hosted, POSTGRES_DATABASE_URL, optional Turnstile, PostHog .env.production

Docker Quick Start


# .env.local

AUTH_MODE=local_noauth
DATAFORSEO_API_KEY=$(echo -n "email:password" | base64)
POSTGRES_DATABASE_URL=postgresql://postgres:postgres@db:5432/openseo
PORT=3000
OPENSEO_TELEMETRY_DISABLED=true
docker compose up -d

Cloudflare Workers Quick Start

In the Cloudflare dashboard, set these as Worker variables (not secrets, unless marked):

Variable Type Value
AUTH_MODE Plain cloudflare_access
TEAM_DOMAIN Plain https://yourteam.cloudflareaccess.com
POLICY_AUD Plain your-access-app-audience-tag
DATAFORSEO_API_KEY Secret base64-encoded credentials
CLOUDFLARE_ACCOUNT_ID Plain from dashboard
CLOUDFLARE_API_TOKEN Secret with D1:edit permission
CLOUDFLARE_DATABASE_ID Plain D1 database UUID

Key Source Files for Configuration

Summary

  • Authentication is mode-driven: Choose cloudflare_access, local_noauth, or hosted via AUTH_MODE, then supply the corresponding variables defined in src/lib/auth.ts
  • Database backend is implicit: Provide D1 variables for Cloudflare Workers, or POSTGRES_DATABASE_URL for Docker/VM deployments
  • External features require keys: DATAFORSEO_API_KEY unlocks SEO analysis; TURNSTILE_SITE_KEY adds bot protection
  • Validation happens at startup: The selfhost-preflight.ts script ensures configurations are complete before the service starts
  • Telemetry is opt-out: Set OPENSEO_TELEMETRY_DISABLED=true or DO_NOT_TRACK=true to disable usage reporting

Frequently Asked Questions

What happens if I don't set AUTH_MODE?

Open SEO defaults to cloudflare_access, which will fail to validate requests unless TEAM_DOMAIN and POLICY_AUD are also configured. For local development, explicitly set AUTH_MODE=local_noauth to bypass authentication entirely.

Can I use PostgreSQL with Cloudflare Workers?

No. Cloudflare Workers only support D1 (Cloudflare's native serverless database) due to platform constraints. PostgreSQL is exclusively for Docker or self-hosted VM deployments where Node.js has direct network access to the database server.

How do I generate the DATAFORSEO_API_KEY format?

Run echo -n "your@email.com:yourpassword" | base64 in any terminal. The -n flag is critical—without it, the newline character corrupts the encoding. The resulting string is what you set as the environment variable value.

Why does my self-hosted deployment fail with "Missing required variables"?

The scripts/selfhost-preflight.ts validation runs before the server starts and checks that your AUTH_MODE selection has all required dependencies. Common fixes: add BETTER_AUTH_URL and BETTER_AUTH_SECRET for hosted mode, or confirm TEAM_DOMAIN and POLICY_AUD for cloudflare_access mode.

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 →