name: drivervault-aio # Production all-in-one — pulls the prebuilt image from the registry instead of # building. One container runs PocketBase + API Server + Web App (nginx). # Everything an operator needs to set lives in .env. # # 1. cp .env.prod.example .env (then edit it) # 2. docker compose -f docker-compose.prod.yml pull # 3. docker compose -f docker-compose.prod.yml up -d # # On first boot PocketBase upserts the superuser from PB_ADMIN_*, and the API # Server creates any missing collections and the DriverVault super-admin from # DRIVERVAULT_SUPERADMIN_*. Both steps are idempotent. services: drivervault: image: "${AIO_IMAGE:-10.2.1.10:5500/admin/drivervault-aio:latest}" container_name: drivervault-aio restart: unless-stopped environment: # Superuser (also used by the API Server to authenticate to PocketBase). PB_ADMIN_EMAIL: "${PB_ADMIN_EMAIL:?set PB_ADMIN_EMAIL in .env}" PB_ADMIN_PASSWORD: "${PB_ADMIN_PASSWORD:?set PB_ADMIN_PASSWORD in .env}" # Match CORS to the web origin (only used if a browser calls the API directly). CORS_ALLOW_ORIGINS: "${CORS_ALLOW_ORIGINS:-http://localhost:8090}" # Probed by the panel status page. nginx serves the Web App on port 80 # inside this container, so the default (localhost:8090) would never answer. WEBAPP_URL: "http://127.0.0.1:80" # Schema + super-admin bootstrap (idempotent). Leave this ON. A release can # add a collection the server needs — app_settings, holding the plugin # settings, is one — and a stack that skipped the bootstrap never gets it: # the plugin panel then answers 503 forever, because a missing collection # is read as "database not ready", never as "no plugins configured". # Turn it off only for a database you know already matches the release. PB_BOOTSTRAP: "${PB_BOOTSTRAP:-true}" DRIVERVAULT_SUPERADMIN_EMAIL: "${DRIVERVAULT_SUPERADMIN_EMAIL:-}" DRIVERVAULT_SUPERADMIN_PASSWORD: "${DRIVERVAULT_SUPERADMIN_PASSWORD:-}" DRIVERVAULT_SUPERADMIN_NAME: "${DRIVERVAULT_SUPERADMIN_NAME:-Administrator}" # OCPP charger control (Anker Solix). This image serves plain HTTP, so a # charger can only connect when TLS is terminated in front of it (set # OCPP_PUBLIC_URL to the public wss:// base) — or, on a trusted network, # with OCPP_REQUIRE_TLS=false. OCPP_REQUIRE_TLS: "${OCPP_REQUIRE_TLS:-true}" OCPP_PUBLIC_URL: "${OCPP_PUBLIC_URL:-}" ports: - "${WEB_PORT:-8090}:80" # Web App - "${PB_PORT:-8070}:8070" # PocketBase admin UI / API - "${API_PORT:-8080}:8080" # API Server + panel (root /) + /ocpp/{serial} volumes: # Named volumes by default; set PB_DATA / API_DATA to host paths in .env # for bind mounts. - "${PB_DATA:-pb_data}:/pb/pb_data" # The .env the panel writes back; plugin settings live in the database. - "${API_DATA:-api_data}:/data" healthcheck: # All three processes must answer. Declared here as well as in the image so # the check is visible, and works against an older pulled image. test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8070/api/health >/dev/null && wget -qO- http://127.0.0.1:8080/healthz >/dev/null && wget -qO- http://127.0.0.1:80/healthz >/dev/null || exit 1"] interval: 30s timeout: 5s retries: 3 start_period: 60s volumes: pb_data: api_data: