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 proxycloudflare_access: For Cloudflare Workers with JWT validation (requiresTEAM_DOMAINandPOLICY_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:
- Generate migration files after schema changes:
pnpm run db:generate - Apply migrations locally:
pnpm run db:migrate:local - 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:
- Configure
AUTH_MODE=cloudflare_access - Set
TEAM_DOMAINandPOLICY_AUDfor Cloudflare Access JWT validation - Deploy via the
wranglerCLI - Use the
portlesslocal 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
.envfiles or real API keys to version control - Keeping
local_noauthmode 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:passwordstring for theDATAFORSEO_API_KEYvariable. - Lock dependencies: Use
corepack enableandpnpm install --frozen-lockfileto ensure reproducible builds. - Run migrations: Execute
pnpm run db:migrate:localbefore 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=postgresfor advanced requirements. - Secure deployments: Use
AUTH_MODE=local_noauthonly behind reverse proxies, and pin Docker images to specific tags. - Disable telemetry: Set
OPENSEO_TELEMETRY_DISABLED=1for privacy-compliant environments. - Validate locally: Run
pnpm ci:checkandpnpm test:cibefore 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →