name: nexus services: postgres: image: postgres:17-alpine restart: always 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 args: NEXUS_VERSION: ${NEXUS_VERSION:-dev} NEXUS_GIT_SHA: ${NEXUS_GIT_SHA:-unknown} restart: always deploy: resources: limits: memory: 512M reservations: memory: 128M 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} Bootstrap__OwnerEmail: ${BOOTSTRAP_OWNER_EMAIL:?Set BOOTSTRAP_OWNER_EMAIL in .env} # Existing initialized databases do not need the bootstrap password again. # A fresh database still fails closed in EnsureDatabaseAsync when this is empty. Bootstrap__OwnerPassword: ${BOOTSTRAP_OWNER_PASSWORD:-} ForwardedHeaders__ForwardLimit: ${FORWARDED_HEADERS_FORWARD_LIMIT:-1} ForwardedHeaders__KnownProxies__0: ${FORWARDED_HEADERS_KNOWN_PROXY:-} ForwardedHeaders__KnownNetworks__0: ${FORWARDED_HEADERS_KNOWN_NETWORK:-} Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://openclaw-gateway:18789} Integrations__OpenClaw__RequiredVersion: ${OPENCLAW_REQUIRED_VERSION:-2026.7.1} Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-} Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-} GatewayConnector__DeviceStatePath: /var/lib/nexus/openclaw/device-state.json GatewayConnector__OperationAuditPath: /var/lib/nexus/openclaw/operation-audit.jsonl GatewayConnector__ClientId: nexus GatewayConnector__ClientMode: backend GatewayConnector__ExternalClientIdentitySupported: ${OPENCLAW_EXTERNAL_CLIENT_ID_SUPPORTED:-false} GatewayConnector__AllowReservedInternalClientIdentity: "false" GatewayConnector__TlsFingerprint: ${OPENCLAW_TLS_FINGERPRINT:-} OpenClawSetup__ExternalClientIdentitySupported: ${OPENCLAW_EXTERNAL_CLIENT_ID_SUPPORTED:-false} Integrations__OpenClaw__AllowCommandCron: ${OPENCLAW_ALLOW_COMMAND_CRON:-false} Admin__ResetToken: ${Admin__ResetToken:-} NexusApiKey: ${NEXUS_API_KEY:-} extra_hosts: - host.docker.internal:host-gateway depends_on: postgres: condition: service_healthy restart: true healthcheck: test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080/health/ready || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 15s volumes: - nexus-openclaw-device:/var/lib/nexus/openclaw networks: - nexus - openclaw_default logging: driver: "json-file" options: max-size: "10m" max-file: "3" web: build: context: ./frontend args: NEXUS_VERSION: ${NEXUS_VERSION:-dev} NEXUS_GIT_SHA: ${NEXUS_GIT_SHA:-unknown} restart: always deploy: resources: limits: memory: 128M reservations: memory: 32M 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_healthy 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: nexus-openclaw-device: