# OPENBUREAU — Komplettstack für Self-Hosting (Muster gespiegelt von RAPPORT-SERVER). # ALLES in einem Stack / einem LXC: Supabase-Kern + CMS. # # Vor `docker compose up`: # 1. cp .env.example .env # 2. JWT_SECRET + POSTGRES_PASSWORD setzen (openssl rand -hex 32) # 3. node scripts/generate-keys.mjs → ANON_KEY + SERVICE_ROLE_KEY in .env # 4. SITE_URL + API_EXTERNAL_URL auf die LAN-/Domain-Adresse setzen # 5. kong.yml: __CORS_ORIGIN__ durch SITE_URL ersetzen (Browser-Origin) # 6. BIND_ADDR: 127.0.0.1 hinter Reverse-Proxy, 0.0.0.0 für LAN-Direkt # # (Das Proxmox-Script erledigt 1–6 automatisch.) # Dann: docker compose up -d --build # # Abweichung von RAPPORT: realtime + storage weggelassen (nutzt das CMS nicht). # Nachrüsten = die beiden Service-Blöcke aus RAPPORT-SERVER hier einfügen. services: # ════════════════════════════════════════════════════════════════════════ # Postgres — Datenbank mit Supabase-Extensions # ════════════════════════════════════════════════════════════════════════ db: image: supabase/postgres:15.8.1.020 container_name: openbureau-db restart: unless-stopped environment: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: postgres JWT_SECRET: ${JWT_SECRET} JWT_EXP: 3600 volumes: - postgres-data:/var/lib/postgresql/data # OPENBUREAU-Schema (posts-Tabelle) wird vom Post-Init eingespielt. - ./db/schema.sql:/openbureau-schema.sql:ro # Läuft als LETZTES Init-Script (zz-) — nach den supabase-internen. - ./volumes/db/init/zz-openbureau-post-init.sh:/docker-entrypoint-initdb.d/zz-openbureau-post-init.sh:ro ports: # Nur localhost — Zugriff über Kong / interne Container-Kommunikation. - "127.0.0.1:${DB_PORT:-5432}:5432" healthcheck: test: ["CMD", "pg_isready", "-U", "supabase_admin", "-d", "postgres"] interval: 5s timeout: 5s retries: 20 start_period: 30s # ════════════════════════════════════════════════════════════════════════ # Migrate — spielt das (idempotente) Schema bei jedem `up` nach, damit neue # Tabellen/Spalten auch in eine BESTEHENDE DB kommen (Init-Scripts laufen nur # beim allerersten Start). Läuft einmal und beendet sich. supabase_admin = # Superuser → keine Owner-Konflikte. schema.sql ist idempotent. # ════════════════════════════════════════════════════════════════════════ migrate: image: supabase/postgres:15.8.1.020 container_name: openbureau-migrate restart: "no" depends_on: db: condition: service_healthy environment: PGPASSWORD: ${POSTGRES_PASSWORD} volumes: - ./db/schema.sql:/openbureau-schema.sql:ro entrypoint: ["bash", "-c"] command: - > psql -h db -U supabase_admin -d postgres -v ON_ERROR_STOP=1 -f /openbureau-schema.sql && psql -h db -U supabase_admin -d postgres -c "notify pgrst, 'reload schema';" && echo '✓ Schema migriert.' # ════════════════════════════════════════════════════════════════════════ # GoTrue — Auth (Login für das CMS) # ════════════════════════════════════════════════════════════════════════ auth: image: supabase/gotrue:v2.158.1 container_name: openbureau-auth restart: unless-stopped depends_on: db: condition: service_healthy environment: GOTRUE_API_HOST: 0.0.0.0 GOTRUE_API_PORT: 9999 API_EXTERNAL_URL: ${API_EXTERNAL_URL} GOTRUE_DB_DRIVER: postgres GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@db:5432/postgres GOTRUE_SITE_URL: ${SITE_URL} GOTRUE_URI_ALLOW_LIST: ${SITE_URL},${SITE_URL}/ # Single-Author: Self-Signup aus. User wird per Admin-API angelegt # (Kommando steht im README / LXC-Output). GOTRUE_DISABLE_SIGNUP: "true" GOTRUE_JWT_ADMIN_ROLES: service_role GOTRUE_JWT_AUD: authenticated GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated GOTRUE_JWT_EXP: 3600 GOTRUE_JWT_SECRET: ${JWT_SECRET} GOTRUE_EXTERNAL_EMAIL_ENABLED: "true" GOTRUE_MAILER_AUTOCONFIRM: "true" # ════════════════════════════════════════════════════════════════════════ # PostgREST — REST-API auf der DB (supabase-js spricht hierüber mit posts) # ════════════════════════════════════════════════════════════════════════ rest: image: postgrest/postgrest:v12.2.0 container_name: openbureau-rest restart: unless-stopped depends_on: db: condition: service_healthy environment: PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD}@db:5432/postgres PGRST_DB_SCHEMAS: public PGRST_DB_ANON_ROLE: anon PGRST_JWT_SECRET: ${JWT_SECRET} PGRST_DB_USE_LEGACY_GUCS: "false" # ════════════════════════════════════════════════════════════════════════ # Kong — API-Gateway: bündelt /auth/v1 + /rest/v1 unter einer URL # ════════════════════════════════════════════════════════════════════════ kong: image: kong:2.8.1 container_name: openbureau-kong restart: unless-stopped depends_on: - auth - rest environment: KONG_DATABASE: "off" KONG_DECLARATIVE_CONFIG: /var/lib/kong/kong.yml KONG_DNS_ORDER: LAST,A,CNAME KONG_PLUGINS: request-transformer,cors,key-auth,acl,basic-auth volumes: - ./kong.yml:/var/lib/kong/kong.yml:ro ports: # Standard 127.0.0.1: nur lokal/Reverse-Proxy erreichbar. Für LAN-Direkt- # zugriff ohne Proxy BIND_ADDR=0.0.0.0 in .env setzen. - "${BIND_ADDR:-127.0.0.1}:${KONG_HTTP_PORT:-8000}:8000" - "${BIND_ADDR:-127.0.0.1}:${KONG_HTTPS_PORT:-8443}:8443" # ════════════════════════════════════════════════════════════════════════ # CMS — Node-API + Hugo-Binary + Admin-SPA, serviert die Site # ════════════════════════════════════════════════════════════════════════ cms: build: context: . dockerfile: api/Dockerfile args: # Browser-seitig (Admin-SPA, zur Build-Zeit): öffentliche Supabase-URL. VITE_SUPABASE_URL: ${API_EXTERNAL_URL} VITE_SUPABASE_ANON_KEY: ${ANON_KEY} container_name: openbureau-cms restart: unless-stopped depends_on: db: condition: service_healthy migrate: condition: service_completed_successfully kong: condition: service_started environment: # Server-seitig: intern über Kong, mit Service-Key. SUPABASE_URL: http://kong:8000 SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY} ADMIN_EMAILS: ${ADMIN_EMAILS:-} SITE_DIR: /site PORT: 3000 GIT_PUBLISH: ${GIT_PUBLISH:-false} GIT_REMOTE: ${GIT_REMOTE:-origin} GIT_BRANCH: ${GIT_BRANCH:-main} GIT_AUTHOR_NAME: ${GIT_AUTHOR_NAME:-OPENBUREAU CMS} GIT_AUTHOR_EMAIL: ${GIT_AUTHOR_EMAIL:-cms@openbureau.ch} volumes: # Repo-Root: api schreibt content/ und baut public/ + preview/. - ..:/site ports: # Wie Kong: standardmäßig nur 127.0.0.1 (hinter Reverse-Proxy). - "${BIND_ADDR:-127.0.0.1}:${APP_PORT:-8080}:3000" volumes: postgres-data: