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

> Master Open-SEO best practices for optimal configuration security and deployment. Learn to secure credentials enable reproducible builds and manage deployments effectively for every-app/open-seo.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: best-practices
- Published: 2026-08-02

---

**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](https://github.com/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](https://github.com/every-app/open-seo/blob/main/docs/LOCAL_DEVELOPMENT.md#L24-L33) documentation, you must store credentials as a **Base64-encoded string** rather than plain text.

Encode your login and password using:

```bash
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`](https://github.com/every-app/open-seo/blob/main/package.json):

```bash
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:

```bash
pnpm run db:migrate:local

```

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

```bash
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`](https://github.com/every-app/open-seo/blob/main/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:

```bash
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](https://github.com/every-app/open-seo/blob/main/docs/LOCAL_DEVELOPMENT.md#L52-L64) 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`](https://github.com/every-app/open-seo/blob/main/compose.yaml) with the official GitHub Container Registry image:

```bash
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](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_DOCKER.md#L46-L50).

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](https://github.com/every-app/open-seo/blob/main/docs/CONTRIBUTING.md#L19-L27), run:

```bash
pnpm ci:check && pnpm test:ci

```

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

```bash
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`](https://github.com/every-app/open-seo/blob/main/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.