How to Configure Open-SEO Settings: A Complete Self-Hosting Guide
Configure Open-SEO by creating a .env file based on .env.example, then run npm run selfhost-preflight to validate required environment variables like DATAFORSEO_API_KEY, POSTGRES_DATABASE_URL, and Cloudflare credentials before deployment.
Open-SEO is a self-hosted SaaS-style SEO platform maintained by every-app. Understanding how to configure Open-SEO settings properly ensures your instance connects to external data providers, databases, and authentication services without runtime failures.
Environment Variable Architecture
Open-SEO centralizes configuration through a runtime-env abstraction layer. The src/server/lib/runtime-env.ts module standardizes access to environment variables across deployment targets, whether you're running locally, in Docker, or on Cloudflare Workers.
The scripts/selfhost-preflight.ts script validates every required variable at startup. This pre-flight check catches missing or malformed configuration before the application boots, preventing cryptic runtime errors.
Required Environment Variables
All configuration lives in a single .env file. Copy .env.example from the repository root as your starting template.
DataForSEO Integration
The DATAFORSEO_API_KEY variable powers rank tracking and backlink analysis features. Without this key, Open-SEO cannot fetch search engine data.
DATAFORSEO_API_KEY=your-dataforseo-api-key
The src/serverFunctions/config.ts endpoint exposes whether this integration is active:
// From src/serverFunctions/config.ts
export const dataforseoConfigured = Boolean(
env.DATAFORSEO_API_KEY?.trim()
);
Database Connection
Open-SEO requires PostgreSQL for data persistence. The drift-SQL layer consumes POSTGRES_DATABASE_URL in drizzle-pg.config.ts:
POSTGRES_DATABASE_URL=postgresql://user:password@host:5432/openseo
Cloudflare Workers Deployment
When deploying to Cloudflare, three additional variables enable D1 database and KV storage access:
| Variable | Purpose |
|---|---|
CLOUDFLARE_ACCOUNT_ID |
Identifies your Cloudflare account |
CLOUDFLARE_API_TOKEN |
API token with Workers and D1 permissions |
CLOUDFLARE_DATABASE_ID |
Specific D1 database identifier |
These are consumed by drizzle-prod.config.ts and wrangler.toml during production builds.
Optional Authentication
Better-Auth integration is controlled by two variables read in src/lib/auth.ts:
BETTER_AUTH_URL=https://auth.yourdomain.com
BETTER_AUTH_SECRET=your-256-bit-secret
Telemetry Opt-Out
Disable usage analytics by setting either flag documented in SELF_HOSTING_CLOUDFLARE_OPERATIONS.md:
OPENSEO_TELEMETRY_DISABLED=1
# Alternative:
DO_NOT_TRACK=1
The isTelemetryOptOutValue helper in scripts/selfhost-preflight.ts handles both variants.
Complete Configuration Example
# Required: External data services
DATAFORSEO_API_KEY=dfseo_live_abc123xyz
# Required: Database
POSTGRES_DATABASE_URL=postgresql://openseo:securepass@db:5432/openseo
# Required only for Cloudflare deployment
CLOUDFLARE_ACCOUNT_ID=1a2b3c4d5e6f
CLOUDFLARE_API_TOKEN=your_cloudflare_api_token
CLOUDFLARE_DATABASE_ID=uuid-of-your-d1-database
# Optional: Authentication
BETTER_AUTH_URL=https://auth.internal.company.com
BETTER_AUTH_SECRET=generated-secret-from-better-auth-cli
# Optional: Privacy
OPENSEO_TELEMETRY_DISABLED=1
Validating Your Configuration
Run the pre-flight validation before starting Open-SEO:
npm run selfhost-preflight
This executes scripts/selfhost-preflight.ts, which checks:
- Presence of required variables
- Non-empty string values
- Telemetry flag interpretation
On validation failure, you'll receive specific guidance:
✖ Open-SEO configuration error: POSTGRES_DATABASE_URL is not set
✖ Open-SEO configuration error: DATAFORSEO_API_KEY appears malformed
Success output confirms readiness for deployment.
Docker Deployment
The docker-compose.yaml demonstrates production-grade configuration injection:
services:
open-seo:
image: ghcr.io/every-app/open-seo:latest
env_file: .env
environment:
- NODE_ENV=production
ports:
- "3000:3000"
depends_on:
- postgres
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: openseo
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: openseo
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
The env_file: .env directive mounts your configuration directly into the container runtime where src/server/lib/runtime-env.ts can access it.
Google Search Console Integration
Additional variables enable GSC data syncing. See docs/SELF_HOSTING_GOOGLE_SEARCH_CONSOLE.md for obtaining and configuring:
GSC_CLIENT_IDGSC_CLIENT_SECRETGSC_REFRESH_TOKEN
These follow the same .env pattern and are validated by the pre-flight script.
Runtime Environment Access
Within application code, always use the typed env object rather than direct process.env access:
import { env } from "@/server/lib/runtime-env";
export function checkDataSources() {
return {
dataforseo: Boolean(env.DATAFORSEO_API_KEY?.trim()),
gsc: Boolean(env.GSC_REFRESH_TOKEN?.trim()),
cloudflare: Boolean(
env.CLOUDFLARE_ACCOUNT_ID &&
env.CLOUDFLARE_API_TOKEN &&
env.CLOUDFLARE_DATABASE_ID
)
};
}
This abstraction ensures compatibility across Node.js and Cloudflare Workers runtimes.
Summary
- Configuration source: Single
.envfile based on.env.example - Validation:
npm run selfhost-preflightexecutesscripts/selfhost-preflight.ts - Required variables:
DATAFORSEO_API_KEY,POSTGRES_DATABASE_URL - Cloudflare variables:
CLOUDFLARE_ACCOUNT_ID,CLOUDFLARE_API_TOKEN,CLOUDFLARE_DATABASE_ID - Access pattern: Use
src/server/lib/runtime-env.tsinstead of rawprocess.env - Telemetry control: Set
OPENSEO_TELEMETRY_DISABLED=1orDO_NOT_TRACK=1
Frequently Asked Questions
What happens if I skip the pre-flight check?
Open-SEO may start with undefined configuration, causing runtime failures when features attempt to connect to DataForSEO or PostgreSQL. The src/server/lib/runtime-env.ts module will return undefined for missing keys, and subsequent API calls will fail with authentication or connection errors. Always run npm run selfhost-preflight before deployment.
Can I use different environment files for different stages?
Yes. Specify an alternative file with ENV_FILE=.env.production or reference it directly in docker-compose.yaml. The runtime-env module reads whatever environment is injected at runtime; the file name itself has no special meaning to Open-SEO.
How do I rotate secrets without downtime?
Update your .env file, then restart containers or redeploy Workers. Open-SEO reads configuration once at startup, so changes require a process restart. For zero-downtime rotations in Kubernetes or Docker Swarm, use rolling deployments that incrementally replace containers with new environment state.
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 →