From 33173f5c04f8d89bade2c5b9068a7c19fe1f23f5 Mon Sep 17 00:00:00 2001 From: Ben Senescu <44480372+bensenescu@users.noreply.github.com> Date: Thu, 12 Mar 2026 19:28:45 -0400 Subject: [PATCH] chore: publish OpenSEO Docker images and use image-first self-host flow (#18) * chore: add published Docker image workflow and self-host image flow * fix: align Docker publish and build paths Use the canonical GHCR image name and correct Dockerfile path references so CI publishing and documented local builds work as expected. * fix: restore Docker self-host runtime defaults Use the full Node base image and expose Compose env vars to the Cloudflare Vite runtime so local self-hosting keeps auth bindings and outbound HTTPS working. --- .dockerignore | 11 ++++++ .env.example | 3 ++ .github/workflows/docker-image.yml | 57 ++++++++++++++++++++++++++++++ Dockerfile.selfhost | 8 ++++- README.md | 15 +++++++- SELF_HOSTING_DOCKER.md | 31 ++++++++++++++-- compose.yaml | 21 ++++------- 7 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/docker-image.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..cdfdf13 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.git +.github +.logs +.wrangler +node_modules +dist +coverage +*.log +Dockerfile +.env +.env.local diff --git a/.env.example b/.env.example index 26073fa..c0b4e0e 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,9 @@ # Optional app port # PORT=3001 +# Optional image tag override for Docker self-hosting +# OPEN_SEO_IMAGE=ghcr.io/every-app/open-seo:latest + # ----------------------------------------------------------------------------- # Auth mode # ----------------------------------------------------------------------------- diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..5652517 --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,57 @@ +name: Publish Docker image + +on: + push: + branches: + - main + tags: + - "v*" + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/every-app/open-seo + tags: | + type=ref,event=branch + type=ref,event=tag + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha,prefix=sha- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push image + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile.selfhost + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile.selfhost b/Dockerfile.selfhost index 3c6d30a..7504756 100644 --- a/Dockerfile.selfhost +++ b/Dockerfile.selfhost @@ -1,3 +1,4 @@ +# Use the full Node image so workerd has a working CA trust store for outbound HTTPS. FROM node:22 ENV PNPM_HOME=/pnpm @@ -8,5 +9,10 @@ WORKDIR /app RUN corepack enable COPY package.json pnpm-lock.yaml ./ - RUN pnpm install --frozen-lockfile + +COPY . . + +EXPOSE 3001 + +CMD ["sh", "-c", "pnpm run db:migrate:local && pnpm exec vite dev --host 0.0.0.0 --port ${PORT:-3001}"] diff --git a/README.md b/README.md index 7b65870..4211a3e 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ printf '%s' 'YOUR_LOGIN:YOUR_PASSWORD' | base64 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` ## Self-hosting @@ -113,9 +114,21 @@ Quickstart: 1. `cp .env.example .env` 2. Set `DATAFORSEO_API_KEY` in `.env` -3. `docker compose up` +3. `docker compose up -d` 4. Open `http://localhost:` (default `3001`) +Docker Compose passes `.env` values into the container, and the Docker self-host flow enables `CLOUDFLARE_INCLUDE_PROCESS_ENV=true` so the Cloudflare Vite runtime can read them as Worker bindings. + +By default, `compose.yaml` pulls the published image from GHCR: + +- `ghcr.io/every-app/open-seo:latest` + +Use a pinned version tag in `.env` if preferred: + +```sh +OPEN_SEO_IMAGE=ghcr.io/every-app/open-seo:v1.2.3 +``` + For more info, see [`SELF_HOSTING_DOCKER.md`](./SELF_HOSTING_DOCKER.md). ## Cloudflare Self-Hosting diff --git a/SELF_HOSTING_DOCKER.md b/SELF_HOSTING_DOCKER.md index 62133ab..8606a73 100644 --- a/SELF_HOSTING_DOCKER.md +++ b/SELF_HOSTING_DOCKER.md @@ -4,6 +4,10 @@ Run OpenSEO locally with Docker. In Docker mode, OpenSEO uses `AUTH_MODE=local_noauth` (no auth checks, local admin user `admin@localhost`). +The default `compose.yaml` uses the published GHCR image: + +- `ghcr.io/every-app/open-seo:latest` + ## Prerequisites - Docker Desktop (or Docker Engine + Docker Compose) @@ -12,15 +16,36 @@ In Docker mode, OpenSEO uses `AUTH_MODE=local_noauth` (no auth checks, local adm ```bash cp .env.example .env -docker compose up +docker compose up -d ``` Set `DATAFORSEO_API_KEY` in `.env`, then open `http://localhost:` (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`) - `AUTH_MODE=local_noauth` (already set in compose) +- `OPEN_SEO_IMAGE` (defaults to `ghcr.io/every-app/open-seo:latest`) + +## 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 @@ -30,10 +55,10 @@ Optional env values: docker compose up -d open-seo ``` -- Rebuild image (after dependency or Docker config changes): +- Pull latest published image and restart: ```bash -docker compose up --build +docker compose pull && docker compose up -d ``` - Stop: diff --git a/compose.yaml b/compose.yaml index 5403d9c..6d2fb9d 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,26 +1,17 @@ services: open-seo: - build: - context: . - dockerfile: Dockerfile.selfhost - working_dir: /app + image: ${OPEN_SEO_IMAGE:-ghcr.io/every-app/open-seo:latest} + restart: unless-stopped environment: + # Required for local Docker self-hosting: exposes Compose env vars to cloudflare:workers bindings. + - CLOUDFLARE_INCLUDE_PROCESS_ENV=true - PORT=${PORT:-3001} - AUTH_MODE=local_noauth - DATAFORSEO_API_KEY=${DATAFORSEO_API_KEY} - VITE_SHOW_DEVTOOLS=false - command: - [ - "sh", - "-c", - "pnpm run db:migrate:local && pnpm exec vite dev --host 0.0.0.0 --port ${PORT:-3001}", - ] ports: - "127.0.0.1:${PORT:-3001}:${PORT:-3001}" volumes: - - .:/app - - open_seo_node_modules:/app/node_modules - - open_seo_pnpm_store:/pnpm/store + - open_seo_data:/app/.wrangler volumes: - open_seo_node_modules: - open_seo_pnpm_store: + open_seo_data: