f95463ef50
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.
146 lines
4.4 KiB
YAML
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:
|