Files
nexus/compose.yaml
T
devops f95463ef50
CI - Build & Test / Backend (.NET) (push) Successful in 28s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 18s
CI - Build & Test / Security Check (push) Successful in 2s
fix: permanent owner password persistence with SeedAudit guard
Root cause: Dual-source architecture for owner password (Gitea secret
ENV_OWNER_PASSWORD vs host .env OWNER_PASSWORD) caused drift when
the DB was ever re-seeded or the volume recreated.

Changes:
- Add SeedAudit entity + migration to track one-time seed operations
- EnsureDatabaseAsync checks SeedAudit BEFORE seeding — owner is never
  re-created even if the Users table is wiped
- Deploy and rollback workflows now read OWNER_PASSWORD from the host's
  persistent .env (single source of truth) instead of Gitea secrets
- compose.yaml documented: OWNER_PASSWORD only used during initial seed
- Cleanup: .gitignore extended for core dumps, changelog/deployment.md
  updated with 2026-06-20 session notes

After this fix the DB is the single source of truth for the owner
password after initial seed. The host .env is the single reference
for the initial value.
2026-06-21 10:15:36 +02:00

146 lines
4.4 KiB
YAML

name: nexus
services:
postgres:
image: postgres:17-alpine
restart: unless-stopped
deploy:
resources:
limits:
memory: 384M
reservations:
memory: 96M
environment:
POSTGRES_INITDB_ARGS: --data-checksums
POSTGRES_DB: ${POSTGRES_DB:-nexus}
POSTGRES_USER: ${POSTGRES_USER:-nexus}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
volumes:
- nexus-postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-nexus} -d ${POSTGRES_DB:-nexus}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks: [nexus]
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
api:
build:
context: ./backend
restart: unless-stopped
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 128M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
environment:
ASPNETCORE_ENVIRONMENT: Production
ASPNETCORE_URLS: http://+:8080
ConnectionStrings__Nexus: Host=postgres;Port=5432;Database=${POSTGRES_DB:-nexus};Username=${POSTGRES_USER:-nexus};Password=${POSTGRES_PASSWORD}
Jwt__Key: ${JWT_KEY:?Set JWT_KEY in .env}
Jwt__Issuer: ${JWT_ISSUER:-nexus}
Jwt__Audience: ${JWT_AUDIENCE:-nexus-web}
Owner__Email: ${OWNER_EMAIL:?Set OWNER_EMAIL in .env}
# OWNER_PASSWORD is only used during initial seed (first deploy).
# After that the DB is the single source of truth, enforced by SeedAudit.
# Default: empty (seed uses a random password if unset on first run).
Owner__Password: ${OWNER_PASSWORD:-}
Owner__DisplayName: ${OWNER_DISPLAY_NAME:-Owner}
Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://host.docker.internal:18789}
Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-}
Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-}
Admin__ResetToken: ${Admin__ResetToken:-}
NexusApiKey: ${NEXUS_API_KEY:-}
extra_hosts:
- host.docker.internal:host-gateway
depends_on:
postgres:
condition: service_started
restart: true
healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080/health/live || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
volumes:
- /home/projekte_bao/openclaw/data/openclaw/openclaw.json:/home/node/.openclaw/openclaw.json:ro
- /home/projekte_bao/openclaw/data/openclaw/workspace-iris:/mnt/workspace-iris
- /home/projekte_bao/openclaw/data/openclaw/workspace-programmer:/mnt/workspace-programmer
- /home/projekte_bao/openclaw/data/openclaw/workspace-reviewer:/mnt/workspace-reviewer
- /home/projekte_bao/openclaw/data/openclaw/workspace-architekt:/mnt/workspace-architekt
- /home/projekte_bao/openclaw/data/openclaw/workspace-researcher:/mnt/workspace-researcher
- /home/projekte_bao/openclaw/data/openclaw/workspace-executor:/mnt/workspace-executor
networks:
- nexus
- openclaw_default
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
web:
build:
context: ./frontend
restart: unless-stopped
deploy:
resources:
limits:
memory: 128M
reservations:
memory: 32M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
labels:
- "traefik.enable=true"
- "traefik.http.routers.nexus.rule=Host(`nexus.noveria.net`)"
- "traefik.http.routers.nexus.tls=true"
- "traefik.http.routers.nexus.tls.certresolver=letsencrypt"
- "traefik.http.services.nexus.loadbalancer.server.port=80"
ports:
- "127.0.0.1:18880:80"
depends_on:
api:
condition: service_started
restart: true
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:80/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
networks:
- nexus
- proxy
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
networks:
nexus:
openclaw_default:
external: true
proxy:
external: true
volumes:
nexus-postgres: