Open-SEO Best Practices: Configuration, Security, and Deployment Guide

To maximize performance and security when using Open-SEO, encode DataForSEO credentials as Base64, use Corepack with pnpm for reproducible builds, select the appropriate AUTH_MODE for your deployment target, and always run database migrations before starting the development server.

Open-SEO is a modern, self-hostable SEO platform built by the every-app/open-seo repository using TypeScript, TanStack Router, and Drizzle ORM. Whether you are running it locally for development or deploying to Docker or Cloudflare Workers, following these architectural guidelines ensures secure credential handling, consistent database migrations, and optimal developer experience.

Secure Environment Configuration

Proper environment setup is the foundation of Open-SEO security and functionality. The repository provides an .env.example file that you must copy to .env.local (for development) or .env (for Docker).

DataForSEO API Credentials

The platform integrates with DataForSEO for search data. According to the LOCAL_DEVELOPMENT.md documentation, you must store credentials as a Base64-encoded string rather than plain text.

Encode your login and password using:

printf '%s' 'your_login:your_password' | base64

Place the resulting string in your environment file as DATAFORSEO_API_KEY. This prevents accidental credential leakage in logs or process lists.

Authentication Mode Selection

Open-SEO supports three AUTH_MODE values defined in the environment configuration:

  • local_noauth: For local development or Docker deployments behind a reverse proxy
  • cloudflare_access: For Cloudflare Workers with JWT validation (requires TEAM_DOMAIN and POLICY_AUD)
  • hosted: For Better Auth integration

Never use local_noauth in production without an external authentication layer or network-level protection.

Local Development Workflow

A reproducible development environment prevents "works on my machine" issues and ensures compatibility with the CI pipeline.

Dependency Management with Corepack

The project requires pnpm as the package manager. Enable Corepack to use the exact version specified in package.json:

corepack enable
pnpm install --frozen-lockfile

Using --frozen-lockfile guarantees that all developers install identical dependency versions, matching the production build environment.

Database Initialization and Dev Server

Before starting the application, initialize the database schema using Drizzle migrations:

pnpm run db:migrate:local

Start the development server with agent-friendly logging on the portless domain:

mkdir -p .logs && touch .logs/dev-server.log
pnpm dev:agents

This serves the application at http://open-seo.localhost:1355, avoiding port collisions when using multiple git worktrees.

Database Provider Selection

Open-SEO abstracts database access through src/db/index.ts (lines 9-19), automatically selecting between Cloudflare D1 (SQLite) and Postgres based on the DATABASE_PROVIDER environment variable.

  • Cloudflare D1: The default zero-config option ideal for self-hosting on Cloudflare's free tier
  • Postgres: Opt-in for production workloads requiring advanced SQL features or larger scale

To switch to Postgres locally:

export DATABASE_PROVIDER=postgres
export DATABASE_URL=postgresql://user:pass@localhost:5432/openseo
pnpm run db:generate
pnpm run db:migrate:local

Migration Management

Schema changes must be handled through Drizzle's migration system to maintain parity across environments. The workflow documented in LOCAL_DEVELOPMENT.md recommends:

  1. Generate migration files after schema changes: pnpm run db:generate
  2. Apply migrations locally: pnpm run db:migrate:local
  3. Verify the Drizzle schema parity test passes before committing

Production deployments use the same migration scripts, ensuring consistency between local development and deployed instances.

Deployment Strategies

Open-SEO supports two primary self-hosting architectures: containerized Docker deployments and serverless Cloudflare Workers.

Docker Self-Hosting

For quick local or CI deployments, use the provided compose.yaml with the official GitHub Container Registry image:

cp .env.example .env

# Edit .env to set DATAFORSEO_API_KEY and AUTH_MODE=local_noauth

# Pin to specific version for reproducibility

echo "OPEN_SEO_IMAGE=ghcr.io/every-app/open-seo:v1.2.3" >> .env

docker compose up -d

When using AUTH_MODE=local_noauth in Docker, always place the container behind a reverse proxy or secure tunnel. Pinning to a specific image tag rather than latest prevents unexpected updates in production.

Cloudflare Workers

For globally distributed edge deployment with zero-cost scaling:

  1. Configure AUTH_MODE=cloudflare_access
  2. Set TEAM_DOMAIN and POLICY_AUD for Cloudflare Access JWT validation
  3. Deploy via the wrangler CLI
  4. Use the portless local development URL (http://open-seo.localhost:1355) to mirror the production environment

Security and Privacy Controls

Beyond credential encoding, Open-SEO provides telemetry controls for regulated environments. Set OPENSEO_TELEMETRY_DISABLED=1 (or DO_NOT_TRACK=1) to disable anonymous usage reporting, as documented in SELF_HOSTING_DOCKER.md.

Additional security hygiene includes:

  • Never committing .env files or real API keys to version control
  • Keeping local_noauth mode restricted to protected networks
  • Regularly updating pinned Docker image tags for security patches

AI Agent Integration

Open-SEO exposes a Machine Control Protocol (MCP) server at /api/mcp that allows AI agents (such as Claude or OpenClaw) to query SEO data programmatically. Enable this by ensuring MCP_ENABLED is set to true (the default in development).

This integration supports automated workflows like keyword research and rank tracking. Refer to the MCP documentation at /docs/mcp for endpoint registration details.

Testing and CI Compliance

Before submitting pull requests, mirror the CI pipeline locally to catch errors early. According to CONTRIBUTING.md, run:

pnpm ci:check && pnpm test:ci

For UI changes within the web/ directory, also execute:

pnpm --dir web install && pnpm --dir web run build

This validates linting, type checking, and build processes against the same criteria used in automated CI checks.

Summary

  • Encode credentials: Always Base64-encode the DataForSEO login:password string for the DATAFORSEO_API_KEY variable.
  • Lock dependencies: Use corepack enable and pnpm install --frozen-lockfile to ensure reproducible builds.
  • Run migrations: Execute pnpm run db:migrate:local before starting the dev server to sync the database schema.
  • Choose the right database: Default to Cloudflare D1 for simplicity; switch to Postgres via DATABASE_PROVIDER=postgres for advanced requirements.
  • Secure deployments: Use AUTH_MODE=local_noauth only behind reverse proxies, and pin Docker images to specific tags.
  • Disable telemetry: Set OPENSEO_TELEMETRY_DISABLED=1 for privacy-compliant environments.
  • Validate locally: Run pnpm ci:check and pnpm test:ci before submitting changes to match CI standards.

Frequently Asked Questions

How do I securely store DataForSEO credentials in Open-SEO?

Store your DataForSEO credentials as a Base64-encoded string in the DATAFORSEO_API_KEY environment variable. Concatenate your login and password with a colon (login:password), then encode using printf '%s' 'credentials' | base64. This prevents plain-text exposure in environment files and process listings.

What is the difference between local_noauth and cloudflare_access modes?

local_noauth disables internal authentication, suitable for local development or Docker containers behind a reverse proxy. cloudflare_access enables JWT validation against Cloudflare Access, requiring TEAM_DOMAIN and POLICY_AUD variables for production deployments on Cloudflare Workers. Never expose local_noauth instances to public networks without external protection.

Can I switch from SQLite (D1) to Postgres after starting development?

Yes. Update the DATABASE_PROVIDER environment variable to postgres and set a valid DATABASE_URL. Regenerate migrations with pnpm run db:generate and apply them using pnpm run db:migrate:local. The provider abstraction in src/db/index.ts handles the connection logic automatically, though you will need to migrate existing data manually.

How do I enable AI agents to interact with my Open-SEO instance?

Enable the MCP server by ensuring MCP_ENABLED=true in your environment (enabled by default in development). AI agents can then connect to the /api/mcp endpoint to execute SEO queries programmatically. This supports automated workflows like bulk keyword analysis and rank tracking through compatible AI systems.

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 →