services: bill-tracker: image: dream.scheller.ltd/null/billtracker:latest container_name: bill-tracker ports: - "3030:3000" environment: # First-run admin bootstrap: set INIT_ADMIN_USER/INIT_ADMIN_PASS here ONLY # for the very first start (with a strong password), then remove them. Do # not ship a real deployment with a default password. # Set the at-rest secrets key OUTSIDE the database (SimpleFIN token, OIDC # secret, SMTP password). Without it the app stores an auto-key in the DB # next to the ciphertext — anyone with DB/backup read access can decrypt. # Generate: node -e "console.log(require('crypto').randomBytes(48).toString('hex'))" # TOKEN_ENCRYPTION_KEY: "replace-with-a-long-random-string" # Behind a reverse proxy (Portainer/Traefik/nginx): trust it so req.secure # (Secure cookies) and req.ip (rate limits, audit + login history) are correct. TRUST_PROXY: "true" # CSRF cookie httpOnly (default: true). The SPA reads the token from # GET /api/auth/csrf-token into memory, so it never needs JS cookie access — # keep true to keep the token off the XSS-accessible surface. CSRF_HTTP_ONLY: "true" # CSRF Cookie sameSite setting (default: strict) # Set CSRF_SAME_SITE=lax for SPA cross-site scenarios CSRF_SAME_SITE: "strict" # CSRF Cookie secure flag (default: true - HTTPS only) # Set CSRF_SECURE=false for HTTP development (NOT recommended for production) CSRF_SECURE: "true" # CSRF Cookie name (default: bt_csrf_token) # Use CSRF_COOKIE_NAME to customize for multi-app deployments CSRF_COOKIE_NAME: "bt_csrf_token" volumes: - /portainer/hosting/bill-tracker/data:/data restart: unless-stopped