# MeterVault self-host stack: the Blazor app + TimescaleDB. # docker compose -f deploy/docker-compose.yml up -d # Secrets are supplied via environment variables (Section__Key double-underscore mapping) # with ${VAR:-default} fallbacks — never baked into the image. services: db: image: timescale/timescaledb:2.17.2-pg16 environment: POSTGRES_DB: metervault POSTGRES_USER: metervault POSTGRES_PASSWORD: ${METERVAULT_DB_PASSWORD:-metervault} volumes: - metervault_db:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U metervault -d metervault"] interval: 10s timeout: 5s retries: 10 restart: unless-stopped app: build: context: .. dockerfile: deploy/Dockerfile image: ${METERVAULT_IMAGE:-metervault/metervault:local} depends_on: db: condition: service_healthy environment: ConnectionStrings__Default: "Host=db;Port=5432;Database=metervault;Username=metervault;Password=${METERVAULT_DB_PASSWORD:-metervault}" ASPNETCORE_ENVIRONMENT: Production MeterVault__TimeZone: ${METERVAULT_TIMEZONE:-Europe/Berlin} MeterVault__Currency: ${METERVAULT_CURRENCY:-EUR} MeterVault__Locale: ${METERVAULT_LOCALE:-en} # REST API is closed by default. Set a key to enable it (or AllowAnonymousApi on a trusted LAN): # MeterVault__ApiKeys__0: your-secret-key # MeterVault__AllowAnonymousApi: "true" ports: - "${METERVAULT_PORT:-8080}:8080" healthcheck: test: ["CMD-SHELL", "curl -fsS http://localhost:8080/healthz || exit 1"] interval: 15s timeout: 5s retries: 5 start_period: 30s restart: unless-stopped volumes: metervault_db: