Simplify Docker self-hosting configuration

This commit is contained in:
Ben Senescu 2026-03-09 23:37:58 -04:00
parent 2d01ce5196
commit d490dde51f
8 changed files with 16 additions and 82 deletions

View File

@ -15,9 +15,11 @@ VITE_APP_ID=open-seo
# # PORT=3001
# -------------------------------------------------------------
# --- Docker self-hosting only (standalone local mode) ---
# --- Docker self-hosting only (local mode) ---
# See SELF_HOSTING_DOCKER.md
# Docker compose runs with BYPASS_GATEWAY_LOCAL_ONLY=true.
# Optional host/container port (defaults to 3001):
# PORT=3001
# Optional in .env because compose already sets it.
# BYPASS_GATEWAY_LOCAL_ONLY=true
# Optional override (defaults to open-seo):
@ -26,4 +28,4 @@ VITE_APP_ID=open-seo
# # See README.md for instructions for how to get this.
# DATAFORSEO_API_KEY=
# Legacy gateway auth keys are not needed in standalone Docker mode.
# Legacy gateway auth keys are not needed in Docker self-host mode.

View File

@ -12,7 +12,7 @@ OpenSEO is an SEO tool for _the people_. If tools like Semrush or Ahrefs are too
- [Community](#community)
- [Pricing / Costs (Free + API costs)](#pricing--costs)
- [Self Hosting (Deploy on Cloudflare) \[5-10 minutes\]](#self-hosting-deploy-on-cloudflare-5-10-minutes)
- [Docker Self Hosting (Standalone OpenSEO)](#docker-self-hosting-standalone-openseo)
- [Docker Self Hosting](#docker-self-hosting)
- [Local Development](#local-development)
- [Contributing](#contributing)
- [SEO API Cost Reference](#seo-api-cost-reference)
@ -144,14 +144,14 @@ npx wrangler secret put DATAFORSEO_API_KEY
Now you're all set! Go back to the gateway, click on the OpenSEO app, and start getting better at SEO!
## Docker Self Hosting (Standalone OpenSEO)
## Docker Self Hosting
Quickstart:
1. `cp .env.example .env`
2. Set `DATAFORSEO_API_KEY` in `.env`
3. `docker compose up`
4. Open `http://localhost:3001`
4. Open `http://localhost:<PORT>` (default `3001`)
For runtime details, caveats, and troubleshooting, see [`SELF_HOSTING_DOCKER.md`](./SELF_HOSTING_DOCKER.md).

View File

@ -1,6 +1,6 @@
# Docker Self-Hosting (Standalone OpenSEO)
# Docker Self-Hosting
This guide runs OpenSEO as a standalone local service without Every App Gateway.
This guide runs OpenSEO as a local service without Every App Gateway.
In this mode, OpenSEO runs with `BYPASS_GATEWAY_LOCAL_ONLY=true`, so authentication and Gateway-managed user accounts are disabled.
@ -32,7 +32,7 @@ Required:
Optional:
- `OPENAI_API_KEY`
- `PORT` (defaults to `3001`)
- `VITE_APP_ID` (defaults to `open-seo`)
- `BYPASS_GATEWAY_LOCAL_ONLY=true` (Docker compose already sets this)
@ -44,7 +44,7 @@ docker compose up
URL:
- OpenSEO: `http://localhost:3001`
- OpenSEO: `http://localhost:<PORT>` (defaults to `3001`)
Boot behavior:

View File

@ -5,22 +5,21 @@ services:
dockerfile: self-host/Dockerfile.selfhost
working_dir: /app
environment:
- PORT=3001
- PORT=${PORT:-3001}
- BYPASS_GATEWAY_LOCAL_ONLY=true
- VITE_APP_ID=${VITE_APP_ID:-open-seo}
- VITE_GATEWAY_URL=${VITE_GATEWAY_URL:-http://localhost:3001}
- GATEWAY_URL=${GATEWAY_URL:-http://localhost:3001}
- VITE_GATEWAY_URL=${VITE_GATEWAY_URL:-http://localhost:${PORT:-3001}}
- GATEWAY_URL=${GATEWAY_URL:-http://localhost:${PORT:-3001}}
- DATAFORSEO_API_KEY=${DATAFORSEO_API_KEY}
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
- VITE_SHOW_DEVTOOLS=false
command:
[
"sh",
"-c",
"pnpm run db:migrate:local && pnpm exec vite dev --host 0.0.0.0 --port 3001",
"pnpm run db:migrate:local && pnpm exec vite dev --host 0.0.0.0 --port ${PORT:-3001}",
]
ports:
- "127.0.0.1:3001:3001"
- "127.0.0.1:${PORT:-3001}:${PORT:-3001}"
volumes:
- .:/app
- open_seo_node_modules:/app/node_modules

View File

@ -8,8 +8,6 @@
"drizzle.config.ts",
// DB index re-exports schema for convenience
"src/db/index.ts",
// Docker self-host runtime entrypoint scripts
"self-host/scripts/*.mjs",
],
"project": ["**/*.{js,mjs,ts,tsx}", "!src/routeTree.gen.ts"],
"ignore": [

View File

@ -1,22 +0,0 @@
FROM node:22
ENV PNPM_HOME=/pnpm
ENV PATH=$PNPM_HOME:$PATH
WORKDIR /app
RUN corepack enable
COPY self-host/scripts/resolve-gateway-tag.mjs self-host/scripts/download-archive.mjs /tmp/scripts/
ARG GATEWAY_RELEASE_TAG=
RUN gateway_tag=$(node /tmp/scripts/resolve-gateway-tag.mjs) \
&& echo "Downloading Gateway source for tag: ${gateway_tag}" \
&& node /tmp/scripts/download-archive.mjs "https://github.com/every-app/every-app/archive/refs/tags/${gateway_tag}.tar.gz" /tmp/every-app-source.tar.gz \
&& mkdir -p /tmp/every-app-source \
&& tar -xzf /tmp/every-app-source.tar.gz -C /tmp/every-app-source \
&& source_root=$(find /tmp/every-app-source -mindepth 1 -maxdepth 1 -type d | head -n 1) \
&& cp -R "$source_root/apps/every-app-gateway/." /app \
&& rm -rf /tmp/every-app-source /tmp/every-app-source.tar.gz /tmp/scripts
RUN pnpm install --frozen-lockfile

View File

@ -1,20 +0,0 @@
// Downloads a file from a URL and writes it to a local path.
// Usage: node self-host/scripts/download-archive.mjs <url> <output-path>
import { writeFileSync } from "node:fs";
const [url, outputPath] = process.argv.slice(2);
if (!url || !outputPath) {
console.error(
"Usage: node self-host/scripts/download-archive.mjs <url> <output-path>",
);
process.exit(1);
}
const res = await fetch(url);
if (!res.ok) {
throw new Error("Failed to download source archive: " + String(res.status));
}
writeFileSync(outputPath, Buffer.from(await res.arrayBuffer()));

View File

@ -1,23 +0,0 @@
// Resolves the gateway release tag to use for the selfhost Docker build.
// If GATEWAY_RELEASE_TAG is set, prints it and exits.
// Otherwise fetches the latest release tag from the GitHub API.
const tag = process.env.GATEWAY_RELEASE_TAG;
if (tag) {
process.stdout.write(tag);
process.exit(0);
}
const res = await fetch(
"https://api.github.com/repos/every-app/every-app/releases/latest",
);
if (!res.ok) {
throw new Error("Failed to resolve latest release: " + String(res.status));
}
const parsed = await res.json();
if (!parsed.tag_name) {
throw new Error("Missing tag_name in latest release payload");
}
process.stdout.write(parsed.tag_name);