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_ID
  • GSC_CLIENT_SECRET
  • GSC_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 .env file based on .env.example
  • Validation: npm run selfhost-preflight executes scripts/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.ts instead of raw process.env
  • Telemetry control: Set OPENSEO_TELEMETRY_DISABLED=1 or DO_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:

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 →