Actualiza toolkit operativo y documentación

This commit is contained in:
urieljareth
2026-09-10 20:53:50 -06:00
parent 3b7209dcc1
commit 714057bfc8
69 changed files with 6023 additions and 384 deletions
@@ -0,0 +1,78 @@
# OpenSEO self-host — Coolify stack (LXC 102)
#
# Por qué este compose en lugar del repo upstream (`every-app/open-seo`) vía
# railpack:
# - el deploy anterior (uuid kj0kccsb4d46tm0d6qe6docy) terminó con Caddy
# respondiendo 404 a todo porque /app/dist no existía en la imagen cacheada
# (Coolify saltó el build: "No build configuration changed & image found ...
# Build step skipped").
# - el README upstream lo dice explícitamente: "We recommend self-hosting
# with Cloudflare as opposed to Railway, Coolify or Dokploy. We plan to
# make it simpler to host on those platforms in the next few months."
# - esta imagen (`ghcr.io/every-app/open-seo:sha-c469a48`) es la build del
# mismo commit, pero el build de Vite corre en `docker-entrypoint.sh` al
# arrancar el contenedor, no en el build de la imagen. Y el entrypoint ya
# tiene la lógica de fingerprint para no reconstruir cuando los env vars
# relevantes no cambiaron.
#
# Contrato: docs/AGENTS-coolify-apps.md
# - sin publicar 80/443: solo `expose`, Traefik enruta (§2.3)
# - SECRETOS vía env vars inyectados por Coolify (§2.5)
# - volumen con nombre para /app/.wrangler (SQLite que sobrevive al redeploy, §5)
# - healthcheck independiente de servicios externos al boot
# - AUTH_MODE=local_noauth porque aquí no hay TEAM_DOMAIN/POLICY_AUD de
# Cloudflare Access. Si más adelante se quiere proteger con auth, cambiar
# a AUTH_MODE=cloudflare_access + TEAM_DOMAIN + POLICY_AUD.
# - ALLOWED_HOST es obligatorio detrás del túnel: sin él Vite bloquea toda
# petición externa con "Blocked request" (ver preflight info level).
services:
app:
image: 'ghcr.io/every-app/open-seo:sha-c469a48'
environment:
# Puerto en el que escucha `vite preview` (per Dockerfile.selfhost / entrypoint).
- PORT=3001
# Single admin user, sin pantalla de login. NO exponer públicamente sin
# poner tu propia auth delante — el preflight lo dice literal.
- AUTH_MODE=local_noauth
# Host header permitido. Es el FQDN público por el que llega el tráfico
# desde el túnel de Cloudflare.
- ALLOWED_HOST=openseo.urieljareth.org
# Requerido por el runtime workerd para exponer process.env a los
# bindings (lo exige el compose upstream).
- CLOUDFLARE_INCLUDE_PROCESS_ENV=true
# SEO data (opcional). Vacío = la app arranca, los workflows SEO
# devuelven "no data". Se setea después vía Coolify env.
- DATAFORSEO_API_KEY=${DATAFORSEO_API_KEY:-}
# Telemetry opt-out (también vía DO_NOT_TRACK). Por defecto apagado.
- OPENSEO_TELEMETRY_DISABLED=${OPENSEO_TELEMETRY_DISABLED:-}
- DO_NOT_TRACK=${DO_NOT_TRACK:-}
# AI features (SAM, el agente SEO integrado). Vacío = SAM deshabilitado.
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}
- OPENROUTER_MODEL=${OPENROUTER_MODEL:-}
expose:
- '3001'
# El endpoint /api/health lo sirve el propio preflight (ver
# src/lib/selfhost-preflight.ts) sin auth — seguro para el healthcheck.
# Usamos `node` directamente porque la imagen es node:22 y el HEALTHCHECK
# upstream hace exactamente esto.
healthcheck:
test:
- CMD-SHELL
- "node -e \"fetch('http://127.0.0.1:3001/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""
interval: 30s
timeout: 10s
retries: 5
# Primer arranque: preflight + migrations + vite build (1-2 min).
start_period: 300s
volumes:
- 'openseo-data:/app/.wrangler'
restart: unless-stopped
logging:
driver: json-file
options:
max-size: '10m'
max-file: '3'
volumes:
openseo-data: {}