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.
This commit is contained in:
Ben Senescu 2026-03-12 19:28:45 -04:00 committed by GitHub
parent b9c1061934
commit 33173f5c04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 126 additions and 20 deletions

11
.dockerignore Normal file
View File

@ -0,0 +1,11 @@
.git
.github
.logs
.wrangler
node_modules
dist
coverage
*.log
Dockerfile
.env
.env.local

View File

@ -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
# -----------------------------------------------------------------------------

57
.github/workflows/docker-image.yml vendored Normal file
View File

@ -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 }}

View File

@ -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}"]

View File

@ -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:<PORT>` (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

View File

@ -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:<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`)
- `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:

View File

@ -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: