Simplify README and organize docs (#400)
This commit is contained in:
parent
6ad65f59e1
commit
072fbecae3
@ -10,6 +10,7 @@ data, or sensitive paths.
|
||||
|
||||
## Open
|
||||
|
||||
- [ ] `2026-07-19T02:55:56Z` — `claude` — Adding a docs folder under `web/content/docs` whose `meta.json` lists an `[Overview](...)` link renders a duplicated, double-highlighted sidebar entry, because the folder-index strip in `web/src/lib/source.ts` (`transformPageTree.folder`) is a per-folder-name allowlist. Derive it from the meta convention (or strip the index for all folders) so new sections don't need a hidden source.ts edit.
|
||||
- [ ] `2026-07-14T01:28:30Z` — `claude` — Regenerating the lockfile (adding or moving a dep) makes `pnpm install` re-run the `minimumReleaseAge` gate on transitive peers already pinned at that exact version (`mysql2`, `sql-escaper`, `@aws-sdk/credential-providers`), failing the install even though nothing about them changed. `pnpm install --config.minimumReleaseAge=0` — then confirm the lockfile diff stays version-neutral — unblocks it; worth documenting that regen step so the gate doesn't re-block already-pinned versions.
|
||||
- [ ] `2026-07-10T21:28:46Z` — `codex` — `pnpm --dir badseo run typecheck` works through the root toolchain but `pnpm --dir badseo run build` can't find Vite because `badseo/node_modules` is absent. Document or enforce the package-local install before validating the `badseo/` subpackage.
|
||||
- [ ] `2026-07-10T21:32:10Z` — `codex` — Formatting the `badseo/` workspace with `pnpm exec prettier` fails because Prettier is only available from the repository root. Document the root-only formatter command or expose a workspace-local formatting script.
|
||||
|
||||
226
README.md
226
README.md
@ -10,27 +10,9 @@ Connect with any agent like Claude Code, OpenClaw or Hermes. We have pre-built s
|
||||
|
||||
<img width="1385" height="794" alt="Image" src="https://github.com/user-attachments/assets/fd208249-44ea-4849-bb4b-5fc896aeab73" />
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Why use OpenSEO?](#why-use-openseo)
|
||||
- [Main SEO Workflows](#main-seo-workflows)
|
||||
- [OpenSEO MCP](#openseo-mcp)
|
||||
- [OpenSEO Agent Skills](#openseo-agent-skills)
|
||||
- [Roadmap](#roadmap)
|
||||
- [Community](#community)
|
||||
- [Pricing / Costs (Free + API costs)](#pricing--costs)
|
||||
- [DataForSEO API Key Setup](#dataforseo-api-key-setup)
|
||||
- [Google Search Console](#google-search-console)
|
||||
- [Self-hosting](#self-hosting)
|
||||
- [Docker Self Hosting](#docker-self-hosting)
|
||||
- [Cloudflare Self-Hosting](#cloudflare-self-hosting)
|
||||
- [Local Development](#local-development)
|
||||
- [Contributing](#contributing)
|
||||
- [SEO API Cost Reference](#seo-api-cost-reference)
|
||||
|
||||
## Hosted Version
|
||||
|
||||
If you're not interested in self hosting, or just want to support the project, we also have a hosted version:
|
||||
Try OpenSEO for free on our website. If you want to support the project, a hosted subscription is $10/month.
|
||||
|
||||
[openseo.so](https://openseo.so)
|
||||
|
||||
@ -52,6 +34,38 @@ If you're not interested in self hosting, or just want to support the project, w
|
||||
- Site Audits
|
||||
- AI Visibility
|
||||
|
||||
## OpenSEO MCP & Agent Skills
|
||||
|
||||
OpenSEO exposes an MCP server so AI agents like Claude Code, OpenClaw, and Hermes can use your SEO data directly. Agent Skills are reusable workflows that guide your agent through SEO tasks using the MCP.
|
||||
|
||||
- [Set up OpenSEO MCP](https://openseo.so/docs/mcp)
|
||||
- [Set up OpenSEO Agent Skills](https://openseo.so/docs/skills/setup)
|
||||
|
||||
## Self-Hosting
|
||||
|
||||
OpenSEO supports two self-hosting paths:
|
||||
|
||||
- **Simple: Docker** for personal use on your own machine (recommended for getting started). See [`docs/SELF_HOSTING_DOCKER.md`](./docs/SELF_HOSTING_DOCKER.md).
|
||||
- **Advanced: Cloudflare** for internet-facing self-hosting across multiple devices or with your team (works on the free plan). See [`docs/SELF_HOSTING_CLOUDFLARE.md`](./docs/SELF_HOSTING_CLOUDFLARE.md).
|
||||
|
||||
Either way, you need a DataForSEO API key to get SEO data. See [`docs/DATAFORSEO_API_KEY.md`](./docs/DATAFORSEO_API_KEY.md).
|
||||
|
||||
## Costs
|
||||
|
||||
OpenSEO needs a [DataForSEO](https://dataforseo.com/?aff=255379) API key so that you can get SEO data. You pay them directly when self hosting.
|
||||
|
||||
See [openseo.so/pricing](https://openseo.so/pricing)
|
||||
|
||||
When you self host, your costs will be slightly lower than the estimates on our website. The way the hosted service makes money is by charging 28% extra for every request we make to DataForSEO.
|
||||
|
||||
## Local Development
|
||||
|
||||
See [`docs/LOCAL_DEVELOPMENT.md`](./docs/LOCAL_DEVELOPMENT.md).
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are very welcome. See [`docs/CONTRIBUTING.md`](./docs/CONTRIBUTING.md).
|
||||
|
||||
## Community
|
||||
|
||||
Join Discord to chat: [Discord](https://discord.gg/c9uGs3cFXr)
|
||||
@ -60,177 +74,3 @@ Follow along for updates:
|
||||
|
||||
- Follow on X: https://x.com/bensenescu
|
||||
- Sign up for the mailing list on our website: [openseo.so](https://openseo.so)
|
||||
|
||||
## OpenSEO MCP
|
||||
|
||||
OpenSEO exposes an MCP server so AI agents can use your SEO data directly.
|
||||
|
||||
Connect Claude Code, OpenClaw, Hermes or any other agent.
|
||||
|
||||
### Setup
|
||||
|
||||
- Set up the app
|
||||
- Click "AI & Agents" in the header
|
||||
- Follow the instructions to connect to your agent
|
||||
|
||||
## OpenSEO Agent Skills
|
||||
|
||||
OpenSEO Agent Skills are reusable workflows for your agent
|
||||
|
||||
They guide your agent through SEO tasks and use the OpenSEO MCP so your agent makes better recommendations.
|
||||
|
||||
### Available Skills
|
||||
|
||||
- `seo-project-setup`
|
||||
- `seo-coach`
|
||||
- `keyword-research`
|
||||
- `keyword-clustering`
|
||||
- `competitive-landscape`
|
||||
- `competitor-analysis`
|
||||
- `link-prospecting`
|
||||
|
||||
### Installation Guide
|
||||
|
||||
Read our docs for how to install the skills:
|
||||
|
||||
https://openseo.so/docs/skills/setup
|
||||
|
||||
## Roadmap
|
||||
|
||||
Top priorities:
|
||||
|
||||
- Improved and Scheduled Site Audits
|
||||
- Custom Reports for Clients
|
||||
- Local SEO
|
||||
- In App AI Agent
|
||||
|
||||
Our top priority is always refining the current product and making existing features better based on user feedback.
|
||||
|
||||
If something important is missing, please join the [Discord](https://discord.gg/c9uGs3cFXr) or email me at ben@openseo.so and request it.
|
||||
|
||||
## Pricing / Costs
|
||||
|
||||
OpenSEO is totally free to use. It works by using DataForSEO's APIs, which is a paid third-party service unaffiliated with OpenSEO.
|
||||
|
||||
There are two separate things:
|
||||
|
||||
1. OpenSEO app cost: $0, you host it yourself.
|
||||
2. DataForSEO API: pay-as-you-go based on usage.
|
||||
|
||||
For cost estimates, see [DataForSEO API Cost Reference](#seo-api-cost-reference).
|
||||
|
||||
## DataForSEO API Key Setup
|
||||
|
||||
OpenSEO uses DataForSEO to fetch SEO data. You need an API key to connect OpenSEO to the service.
|
||||
|
||||
1. Go to [DataForSEO API Access](https://app.dataforseo.com/api-access?aff=255379).
|
||||
2. Click "Send by email" to get set your credentials.
|
||||
3. Copy the longer crendentials labelled "Base64" credentials.
|
||||
4. Set this as `DATAFORSEO_API_KEY` in your environment file:
|
||||
|
||||
- Docker self-hosting: `.env`
|
||||
- Cloudflare: Set it in the workers UI
|
||||
- Local development: `.env.local`
|
||||
|
||||
## Google Search Console
|
||||
|
||||
Search Console is optional and works in self-hosted deployments using your own
|
||||
Google OAuth client. It takes ~10 minutes of one-time setup — see
|
||||
[`docs/SELF_HOSTING_GOOGLE_SEARCH_CONSOLE.md`](./docs/SELF_HOSTING_GOOGLE_SEARCH_CONSOLE.md).
|
||||
|
||||
## AI Features (SAM)
|
||||
|
||||
AI features like SAM, the in-app SEO agent, are optional — set the `OPENROUTER_API_KEY` environment variable to enable them (create a key at [openrouter.ai/settings/keys](https://openrouter.ai/settings/keys)).
|
||||
|
||||
## Self-hosting
|
||||
|
||||
OpenSEO supports two self-hosting paths:
|
||||
|
||||
- Docker for personal use and testing (Recommended for local use).
|
||||
- Cloudflare for internet-facing self-hosting across multiple devices or for your team.
|
||||
|
||||
_Docker_
|
||||
|
||||
Docker is recommended for getting started. It's super easy to get up and running once you install Docker.
|
||||
|
||||
_Cloudflare_
|
||||
|
||||
If you love OpenSEO and want to use it across multiple devices or with your team, you can host it on Cloudflare which we'll be a SaaS-like experience. Also, this will have automatic database backups and other nice convenience features. It's just a bit more effort to get started if you're unfamiliar with Cloudflare.
|
||||
|
||||
## Docker Self Hosting
|
||||
|
||||
> [!WARNING]
|
||||
> By default, the Docker version is intended for local use only. It runs in single-user mode with no authentication. For internet-facing self-hosting, use Cloudflare (free plan compatible). Or read [`docs/SELF_HOSTING_DOCKER.md`](./docs/SELF_HOSTING_DOCKER.md) before exposing to the internet.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- Install Docker: https://www.docker.com/products/docker-desktop/
|
||||
|
||||
Quickstart:
|
||||
|
||||
1. `cp .env.example .env`
|
||||
2. Set `DATAFORSEO_API_KEY` in `.env`
|
||||
3. `docker compose up -d`
|
||||
4. Open `http://localhost:<PORT>` (default `3001`)
|
||||
|
||||
To update to the newest published image, pull first and then restart:
|
||||
|
||||
```sh
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
For more info, see [`docs/SELF_HOSTING_DOCKER.md`](./docs/SELF_HOSTING_DOCKER.md).
|
||||
|
||||
## Cloudflare Self-Hosting
|
||||
|
||||
### Deploy the Worker
|
||||
|
||||
Clicking this button opens a page to deploy OpenSEO in your Cloudflare account. If you do not have an account yet, it will take you to account creation first (OpenSEO works great on the free plan).
|
||||
|
||||
Reference these docs while deploying since the Cloudflare UI doesn't indicate what steps you need to take: [`docs/SELF_HOSTING_CLOUDFLARE.md`](./docs/SELF_HOSTING_CLOUDFLARE.md).
|
||||
|
||||
[](https://deploy.workers.cloudflare.com/?url=https://github.com/every-app/open-seo)
|
||||
|
||||
## Local Development
|
||||
|
||||
See [`docs/LOCAL_DEVELOPMENT.md`](./docs/LOCAL_DEVELOPMENT.md).
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are very welcome.
|
||||
|
||||
- Open an issue for bugs, UX friction, or feature requests.
|
||||
- Open a PR if you want to implement a feature directly.
|
||||
- Community-driven improvements are prioritized, and high-quality PRs are encouraged.
|
||||
|
||||
If you want to contribute but are unsure where to start, open an issue and describe what you want to build.
|
||||
|
||||
## SEO API Cost Reference
|
||||
|
||||
Use this section to estimate DataForSEO spend per request type. OpenSEO itself remains free; these are API usage costs only.
|
||||
|
||||
As of February 26, 2026, DataForSEO’s public docs/pricing pages say:
|
||||
|
||||
- New accounts include **$1 free credit** to test the API.
|
||||
- The minimum top-up/payment is **$50**.
|
||||
|
||||
That means you can try OpenSEO for free with the starter credit, then decide if/when to top up.
|
||||
|
||||
### Planning examples
|
||||
|
||||
- Track 100 keywords weekly at depth 50: `~$1.20/month`
|
||||
- 100 keyword research requests at the default 150 results: `$3.50`
|
||||
- 100 keyword research requests at 500 results each: `$7.00`
|
||||
- 100 domain overviews (200 ranked keywords each): `$4.01`
|
||||
- 100 backlinks domain searches at current defaults before opening extra tabs: about `$6.34`
|
||||
- 100 backlinks page searches at current defaults before opening extra tabs: about `$4.30`
|
||||
- 100 fully explored backlinks domain searches: about `$10.94`
|
||||
- 100 fully explored backlinks page searches: about `$8.61`
|
||||
|
||||
### Pricing sources
|
||||
|
||||
- DataForSEO SERP API pricing: https://dataforseo.com/apis/serp-api/pricing
|
||||
- DataForSEO Keywords Data API pricing: https://dataforseo.com/pricing/dataforseo-labs/dataforseo-google-api
|
||||
- DataForSEO Backlinks pricing: https://dataforseo.com/pricing/backlinks/backlinks
|
||||
- DataForSEO Lighthouse API docs: https://docs.dataforseo.com/v3/on_page/lighthouse/overview/
|
||||
|
||||
19
docs/CONTRIBUTING.md
Normal file
19
docs/CONTRIBUTING.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Contributing to OpenSEO
|
||||
|
||||
Contributions are very welcome.
|
||||
|
||||
- Open an issue for bugs, UX friction, or feature requests.
|
||||
- Open a PR if you want to implement a feature directly.
|
||||
- Community-driven improvements are prioritized, and high-quality PRs are encouraged.
|
||||
|
||||
If you want to contribute but are unsure where to start, open an issue and describe what you want to build. You can also join the [Discord](https://discord.gg/c9uGs3cFXr) to talk through ideas first.
|
||||
|
||||
## Local development
|
||||
|
||||
See [LOCAL_DEVELOPMENT.md](./LOCAL_DEVELOPMENT.md) for how to run the app locally.
|
||||
|
||||
## Guidelines
|
||||
|
||||
- Keep PRs focused: one feature or fix per PR.
|
||||
- For larger features, open an issue first so we can align on the approach before you invest time.
|
||||
- Make sure `pnpm ci:check` passes before requesting review.
|
||||
19
docs/DATAFORSEO_API_KEY.md
Normal file
19
docs/DATAFORSEO_API_KEY.md
Normal file
@ -0,0 +1,19 @@
|
||||
# DataForSEO API Key Setup
|
||||
|
||||
OpenSEO uses [DataForSEO](https://dataforseo.com/?aff=255379) to fetch SEO data. It's a pay-as-you-go third-party service unaffiliated with OpenSEO. You need an API key to connect OpenSEO to it.
|
||||
|
||||
New DataForSEO accounts include $1 of free credit to test with, and the minimum top-up is $50.
|
||||
|
||||
## Get your API key
|
||||
|
||||
1. Go to [DataForSEO API Access](https://app.dataforseo.com/api-access?aff=255379) (create an account if you don't have one).
|
||||
2. Click "Send by email" to get your credentials.
|
||||
3. Copy the longer credentials labelled "Base64" credentials. This is the base64 encoded value of your DataForSEO email and API password in the format `email:password`.
|
||||
|
||||
## Where to set it
|
||||
|
||||
Set the value as `DATAFORSEO_API_KEY`:
|
||||
|
||||
- **Docker self-hosting:** in `.env` (see [`SELF_HOSTING_DOCKER.md`](./SELF_HOSTING_DOCKER.md)).
|
||||
- **Cloudflare self-hosting:** as a Worker secret in the dashboard under `Settings` -> `Variables & Secrets`, or with `pnpm exec wrangler secret put DATAFORSEO_API_KEY` (see [`SELF_HOSTING_CLOUDFLARE.md`](./SELF_HOSTING_CLOUDFLARE.md)).
|
||||
- **Local development:** in `.env.local` (see [`LOCAL_DEVELOPMENT.md`](./LOCAL_DEVELOPMENT.md)).
|
||||
@ -1,16 +1,13 @@
|
||||
# Cloudflare Self-Hosting
|
||||
|
||||
This guide covers:
|
||||
Host OpenSEO on Cloudflare for internet-facing self-hosting across multiple devices or with your team. It works on Cloudflare's free plan.
|
||||
|
||||
1. [Initial setup after clicking Deploy to Cloudflare](#initial-setup)
|
||||
2. [Manual deploy with Wrangler](#manual-deploy-with-wrangler)
|
||||
3. [How to connect the OpenSEO MCP server through Cloudflare Access](#connect-the-mcp-server-through-cloudflare-access)
|
||||
4. [How to update to the latest OpenSEO version](#how-to-update-to-the-latest-openseo-version)
|
||||
5. [How to add teammates](#give-teammates-access-to-openseo)
|
||||
This doc covers initial setup with the Deploy to Cloudflare button. Related guides:
|
||||
|
||||
## Initial setup
|
||||
- [Manual deploy with Wrangler](./SELF_HOSTING_CLOUDFLARE_MANUAL.md): use this if the deploy button fails or you want full control over resources.
|
||||
- [Operations](./SELF_HOSTING_CLOUDFLARE_OPERATIONS.md): connect the MCP server, update to the latest version, add teammates, telemetry.
|
||||
|
||||
### 1) Deploy from GitHub
|
||||
## 1) Deploy from GitHub
|
||||
|
||||
[](https://deploy.workers.cloudflare.com/?url=https://github.com/every-app/open-seo)
|
||||
|
||||
@ -21,9 +18,9 @@ Click the deploy button, there are lots of fields on the deploy form, but you on
|
||||
3. Click `Create and Deploy`.
|
||||
4. Wait 1-2 minutes for deployment to finish.
|
||||
|
||||
If deploy fails with `Cannot provision a KV Namespace with the title "open-seo" because it already exists`, use the [manual deploy with Wrangler](#manual-deploy-with-wrangler) flow instead.
|
||||
If deploy fails with `Cannot provision a KV Namespace with the title "open-seo" because it already exists`, use the [manual deploy with Wrangler](./SELF_HOSTING_CLOUDFLARE_MANUAL.md) flow instead.
|
||||
|
||||
### 2) Configure authentication and secrets
|
||||
## 2) Configure authentication and secrets
|
||||
|
||||
In the Cloudflare dashboard:
|
||||
|
||||
@ -34,9 +31,9 @@ In the Cloudflare dashboard:
|
||||
5. In `Variables & Secrets`, add:
|
||||
- `POLICY_AUD` (from Access setup)
|
||||
- `TEAM_DOMAIN` (domain from `JWKS_URL`, for example `https://your-team.cloudflareaccess.com`)
|
||||
- `DATAFORSEO_API_KEY`
|
||||
- `DATAFORSEO_API_KEY` (see [`DATAFORSEO_API_KEY.md`](./DATAFORSEO_API_KEY.md) for how to get one)
|
||||
|
||||
### 3) Optional: add an R2 lifecycle rule
|
||||
## 3) Optional: add an R2 lifecycle rule
|
||||
|
||||
DataForSEO API responses are cached in R2 under the `dataforseo-cache/` prefix. This step is optional, but recommended to automatically clean up expired cache objects:
|
||||
|
||||
@ -48,7 +45,7 @@ If you changed the R2 bucket name during deploy, replace `open-seo` with your bu
|
||||
|
||||
Without a lifecycle rule, cached objects under `dataforseo-cache/` will accumulate indefinitely and increase storage costs over time.
|
||||
|
||||
### 4) Validate setup
|
||||
## 4) Validate setup
|
||||
|
||||
1. Open your Worker URL again.
|
||||
2. Sign in with Cloudflare Access.
|
||||
@ -56,202 +53,6 @@ Without a lifecycle rule, cached objects under `dataforseo-cache/` will accumula
|
||||
|
||||
If login fails, re-check the three secrets and Access toggle.
|
||||
|
||||
## Connect the MCP server through Cloudflare Access
|
||||
## Next steps
|
||||
|
||||
Use the same Cloudflare Access application that protects your OpenSEO Worker.
|
||||
Managed OAuth is required for MCP clients and is not enabled by default.
|
||||
|
||||
1. Open Cloudflare Zero Trust.
|
||||
2. Go to `Access controls` -> `Applications`.
|
||||
3. Find your OpenSEO application, then select `Edit`.
|
||||
4. Go to `Additional settings` -> `OAuth`.
|
||||
5. Turn on `Managed OAuth`.
|
||||
6. In `Managed OAuth settings`, allow the redirect URIs your MCP clients use:
|
||||
- Allow `localhost` / loopback clients — for CLI and desktop agents (Codex
|
||||
CLI, Claude Code) that register `http://localhost:PORT/callback`.
|
||||
- Add HTTPS redirect URIs for web connectors (a path may end in `/*`).
|
||||
- Without this, clients can't finish [Dynamic Client Registration](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/managed-oauth/)
|
||||
and log in but expose no tools.
|
||||
7. Save.
|
||||
|
||||
MCP clients should connect to:
|
||||
|
||||
```text
|
||||
https://YOUR_WORKER_HOSTNAME/mcp
|
||||
```
|
||||
|
||||
## How to update to the latest OpenSEO version
|
||||
|
||||
If your repo was created from the Cloudflare Deploy button, use this flow.
|
||||
|
||||
### One-time setup
|
||||
|
||||
Run this once in your local repo:
|
||||
|
||||
```bash
|
||||
git remote add upstream https://github.com/every-app/open-seo.git
|
||||
git fetch upstream
|
||||
```
|
||||
|
||||
### Update steps (use every time)
|
||||
|
||||
```bash
|
||||
git fetch upstream
|
||||
cp wrangler.jsonc wrangler.local.backup.jsonc
|
||||
git checkout main
|
||||
git reset --hard upstream/main
|
||||
cp wrangler.local.backup.jsonc wrangler.jsonc
|
||||
git add wrangler.jsonc
|
||||
git commit -m "restore Cloudflare settings" || true
|
||||
git push --force-with-lease origin main
|
||||
```
|
||||
|
||||
Why this is needed:
|
||||
|
||||
- `wrangler.jsonc` has your Cloudflare resource IDs.
|
||||
- The update step keeps your IDs while pulling the newest OpenSEO code.
|
||||
|
||||
## Give teammates access to OpenSEO
|
||||
|
||||
1. Open Cloudflare Zero Trust.
|
||||
2. Go to Access -> Applications.
|
||||
3. Open your OpenSEO application.
|
||||
4. Edit the `Allow` policy.
|
||||
5. Add teammate emails (or your company email domain / group).
|
||||
6. Save.
|
||||
|
||||
Screenshots from the setup flow:
|
||||
|
||||
- [Edit the Access policy](https://github.com/user-attachments/assets/c7bbc7b4-a18e-4ae4-9fe5-3b33c72048a7)
|
||||
- [Add teammate emails to the allow list](https://github.com/user-attachments/assets/fa4ecaf2-31f7-4a64-9001-210cf729747b)
|
||||
|
||||
After saving, teammates can open your OpenSEO URL and sign in through Cloudflare
|
||||
Access. OpenSEO will use a shared workspace for everyone allowed by the policy.
|
||||
|
||||
## Telemetry
|
||||
|
||||
OpenSEO collects anonymized telemetry for core usage events: heartbeats with aggregate counts (installs, users, projects, feature usage) tied to a random install ID — every 5 minutes during the first two hours after install, then at most once daily. No URLs, keywords, prompts, emails, or IP-derived location are collected, and idle installs send nothing.
|
||||
|
||||
To disable it, add `OPENSEO_TELEMETRY_DISABLED=1` (or `DO_NOT_TRACK=1`) as a Worker variable under **Settings → Variables & Secrets**, then redeploy or restart the Worker.
|
||||
|
||||
## Manual deploy with Wrangler
|
||||
|
||||
Use this flow if the Deploy to Cloudflare button fails with `Cannot provision a KV Namespace with the title "open-seo" because it already exists`. The reliable path is to create Cloudflare resources yourself, put their IDs into `wrangler.jsonc`, then deploy with Wrangler.
|
||||
|
||||
### 1) Clone your OpenSEO repo
|
||||
|
||||
Fork `every-app/open-seo` on GitHub if you want a repo you control for future updates, then clone it locally:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YOUR_GITHUB_USER/open-seo.git
|
||||
cd open-seo
|
||||
corepack enable
|
||||
pnpm install
|
||||
```
|
||||
|
||||
If you do not need a fork, clone the upstream repo instead:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/every-app/open-seo.git
|
||||
cd open-seo
|
||||
corepack enable
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 2) Log in to Cloudflare
|
||||
|
||||
```bash
|
||||
pnpm exec wrangler login
|
||||
```
|
||||
|
||||
### 3) Create Cloudflare resources
|
||||
|
||||
Use unique names so they do not collide with resources that already exist in your Cloudflare account. Replace `YOUR_SUFFIX` with something unique to you, for example your GitHub username or company name.
|
||||
|
||||
```bash
|
||||
pnpm exec wrangler kv namespace create open-seo-YOUR_SUFFIX
|
||||
pnpm exec wrangler kv namespace create open-seo-oauth-YOUR_SUFFIX
|
||||
pnpm exec wrangler d1 create open-seo-YOUR_SUFFIX
|
||||
pnpm exec wrangler r2 bucket create open-seo-YOUR_SUFFIX
|
||||
```
|
||||
|
||||
Save the IDs and names printed by Wrangler:
|
||||
|
||||
- The first KV namespace ID is for the `KV` binding.
|
||||
- The second KV namespace ID is for the `OAUTH_KV` binding.
|
||||
- The D1 `database_id` is for the `DB` binding.
|
||||
- The R2 bucket name is for the `R2` binding.
|
||||
|
||||
### 4) Edit `wrangler.jsonc`
|
||||
|
||||
Open `wrangler.jsonc` and replace only your Cloudflare resource values. Keep the binding names exactly as shown below, because the application code expects those names.
|
||||
|
||||
```jsonc
|
||||
"kv_namespaces": [
|
||||
{
|
||||
"binding": "KV",
|
||||
"id": "YOUR_KV_NAMESPACE_ID",
|
||||
},
|
||||
{
|
||||
"binding": "OAUTH_KV",
|
||||
"id": "YOUR_OAUTH_KV_NAMESPACE_ID",
|
||||
},
|
||||
],
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"database_name": "open-seo-YOUR_SUFFIX",
|
||||
"database_id": "YOUR_D1_DATABASE_ID",
|
||||
"migrations_dir": "drizzle",
|
||||
},
|
||||
],
|
||||
"r2_buckets": [
|
||||
{
|
||||
"bucket_name": "open-seo-YOUR_SUFFIX",
|
||||
"binding": "R2",
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
Do not use `wrangler deploy --update-config` for this step. Edit `wrangler.jsonc` manually so `"migrations_dir": "drizzle"` stays in the D1 database config.
|
||||
|
||||
### 5) Deploy
|
||||
|
||||
```bash
|
||||
pnpm run deploy
|
||||
```
|
||||
|
||||
### 6) Configure authentication and secrets
|
||||
|
||||
In the Cloudflare dashboard:
|
||||
|
||||
1. Go to `Compute` -> `Workers & Pages` -> your OpenSEO Worker.
|
||||
2. Open `Settings`.
|
||||
3. In `Domains & Routes`, enable `Cloudflare Access` for the `workers.dev` route.
|
||||
4. Save the values shown by Cloudflare Access.
|
||||
|
||||
Then set the same values as Worker secrets with Wrangler:
|
||||
|
||||
```bash
|
||||
pnpm exec wrangler secret put TEAM_DOMAIN
|
||||
pnpm exec wrangler secret put POLICY_AUD
|
||||
pnpm exec wrangler secret put DATAFORSEO_API_KEY
|
||||
```
|
||||
|
||||
Use the domain from `JWKS_URL` for `TEAM_DOMAIN`, for example `https://your-team.cloudflareaccess.com`. Use the Access application audience value for `POLICY_AUD`.
|
||||
|
||||
### 7) Optional: add an R2 lifecycle rule
|
||||
|
||||
DataForSEO API responses are cached in R2 under the `dataforseo-cache/` prefix. This step is optional, but recommended to automatically clean up expired cache objects:
|
||||
|
||||
```bash
|
||||
pnpm exec wrangler r2 bucket lifecycle add open-seo-YOUR_SUFFIX dataforseo-cache-expiry dataforseo-cache/ --expire-days 7
|
||||
```
|
||||
|
||||
### 8) Validate setup
|
||||
|
||||
1. Open your Worker URL again.
|
||||
2. Sign in with Cloudflare Access.
|
||||
3. OpenSEO should load after login.
|
||||
|
||||
If login fails, re-check the three secrets, the Access toggle, and the binding values in `wrangler.jsonc`.
|
||||
See [Operations](./SELF_HOSTING_CLOUDFLARE_OPERATIONS.md) for connecting MCP clients, updating to the latest OpenSEO version, and giving teammates access.
|
||||
|
||||
125
docs/SELF_HOSTING_CLOUDFLARE_MANUAL.md
Normal file
125
docs/SELF_HOSTING_CLOUDFLARE_MANUAL.md
Normal file
@ -0,0 +1,125 @@
|
||||
# Cloudflare Self-Hosting: Manual Deploy with Wrangler
|
||||
|
||||
Use this flow if the [Deploy to Cloudflare button](./SELF_HOSTING_CLOUDFLARE.md) fails with `Cannot provision a KV Namespace with the title "open-seo" because it already exists`. The reliable path is to create Cloudflare resources yourself, put their IDs into `wrangler.jsonc`, then deploy with Wrangler.
|
||||
|
||||
## 1) Clone your OpenSEO repo
|
||||
|
||||
Fork `every-app/open-seo` on GitHub if you want a repo you control for future updates, then clone it locally:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YOUR_GITHUB_USER/open-seo.git
|
||||
cd open-seo
|
||||
corepack enable
|
||||
pnpm install
|
||||
```
|
||||
|
||||
If you do not need a fork, clone the upstream repo instead:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/every-app/open-seo.git
|
||||
cd open-seo
|
||||
corepack enable
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## 2) Log in to Cloudflare
|
||||
|
||||
```bash
|
||||
pnpm exec wrangler login
|
||||
```
|
||||
|
||||
## 3) Create Cloudflare resources
|
||||
|
||||
Use unique names so they do not collide with resources that already exist in your Cloudflare account. Replace `YOUR_SUFFIX` with something unique to you, for example your GitHub username or company name.
|
||||
|
||||
```bash
|
||||
pnpm exec wrangler kv namespace create open-seo-YOUR_SUFFIX
|
||||
pnpm exec wrangler kv namespace create open-seo-oauth-YOUR_SUFFIX
|
||||
pnpm exec wrangler d1 create open-seo-YOUR_SUFFIX
|
||||
pnpm exec wrangler r2 bucket create open-seo-YOUR_SUFFIX
|
||||
```
|
||||
|
||||
Save the IDs and names printed by Wrangler:
|
||||
|
||||
- The first KV namespace ID is for the `KV` binding.
|
||||
- The second KV namespace ID is for the `OAUTH_KV` binding.
|
||||
- The D1 `database_id` is for the `DB` binding.
|
||||
- The R2 bucket name is for the `R2` binding.
|
||||
|
||||
## 4) Edit `wrangler.jsonc`
|
||||
|
||||
Open `wrangler.jsonc` and replace only your Cloudflare resource values. Keep the binding names exactly as shown below, because the application code expects those names.
|
||||
|
||||
```jsonc
|
||||
"kv_namespaces": [
|
||||
{
|
||||
"binding": "KV",
|
||||
"id": "YOUR_KV_NAMESPACE_ID",
|
||||
},
|
||||
{
|
||||
"binding": "OAUTH_KV",
|
||||
"id": "YOUR_OAUTH_KV_NAMESPACE_ID",
|
||||
},
|
||||
],
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"database_name": "open-seo-YOUR_SUFFIX",
|
||||
"database_id": "YOUR_D1_DATABASE_ID",
|
||||
"migrations_dir": "drizzle",
|
||||
},
|
||||
],
|
||||
"r2_buckets": [
|
||||
{
|
||||
"bucket_name": "open-seo-YOUR_SUFFIX",
|
||||
"binding": "R2",
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
Do not use `wrangler deploy --update-config` for this step. Edit `wrangler.jsonc` manually so `"migrations_dir": "drizzle"` stays in the D1 database config.
|
||||
|
||||
## 5) Deploy
|
||||
|
||||
```bash
|
||||
pnpm run deploy
|
||||
```
|
||||
|
||||
## 6) Configure authentication and secrets
|
||||
|
||||
In the Cloudflare dashboard:
|
||||
|
||||
1. Go to `Compute` -> `Workers & Pages` -> your OpenSEO Worker.
|
||||
2. Open `Settings`.
|
||||
3. In `Domains & Routes`, enable `Cloudflare Access` for the `workers.dev` route.
|
||||
4. Save the values shown by Cloudflare Access.
|
||||
|
||||
Then set the same values as Worker secrets with Wrangler:
|
||||
|
||||
```bash
|
||||
pnpm exec wrangler secret put TEAM_DOMAIN
|
||||
pnpm exec wrangler secret put POLICY_AUD
|
||||
pnpm exec wrangler secret put DATAFORSEO_API_KEY
|
||||
```
|
||||
|
||||
Use the domain from `JWKS_URL` for `TEAM_DOMAIN`, for example `https://your-team.cloudflareaccess.com`. Use the Access application audience value for `POLICY_AUD`. See [`DATAFORSEO_API_KEY.md`](./DATAFORSEO_API_KEY.md) for how to get a DataForSEO key.
|
||||
|
||||
## 7) Optional: add an R2 lifecycle rule
|
||||
|
||||
DataForSEO API responses are cached in R2 under the `dataforseo-cache/` prefix. This step is optional, but recommended to automatically clean up expired cache objects:
|
||||
|
||||
```bash
|
||||
pnpm exec wrangler r2 bucket lifecycle add open-seo-YOUR_SUFFIX dataforseo-cache-expiry dataforseo-cache/ --expire-days 7
|
||||
```
|
||||
|
||||
## 8) Validate setup
|
||||
|
||||
1. Open your Worker URL again.
|
||||
2. Sign in with Cloudflare Access.
|
||||
3. OpenSEO should load after login.
|
||||
|
||||
If login fails, re-check the three secrets, the Access toggle, and the binding values in `wrangler.jsonc`.
|
||||
|
||||
## Next steps
|
||||
|
||||
See [Operations](./SELF_HOSTING_CLOUDFLARE_OPERATIONS.md) for connecting MCP clients, updating to the latest OpenSEO version, and giving teammates access.
|
||||
81
docs/SELF_HOSTING_CLOUDFLARE_OPERATIONS.md
Normal file
81
docs/SELF_HOSTING_CLOUDFLARE_OPERATIONS.md
Normal file
@ -0,0 +1,81 @@
|
||||
# Cloudflare Self-Hosting: Operations
|
||||
|
||||
Day-to-day tasks after [initial setup](./SELF_HOSTING_CLOUDFLARE.md): connect the MCP server, update to the latest OpenSEO version, give teammates access, and manage telemetry.
|
||||
|
||||
## Connect the MCP server through Cloudflare Access
|
||||
|
||||
Use the same Cloudflare Access application that protects your OpenSEO Worker.
|
||||
Managed OAuth is required for MCP clients and is not enabled by default.
|
||||
|
||||
1. Open Cloudflare Zero Trust.
|
||||
2. Go to `Access controls` -> `Applications`.
|
||||
3. Find your OpenSEO application, then select `Edit`.
|
||||
4. Go to `Additional settings` -> `OAuth`.
|
||||
5. Turn on `Managed OAuth`.
|
||||
6. In `Managed OAuth settings`, allow the redirect URIs your MCP clients use:
|
||||
- Allow `localhost` / loopback clients for CLI and desktop agents (Codex
|
||||
CLI, Claude Code) that register `http://localhost:PORT/callback`.
|
||||
- Add HTTPS redirect URIs for web connectors (a path may end in `/*`).
|
||||
- Without this, clients can't finish [Dynamic Client Registration](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/managed-oauth/)
|
||||
and log in but expose no tools.
|
||||
7. Save.
|
||||
|
||||
MCP clients should connect to:
|
||||
|
||||
```text
|
||||
https://YOUR_WORKER_HOSTNAME/mcp
|
||||
```
|
||||
|
||||
## How to update to the latest OpenSEO version
|
||||
|
||||
If your repo was created from the Cloudflare Deploy button, use this flow.
|
||||
|
||||
### One-time setup
|
||||
|
||||
Run this once in your local repo:
|
||||
|
||||
```bash
|
||||
git remote add upstream https://github.com/every-app/open-seo.git
|
||||
git fetch upstream
|
||||
```
|
||||
|
||||
### Update steps (use every time)
|
||||
|
||||
```bash
|
||||
git fetch upstream
|
||||
cp wrangler.jsonc wrangler.local.backup.jsonc
|
||||
git checkout main
|
||||
git reset --hard upstream/main
|
||||
cp wrangler.local.backup.jsonc wrangler.jsonc
|
||||
git add wrangler.jsonc
|
||||
git commit -m "restore Cloudflare settings" || true
|
||||
git push --force-with-lease origin main
|
||||
```
|
||||
|
||||
Why this is needed:
|
||||
|
||||
- `wrangler.jsonc` has your Cloudflare resource IDs.
|
||||
- The update step keeps your IDs while pulling the newest OpenSEO code.
|
||||
|
||||
## Give teammates access to OpenSEO
|
||||
|
||||
1. Open Cloudflare Zero Trust.
|
||||
2. Go to Access -> Applications.
|
||||
3. Open your OpenSEO application.
|
||||
4. Edit the `Allow` policy.
|
||||
5. Add teammate emails (or your company email domain / group).
|
||||
6. Save.
|
||||
|
||||
Screenshots from the setup flow:
|
||||
|
||||
- [Edit the Access policy](https://github.com/user-attachments/assets/c7bbc7b4-a18e-4ae4-9fe5-3b33c72048a7)
|
||||
- [Add teammate emails to the allow list](https://github.com/user-attachments/assets/fa4ecaf2-31f7-4a64-9001-210cf729747b)
|
||||
|
||||
After saving, teammates can open your OpenSEO URL and sign in through Cloudflare
|
||||
Access. OpenSEO will use a shared workspace for everyone allowed by the policy.
|
||||
|
||||
## Telemetry
|
||||
|
||||
OpenSEO collects anonymized telemetry for core usage events: heartbeats with aggregate counts (installs, users, projects, feature usage) tied to a random install ID, sent every 5 minutes during the first two hours after install, then at most once daily. No URLs, keywords, prompts, emails, or IP-derived location are collected, and idle installs send nothing.
|
||||
|
||||
To disable it, add `OPENSEO_TELEMETRY_DISABLED=1` (or `DO_NOT_TRACK=1`) as a Worker variable under **Settings → Variables & Secrets**, then redeploy or restart the Worker.
|
||||
@ -11,6 +11,7 @@ The default `compose.yaml` uses the published GHCR image:
|
||||
## Prerequisites
|
||||
|
||||
- Docker Desktop (or Docker Engine + Docker Compose)
|
||||
- A DataForSEO API key (see [`DATAFORSEO_API_KEY.md`](./DATAFORSEO_API_KEY.md))
|
||||
|
||||
## Quickstart
|
||||
|
||||
@ -40,7 +41,7 @@ You can also persist it in `.env`.
|
||||
|
||||
## Telemetry
|
||||
|
||||
OpenSEO collects anonymized telemetry for core usage events: heartbeats with aggregate counts (installs, users, projects, feature usage) tied to a random install ID — every 5 minutes during the first two hours after install, then at most once daily. No URLs, keywords, prompts, emails, or IP-derived location are collected, and idle installs send nothing.
|
||||
OpenSEO collects anonymized telemetry for core usage events: heartbeats with aggregate counts (installs, users, projects, feature usage) tied to a random install ID, sent every 5 minutes during the first two hours after install, then at most once daily. No URLs, keywords, prompts, emails, or IP-derived location are collected, and idle installs send nothing.
|
||||
|
||||
To disable it, set `OPENSEO_TELEMETRY_DISABLED=1` (or `DO_NOT_TRACK=1`) in `.env`, then run `docker compose up -d --force-recreate open-seo`.
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ _Star counts are updated monthly. Last updated June 5, 2026._
|
||||
|
||||
OpenSEO is an open source alternative to Semrush and Ahrefs, built to be the only SEO tool that companies or small agencies need. It covers keyword research, rank tracking, backlinks, site audits, AI brand visibility, and an AI search prompt explorer. See them all on the [features page](/features).
|
||||
|
||||
It relies on [DataForSEO](https://dataforseo.com), a paid service, which is the gold standard for SEO data with pay-as-you-go pricing. Many features cost money to run, but far less than a legacy SaaS seat, and the [pricing is published in the repo](https://github.com/every-app/open-seo#seo-api-cost-reference).
|
||||
It relies on [DataForSEO](https://dataforseo.com), a paid service, which is the gold standard for SEO data with pay-as-you-go pricing. Many features cost money to run, but far less than a legacy SaaS seat, and the [costs are documented](/pricing).
|
||||
|
||||
OpenSEO also has an [MCP server](/docs/mcp) and AI skills, so you can use Claude Code, Codex, or OpenClaw to handle tedious SEO work like a first pass of keyword research, then dig into the results in the OpenSEO UI. That is different from pointing an agent at DataForSEO's MCP directly. You can save data to your OpenSEO account through the MCP, like tags for clustering keywords, and you can ask the agent for a link to view its research in OpenSEO instead of trusting whatever it reports back.
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
{
|
||||
"pages": ["mcp", "skills"]
|
||||
"pages": ["mcp", "skills", "self-hosting"]
|
||||
}
|
||||
|
||||
89
web/content/docs/self-hosting/cloudflare.md
Normal file
89
web/content/docs/self-hosting/cloudflare.md
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
title: "Cloudflare Self-Hosting"
|
||||
description: "Deploy OpenSEO to your own Cloudflare account for internet-facing, multi-device, or team use."
|
||||
---
|
||||
|
||||
Host OpenSEO on Cloudflare for internet-facing self-hosting across multiple devices or with your team. It works on Cloudflare's free plan.
|
||||
|
||||
## 1) Deploy from GitHub
|
||||
|
||||
[](https://deploy.workers.cloudflare.com/?url=https://github.com/every-app/open-seo)
|
||||
|
||||
Click the deploy button. There are lots of fields on the deploy form, but you only need to do the below steps.
|
||||
|
||||
1. Connect your Git provider (GitHub/GitLab).
|
||||
2. Leave the resource naming fields as default unless you have a reason to change them.
|
||||
3. Click `Create and Deploy`.
|
||||
4. Wait 1-2 minutes for deployment to finish.
|
||||
|
||||
If deploy fails with `Cannot provision a KV Namespace with the title "open-seo" because it already exists`, use the [manual deploy with Wrangler guide on GitHub](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_CLOUDFLARE_MANUAL.md) instead.
|
||||
|
||||
## 2) Configure authentication and secrets
|
||||
|
||||
In the Cloudflare dashboard:
|
||||
|
||||
1. Go to `Compute` -> `Workers & Pages` -> your OpenSEO Worker.
|
||||
2. Open `Settings`.
|
||||
3. In `Domains & Routes`, enable `Cloudflare Access` for the `workers.dev` route.
|
||||
4. Save the values shown by Cloudflare Access.
|
||||
5. In `Variables & Secrets`, add:
|
||||
- `POLICY_AUD` (from Access setup)
|
||||
- `TEAM_DOMAIN` (domain from `JWKS_URL`, for example `https://your-team.cloudflareaccess.com`)
|
||||
- `DATAFORSEO_API_KEY` (see [DataForSEO API key setup](/docs/self-hosting#dataforseo-api-key-setup))
|
||||
|
||||
## 3) Optional: add an R2 lifecycle rule
|
||||
|
||||
DataForSEO API responses are cached in R2 under the `dataforseo-cache/` prefix. This step is optional, but recommended to automatically clean up expired cache objects:
|
||||
|
||||
```bash
|
||||
npx wrangler r2 bucket lifecycle add open-seo dataforseo-cache-expiry dataforseo-cache/ --expire-days 7
|
||||
```
|
||||
|
||||
If you changed the R2 bucket name during deploy, replace `open-seo` with your bucket name.
|
||||
|
||||
Without a lifecycle rule, cached objects under `dataforseo-cache/` will accumulate indefinitely and increase storage costs over time.
|
||||
|
||||
## 4) Validate setup
|
||||
|
||||
1. Open your Worker URL again.
|
||||
2. Sign in with Cloudflare Access.
|
||||
3. OpenSEO should load after login.
|
||||
|
||||
If login fails, re-check the three secrets and Access toggle.
|
||||
|
||||
## Connect the MCP server through Cloudflare Access
|
||||
|
||||
Use the same Cloudflare Access application that protects your OpenSEO Worker. Managed OAuth is required for MCP clients and is not enabled by default.
|
||||
|
||||
1. Open Cloudflare Zero Trust.
|
||||
2. Go to `Access controls` -> `Applications`.
|
||||
3. Find your OpenSEO application, then select `Edit`.
|
||||
4. Go to `Additional settings` -> `OAuth`.
|
||||
5. Turn on `Managed OAuth`.
|
||||
6. In `Managed OAuth settings`, allow the redirect URIs your MCP clients use:
|
||||
- Allow `localhost` / loopback clients for CLI and desktop agents (Codex CLI, Claude Code) that register `http://localhost:PORT/callback`.
|
||||
- Add HTTPS redirect URIs for web connectors (a path may end in `/*`).
|
||||
- Without this, clients can't finish [Dynamic Client Registration](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/managed-oauth/) and log in but expose no tools.
|
||||
7. Save.
|
||||
|
||||
MCP clients should connect to:
|
||||
|
||||
```text
|
||||
https://YOUR_WORKER_HOSTNAME/mcp
|
||||
```
|
||||
|
||||
## Give teammates access to OpenSEO
|
||||
|
||||
1. Open Cloudflare Zero Trust.
|
||||
2. Go to Access -> Applications.
|
||||
3. Open your OpenSEO application.
|
||||
4. Edit the `Allow` policy.
|
||||
5. Add teammate emails (or your company email domain / group).
|
||||
6. Save.
|
||||
|
||||
After saving, teammates can open your OpenSEO URL and sign in through Cloudflare Access. OpenSEO will use a shared workspace for everyone allowed by the policy.
|
||||
|
||||
## Advanced guides on GitHub
|
||||
|
||||
- [Manual deploy with Wrangler](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_CLOUDFLARE_MANUAL.md): create the Cloudflare resources yourself and deploy with the CLI.
|
||||
- [Operations](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_CLOUDFLARE_OPERATIONS.md): update to the latest OpenSEO version and manage telemetry.
|
||||
113
web/content/docs/self-hosting/docker.md
Normal file
113
web/content/docs/self-hosting/docker.md
Normal file
@ -0,0 +1,113 @@
|
||||
---
|
||||
title: "Docker Self-Hosting"
|
||||
description: "Run OpenSEO locally with Docker Compose using the published GHCR image."
|
||||
---
|
||||
|
||||
Run OpenSEO locally with Docker.
|
||||
|
||||
In Docker mode, OpenSEO uses `AUTH_MODE=local_noauth` (no auth checks, local admin user `admin@localhost`). Only expose it behind your own auth-protected reverse proxy, tunnel, or private network. For internet-facing self-hosting, use [Cloudflare](/docs/self-hosting/cloudflare) instead.
|
||||
|
||||
The default `compose.yaml` uses the published GHCR image:
|
||||
|
||||
- `ghcr.io/every-app/open-seo:latest`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Docker Desktop](https://www.docker.com/products/docker-desktop/) (or Docker Engine + Docker Compose)
|
||||
- A [DataForSEO API key](/docs/self-hosting#dataforseo-api-key-setup)
|
||||
|
||||
## Quickstart
|
||||
|
||||
Clone the repo, then:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/every-app/open-seo.git
|
||||
cd open-seo
|
||||
cp .env.example .env
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Set `DATAFORSEO_API_KEY` in `.env`, then open `http://localhost:<PORT>` (default `3001`).
|
||||
|
||||
Docker Compose passes `.env` values into the container, and `compose.yaml` enables `CLOUDFLARE_INCLUDE_PROCESS_ENV=true` so the Cloudflare Vite runtime can read them as Worker bindings during local self-hosting.
|
||||
|
||||
Optional env values:
|
||||
|
||||
- `PORT` (defaults to `3001`)
|
||||
- `ALLOWED_HOST` (single reverse-proxy hostname to allow in Vite preview)
|
||||
- `AUTH_MODE=local_noauth` (already set in compose)
|
||||
- `OPEN_SEO_IMAGE` (defaults to `ghcr.io/every-app/open-seo:latest`)
|
||||
|
||||
If you are putting Docker behind a reverse proxy or a temporary tunnel, remember that Docker self-hosting runs with app auth disabled. Only expose it behind your own auth-protected reverse proxy, tunnel, or private network, and add the public hostname before restarting:
|
||||
|
||||
```bash
|
||||
ALLOWED_HOST=yourdomain.com docker compose up -d
|
||||
```
|
||||
|
||||
You can also persist it in `.env`.
|
||||
|
||||
## Telemetry
|
||||
|
||||
OpenSEO collects anonymized telemetry for core usage events: heartbeats with aggregate counts (installs, users, projects, feature usage) tied to a random install ID, sent every 5 minutes during the first two hours after install, then at most once daily. No URLs, keywords, prompts, emails, or IP-derived location are collected, and idle installs send nothing.
|
||||
|
||||
To disable it, set `OPENSEO_TELEMETRY_DISABLED=1` (or `DO_NOT_TRACK=1`) in `.env`, then run `docker compose up -d --force-recreate open-seo`.
|
||||
|
||||
## Pin to a specific image tag
|
||||
|
||||
Set `OPEN_SEO_IMAGE` in `.env` and restart:
|
||||
|
||||
```bash
|
||||
OPEN_SEO_IMAGE=ghcr.io/every-app/open-seo:v1.2.3
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Build your own image locally
|
||||
|
||||
If you are testing local code changes, build and run a local tag:
|
||||
|
||||
```bash
|
||||
docker build -f Dockerfile.selfhost -t open-seo:local .
|
||||
OPEN_SEO_IMAGE=open-seo:local docker compose up -d
|
||||
```
|
||||
|
||||
## Common commands
|
||||
|
||||
Restart service after env changes:
|
||||
|
||||
```bash
|
||||
docker compose up -d open-seo
|
||||
```
|
||||
|
||||
Pull latest published image and restart:
|
||||
|
||||
```bash
|
||||
docker compose pull && docker compose up -d
|
||||
```
|
||||
|
||||
Stop:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
Stop and remove volumes:
|
||||
|
||||
```bash
|
||||
docker compose down -v
|
||||
```
|
||||
|
||||
## Troubleshooting environment variables
|
||||
|
||||
To confirm Docker Compose is using the expected environment variables:
|
||||
|
||||
```bash
|
||||
docker compose config
|
||||
```
|
||||
|
||||
Check that `AUTH_MODE=local_noauth`, and that `DATAFORSEO_API_KEY` is the base64 encoded value of your DataForSEO email and API password in this format: `email:password`.
|
||||
|
||||
If you changed `.env`, recreate the container so Compose reapplies it:
|
||||
|
||||
```bash
|
||||
docker compose up -d --force-recreate open-seo
|
||||
```
|
||||
35
web/content/docs/self-hosting/index.md
Normal file
35
web/content/docs/self-hosting/index.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: "Self-Hosting OpenSEO"
|
||||
description: "Run OpenSEO yourself with Docker or Cloudflare, bring your own DataForSEO API key, and pay only for what you use."
|
||||
---
|
||||
|
||||
OpenSEO is free and open source. Self-hosting means the app costs $0. You bring your own DataForSEO API key and pay DataForSEO directly for API usage.
|
||||
|
||||
There are two self-hosting paths:
|
||||
|
||||
- **Simple: [Docker](/docs/self-hosting/docker)**, recommended for personal use on your own machine. Easiest way to get started.
|
||||
- **Advanced: [Cloudflare](/docs/self-hosting/cloudflare)**, for internet-facing self-hosting across multiple devices or with your team. A SaaS-like experience with automatic database backups, and it works on Cloudflare's free plan. Slightly more setup if you're unfamiliar with Cloudflare.
|
||||
|
||||
## DataForSEO API key setup
|
||||
|
||||
OpenSEO uses [DataForSEO](https://dataforseo.com/?aff=255379) to fetch SEO data. DataForSEO is a paid third-party service unaffiliated with OpenSEO. You need an API key to connect OpenSEO to it.
|
||||
|
||||
1. Go to [DataForSEO API Access](https://app.dataforseo.com/api-access?aff=255379).
|
||||
2. Click "Send by email" to get your credentials.
|
||||
3. Copy the longer credentials labelled "Base64" credentials.
|
||||
4. Set this as `DATAFORSEO_API_KEY` in your environment:
|
||||
- Docker: `.env`
|
||||
- Cloudflare: as a Worker secret in the dashboard
|
||||
- Local development: `.env.local`
|
||||
|
||||
New DataForSEO accounts include $1 of free credit to test with, and the minimum top-up is $50. See [pricing](/pricing) for cost estimates. Self-hosted costs run slightly lower, since the hosted service adds a 28% fee on DataForSEO requests.
|
||||
|
||||
## Optional features
|
||||
|
||||
### Google Search Console
|
||||
|
||||
Search Console is optional and works in self-hosted deployments using your own Google OAuth client. It takes about 10 minutes of one-time setup. See the [Google Search Console guide on GitHub](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_GOOGLE_SEARCH_CONSOLE.md).
|
||||
|
||||
### AI features (SAM)
|
||||
|
||||
AI features like SAM, the in-app SEO agent, are optional. Set the `OPENROUTER_API_KEY` environment variable to enable them. Create a key at [openrouter.ai/settings/keys](https://openrouter.ai/settings/keys).
|
||||
8
web/content/docs/self-hosting/meta.json
Normal file
8
web/content/docs/self-hosting/meta.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "Self-Hosting",
|
||||
"pages": [
|
||||
"[Overview](/docs/self-hosting)",
|
||||
"[Docker](/docs/self-hosting/docker)",
|
||||
"[Cloudflare](/docs/self-hosting/cloudflare)"
|
||||
]
|
||||
}
|
||||
@ -19,7 +19,10 @@ export const docsSource = loader({
|
||||
{
|
||||
transformPageTree: {
|
||||
folder(node, folderPath) {
|
||||
if (folderPath !== "skills") return node;
|
||||
// Folders whose meta.json lists an explicit "[Overview](...)" link;
|
||||
// drop the index node so the folder title doesn't duplicate it.
|
||||
if (folderPath !== "skills" && folderPath !== "self-hosting")
|
||||
return node;
|
||||
|
||||
return {
|
||||
...node,
|
||||
|
||||
@ -59,7 +59,7 @@ function getMobileNavItems(githubStarCount: string) {
|
||||
label: "Resources",
|
||||
links: [
|
||||
{ label: "Blog", href: "/blogs" },
|
||||
{ label: "Why Open Source?", href: "/open-source-seo" },
|
||||
{ label: "Docs", href: "/docs" },
|
||||
{ label: "MCP Setup", href: "/docs/mcp" },
|
||||
{ label: "Skills", href: "/docs/skills" },
|
||||
],
|
||||
@ -273,9 +273,9 @@ function ResourcesDropdown() {
|
||||
description: "SEO articles and guides.",
|
||||
},
|
||||
{
|
||||
label: "Why Open Source?",
|
||||
href: "/open-source-seo",
|
||||
description: "Open source puts the power in user's hands.",
|
||||
label: "Docs",
|
||||
href: "/docs",
|
||||
description: "Setup, MCP, skills, and self-hosting guides.",
|
||||
},
|
||||
{
|
||||
label: "MCP",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user