# How to Deploy OpenSEO on Cloudflare Workers and Manage D1 Database Backups

> Deploy OpenSEO to Cloudflare Workers and manage D1 database backups using the deploy button. Configure secrets, set up R2 buckets, and implement D1 export workflows for data protection.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-06-26

---

**Deploy OpenSEO by using the Cloudflare "Deploy to Workers" button to provision a Worker, D1 database, and R2 bucket, then configure required secrets and protect your data with D1 export workflows before running maintenance operations.**

OpenSEO is an open-source SEO analysis platform designed to run entirely on Cloudflare's edge infrastructure. Deploying OpenSEO on Cloudflare Workers involves binding serverless functions to a D1 SQLite database and R2 object storage, while proper database backup management ensures data integrity during schema migrations and content cleanup. This guide covers the complete deployment architecture and backup procedures implemented in the `every-app/open-seo` repository.

## Initial Deployment Architecture

OpenSEO deploys as a Cloudflare Worker with two critical infrastructure dependencies: a D1 database named `open-seo` for relational data and an R2 bucket named `open-seo` for static assets and caching.

### One-Click Worker Deployment

The fastest method to deploy OpenSEO uses Cloudflare's deploy button, which automatically creates all required resources. According to [`docs/SELF_HOSTING_CLOUDFLARE.md`](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_CLOUDFLARE.md), this process provisions:

- A new Cloudflare Worker project
- A D1 database (`open-seo`) for SQLite storage
- An R2 bucket (`open-seo`) for the DataForSEO cache and static files

After initial deployment, the `wrangler.jsonc` configuration file contains auto-generated resource IDs for your zone, D1 database, and R2 bucket. When updating your deployment, you must preserve this file: back up the current `wrangler.jsonc`, pull upstream changes, then restore your configuration before committing.

### Required Secrets Configuration

Secure your deployment by adding three mandatory secrets through the Cloudflare dashboard (Workers & Pages → your Worker → Settings → Variables & Secrets):

- **`POLICY_AUD`** and **`TEAM_DOMAIN`**: Enable Cloudflare Access authentication, restricting the dashboard to your organization's identity provider
- **`DATAFORSEO_API_KEY`**: Authenticates requests to the external SEO data provider API

## Database Backup Strategy for OpenSEO D1

Because OpenSEO uses Cloudflare D1 (a managed SQLite database), backups are essential before any destructive database operations, such as running the default-project cleanup script.

### Manual D1 Export Procedures

Before executing maintenance commands, create a backup using the Wrangler CLI:

```bash

# Export D1 database to JSON format

wrangler d1 export open-seo > backup-$(date +%F).json

```

The [`docs/default-project-cleanup.md`](https://github.com/every-app/open-seo/blob/main/docs/default-project-cleanup.md) file explicitly recommends taking a D1 backup or creating a "time-travel restore point" via the Cloudflare dashboard before applying changes.

### Pre-Cleanup Safety Checks

The cleanup command includes built-in safety mechanisms. When running:

```bash
pnpm cleanup:default-projects:d1 --database open-seo --apply --confirm-remote-apply

```

The script automatically checks for a recent D1 backup and aborts if none is detected. Always run a dry run first to preview affected rows:

```bash
pnpm cleanup:default-projects:d1 --database open-seo

```

### Automated Backup Workflows

The `wrangler.jsonc` file already declares a cron trigger running every 15 minutes (`*/15 * * * *`). You can extend this to automate backups by adding a script that exports the D1 database and stores the result in R2:

```javascript
// Add to wrangler.jsonc triggers configuration
"triggers": {
  "crons": ["*/15 * * * *"]
}

```

For automated long-term retention, schedule a command that pipes `wrangler d1 export` output directly to your R2 backup bucket.

## R2 Storage Lifecycle Management

OpenSEO caches DataForSEO API responses under the `dataforseo-cache/` prefix in R2. Without lifecycle rules, this cache grows indefinitely.

Configure automatic expiration to delete cached responses older than 7 days:

```bash
npx wrangler r2 bucket lifecycle add open-seo dataforseo-cache-expiry \
  --prefix dataforseo-cache/ \
  --expire-days 7

```

This rule prevents unbounded storage growth while maintaining recent cache hits for performance.

## Key Configuration Files

Understanding these source files helps troubleshoot deployment and backup issues:

- **`wrangler.jsonc`**: Defines Worker bindings (D1, R2), cron triggers, and resource IDs located at the repository root
- **[`drizzle.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle.config.ts)**: Configures the Drizzle ORM for D1 migrations used during deployment
- **[`scripts/cleanup-default-projects.sql`](https://github.com/every-app/open-seo/blob/main/scripts/cleanup-default-projects.sql)**: Contains the SQL executed by the cleanup command; review this before running destructive operations
- **[`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts)**: Worker entry point that initializes D1 and R2 connections using the `env` bindings defined in `wrangler.jsonc`

## Summary

Deploying OpenSEO on Cloudflare Workers requires provisioning three components: a Worker instance, a D1 database, and an R2 bucket. Key operational practices include:

- Preserving `wrangler.jsonc` resource IDs during updates to maintain infrastructure bindings
- Configuring `POLICY_AUD`, `TEAM_DOMAIN`, and `DATAFORSEO_API_KEY` secrets for security and API access
- Always exporting D1 backups before running `cleanup:default-projects:d1` with the `--apply` flag
- Implementing R2 lifecycle rules to automatically purge cached SEO data older than 7 days
- Utilizing the existing 15-minute cron trigger in `wrangler.jsonc` for automated backup scheduling

## Frequently Asked Questions

### What infrastructure does OpenSEO require on Cloudflare?

OpenSEO requires three Cloudflare resources: a Worker (compute), a D1 database named `open-seo` (SQLite storage), and an R2 bucket named `open-seo` (object storage). The "Deploy to Cloudflare" button creates these automatically, as documented in [`docs/SELF_HOSTING_CLOUDFLARE.md`](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_CLOUDFLARE.md).

### How do I back up the OpenSEO database before maintenance?

Export your D1 database using `wrangler d1 export open-seo > backup-$(date +%F).json` before any destructive operations. The cleanup script enforces this by checking for recent backups before allowing `--confirm-remote-apply` execution.

### Why does the R2 bucket need lifecycle configuration?

OpenSEO caches DataForSEO API responses under the `dataforseo-cache/` prefix. Without lifecycle rules, storage costs grow indefinitely. Configure a 7-day expiration rule to automatically remove stale cache entries while preserving recent data.

### How do I update OpenSEO without losing my configuration?

When pulling updates from the `every-app/open-seo` repository, copy your existing `wrangler.jsonc` to a temporary location first. After merging upstream changes, restore your original `wrangler.jsonc` to preserve your D1 database ID, R2 bucket ID, and other Cloudflare resource bindings.