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 dashboardCLOUDFLARE_API_TOKEN— API token with D1 edit permissionsCLOUDFLARE_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-outDO_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:
AUTH_MODEis a valid enum value- Required variables for the selected auth mode are present
- 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
worker-configuration.d.ts— CompleteCloudflare.Envinterface definitionsrc/lib/auth-mode.ts—AUTH_MODEenum and validation logicscripts/selfhost-preflight.ts— Startup validation that catches missing variablesdrizzle-prod.config.ts/drizzle-pg.config.ts— Database backend configurationsdocs/SELF_HOSTING_DOCKER.md— Recommended Docker defaultsdocs/LOCAL_DEVELOPMENT.md— Local development configuration guide
Summary
- Authentication is mode-driven: Choose
cloudflare_access,local_noauth, orhostedviaAUTH_MODE, then supply the corresponding variables defined insrc/lib/auth.ts - Database backend is implicit: Provide D1 variables for Cloudflare Workers, or
POSTGRES_DATABASE_URLfor Docker/VM deployments - External features require keys:
DATAFORSEO_API_KEYunlocks SEO analysis;TURNSTILE_SITE_KEYadds bot protection - Validation happens at startup: The
selfhost-preflight.tsscript ensures configurations are complete before the service starts - Telemetry is opt-out: Set
OPENSEO_TELEMETRY_DISABLED=trueorDO_NOT_TRACK=trueto 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →