Docker vs Cloudflare Deployment for OpenSEO: 7 Key Differences Explained
Docker and Cloudflare deployments differ fundamentally in execution environment, data storage, authentication model, and operational responsibility—Docker runs locally with SQLite and no built-in auth, while Cloudflare runs on the edge with D1/KV/R2 storage and Cloudflare Access authentication.
OpenSEO, the open‑source SEO intelligence platform from every-app/open-seo, supports two primary self‑hosting strategies. While both run identical application code, the deployment method you choose determines your infrastructure footprint, security model, and maintenance workflow. This guide breaks down the technical distinctions between Docker and Cloudflare deployments based on the actual source implementation.
Execution Environment: Container vs Edge Worker
The most fundamental difference lies in where your code runs.
Docker deployment executes inside a container on infrastructure you control. As defined in Dockerfile.selfhost, the image bundles the Node.js runtime and launches the app via docker compose. The service binds to a local port (default 3001) and remains isolated to your host network.
Cloudflare deployment compiles the same source into a V8 isolate that runs on Cloudflare's edge network. The Worker is distributed globally, with requests routed to the nearest point of presence. No persistent server process exists—each request spins up a fresh execution context.
This architectural split affects cold-start latency, geographic reach, and resource scaling without configuration changes.
Provisioning Workflow: Manual vs Automated
Docker requires minimal setup but manual orchestration.
# Docker: pull and run
cp .env.example .env
# edit .env with DATAFORSEO_API_KEY, etc.
docker compose up -d
Cloudflare deployment automates infrastructure provisioning through Alchemy, the infrastructure-as-code toolkit used by OpenSEO.
# Cloudflare: single-command provisioning
pnpm install
pnpm alchemy login
pnpm alchemy cloudflare bootstrap
pnpm deploy:selfhost --yes
The pnpm deploy:selfhost --yes command, documented in docs/SELF_HOSTING_CLOUDFLARE.md, creates:
- A D1 database for relational data
- KV namespaces for key‑value caching
- An R2 bucket for object storage
- A Cloudflare Access application for authentication
No equivalent automation exists for Docker—you manage storage volumes, networking, and auth integration yourself.
Data Persistence: Local SQLite vs Managed Cloud Services
| Storage Layer | Docker | Cloudflare |
|---|---|---|
| Primary database | Local SQLite file (sqlite.db) |
Cloudflare D1 (SQLite‑compatible) |
| Caching | In‑memory or local Redis (manual setup) | Native KV namespaces |
| Object storage | Local filesystem or self‑hosted MinIO | Cloudflare R2 |
| Backup/restore | Manual file operations | D1 snapshots via CLI/API |
In Docker, the SQLite database lives inside the container filesystem. Data persists across restarts only if you mount a volume—docker compose down without volume preservation destroys all data.
Cloudflare D1 provides managed replication, automated backups, and point‑in‑time recovery. When you run pnpm alchemy destroy, D1 databases, KV stores, and R2 buckets are permanently deleted, making environment lifecycle management explicit and reversible.
Authentication Model: Disabled by Default vs Cloudflare Access
Security posture diverges sharply between the two approaches.
Docker ships with authentication disabled (AUTH_MODE=local_noauth). The .env.example template sets this explicitly, assuming you'll place the container behind a corporate VPN, reverse proxy with basic auth, or Tailscale tunnel. No identity provider integration exists in the default configuration.
Cloudflare deployment mandates authentication through Cloudflare Access. The ACCESS_ALLOWED_EMAILS environment variable defines an allowlist of email addresses that can reach the Worker. Unauthorized requests are intercepted at Cloudflare's network edge before reaching your code, with customizable login methods (one‑time PIN, SAML, OIDC) configurable in the Zero‑Trust dashboard.
This represents a shift from application‑layer auth to network‑layer identity, reducing your attack surface but adding vendor dependency.
Networking and Exposure: Internal vs Global
Docker exposes a single TCP port bound to localhost or your host's network interface. Reachability requires additional infrastructure:
- Port forwarding for external access
- Reverse proxy (Nginx, Caddy, Traefik) for TLS termination
- VPN or tunnel (Cloudflare Tunnel, ngrok) for secure remote access
Cloudflare Workers receive a public HTTPS URL immediately—https://<worker>.workers.dev by default, or your custom domain. Cloudflare handles TLS certificate provisioning, HTTP/2 and HTTP/3 termination, DDoS protection, and edge caching without configuration.
For teams needing rapid external sharing or client demonstrations, Cloudflare eliminates days of networking setup.
Operational Responsibilities: You vs The Platform
| Responsibility | Docker | Cloudflare |
|---|---|---|
| Runtime patching | You manage base image updates | Cloudflare manages V8 isolate |
| Database maintenance | Vacuum, backup, migration scripts | Automated by D1 |
| Scaling | Vertical (bigger host) or orchestrator (K8s) | Automatic to zero and unlimited |
| Uptime monitoring | Self‑implemented health checks | Cloudflare status dashboard |
| Log aggregation | Local stdout/file or external Loki | Cloudflare Logs/Analytics |
Docker maximizes control—you own the entire stack from kernel to application. Cloudflare trades control for operational simplicity, abstracting away infrastructure concerns common to small teams.
Update and Teardown Workflows
Docker updates require image management:
# Update Docker deployment
docker compose pull # fetch latest ghcr.io/every-app/open-seo:latest
docker compose up -d # recreate containers
Data persists in mounted volumes unless explicitly pruned.
Cloudflare updates re‑provision infrastructure in place:
# Update Cloudflare deployment
git pull origin main
pnpm deploy:selfhost --yes
Schema migrations run automatically against D1.
Complete removal differs dramatically:
# Docker: stop containers, preserve volumes by default
docker compose down
# Cloudflare: destroy all cloud resources and data
pnpm alchemy destroy --env-file .env.selfhost --stage selfhost
The Alchemy destroy command, referenced in docs/SELF_HOSTING_CLOUDFLARE.md, provides clean environment teardown that Docker lacks by design.
Cost Model: Local Resources vs Cloud Tier
Docker incurs no cloud service charges—only your underlying hardware costs (electricity, amortized server purchase, or VPS rental). The ghcr.io/every-app/open-seo:latest image pulls are free.
Cloudflare operates on a generous free tier: D1, KV, and R2 include substantial monthly allowances. Costs emerge only at scale or when using paid features like advanced Access policies. You also pay separately for the DataForSEO API key, required for both deployment modes.
For personal use or small teams, both approaches are effectively free. For production workloads, Cloudflare's pricing becomes predictable whereas Docker costs scale with your infrastructure management overhead.
Summary
- Execution: Docker runs containers locally; Cloudflare runs V8 isolates on the global edge
- Provisioning: Docker requires manual
docker composesetup; Cloudflare automates D1/KV/R2/Access creation viapnpm deploy:selfhost --yes - Storage: Docker uses local SQLite; Cloudflare uses managed D1 with KV and R2
- Authentication: Docker disables auth by default; Cloudflare enforces Access‑based identity
- Networking: Docker needs manual proxy/VPN configuration; Cloudflare provides instant HTTPS endpoints
- Operations: Docker demands full infrastructure ownership; Cloudflare abstracts runtime management
- Teardown: Docker preserves data by default; Cloudflare's
alchemy destroypermanently removes all resources
Choose Docker when you need air‑gapped environments, custom networking, or existing container infrastructure. Choose Cloudflare when you prioritize rapid global deployment, zero infrastructure maintenance, and built‑in security gating.
Frequently Asked Questions
Can I switch from Docker to Cloudflare without losing data?
No direct migration path exists in the current OpenSEO codebase. Your SQLite database from Docker cannot be automatically imported into Cloudflare D1. You would need to export data manually and re‑import via D1's SQL API or restart data collection after switching deployment modes. Plan your choice based on long‑term storage needs.
Does Cloudflare deployment work without a Cloudflare account?
No. The pnpm alchemy login command authenticates against Cloudflare's API, and pnpm alchemy cloudflare bootstrap requires account credentials to provision D1, KV, R2, and Access resources. The entire Cloudflare workflow is tied to their platform infrastructure; there is no hybrid or portable equivalent.
Is Docker deployment suitable for production use?
Docker can serve production traffic but requires additional engineering effort. You must implement: TLS termination (via reverse proxy), authentication (via external IdP or proxy), backup procedures for the SQLite file, and monitoring/alerting. The OpenSEO documentation explicitly notes that Docker's AUTH_MODE=local_noauth is intended for local development unless augmented with external security controls.
What happens to my data when I destroy a Cloudflare deployment?
Running pnpm alchemy destroy --env-file .env.selfhost --stage selfhost permanently deletes the Cloudflare Worker, D1 database, KV namespaces, R2 bucket, and Access application. All stored SEO data, cached results, and uploaded assets are irreversibly removed. OpenSEO provides no built‑in backup mechanism—export D1 data manually via the Cloudflare CLI if preservation is required.
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 →