Configuration
Complete reference for all environment variables and configuration options.
Required Variables
These must be set for the application to function:
| Variable | Description | Example |
|---|---|---|
DATABASE_URL | PostgreSQL connection string | postgresql://user:pass@host:5432/dbname |
JWT_SECRET_KEY | JWT signing key for authentication | openssl rand -hex 32 |
FLASK_SECRET_KEY | Session encryption key (fallback for JWT if not set) | openssl rand -hex 32 |
In production, at least one of JWT_SECRET_KEY or FLASK_SECRET_KEY must be explicitly set. The application will fail to start otherwise to prevent insecure deployments.
Deployment Options
| Variable | Description | Default |
|---|---|---|
DEPLOYMENT_MODE | self-hosted or saas | self-hosted |
ENABLE_REGISTRATION | Allow public user registration | false |
REQUIRE_EMAIL_VERIFICATION | Require email verification for new users | false |
Telemetry
The telemetry service is enabled by default, but a new instance sends nothing until an account owner accepts the notice.
| Variable | Description | Default |
|---|---|---|
TELEMETRY_ENABLED | Enable the telemetry service for this instance | true |
TELEMETRY_URL | Receive telemetry submissions | https://app.billmanager.app/api/telemetry |
TELEMETRY_LOCAL_LOG_RETENTION_DAYS | Set the local telemetry-log retention period in days | 90 |
Set TELEMETRY_ENABLED=false to disable telemetry for the full instance. See Manage Telemetry for collected fields, consent, and local logs.
Telemetry is separate from the optional crash reporting and product analytics described below.
Crash Reporting (Optional)
BillManager can send server crash reports to a Sentry project that you control. Crash reporting is off unless you set SENTRY_DSN. BillManager has no built-in DSN, and this setting is independent of telemetry consent.
| Variable | Description | Default |
|---|---|---|
SENTRY_DSN | DSN of your Sentry project. Leave blank to disable crash reporting. | Unset |
SENTRY_ENVIRONMENT | Deployment label, such as production or staging | development |
SENTRY_RELEASE | Release label for reports | server-v<version> |
BillManager reports unhandled server request errors only. Each report keeps the exception type, stack frames from deployed code, the release and environment labels, the Python version, and the event time. The exception message is replaced with a fixed placeholder.
Reports never include request URLs, query strings, headers, cookies, request bodies, user or IP fields, Bill Group IDs, breadcrumbs, source code, or local variables. Tracing, profiling, sessions, and log forwarding are disabled. Sentry still sees the network address of your server when it receives a report.
Use a deployment label for SENTRY_ENVIRONMENT, never a person's name or account identifier. An invalid DSN disables crash reporting and logs a warning that does not repeat the value. To turn crash reporting off, remove SENTRY_DSN and restart BillManager.
Product Analytics (Optional)
The public ghcr.io/brdweb/billmanager images contain no product-analytics tracker. You don't need to do anything to keep analytics off.
To track product events in your own Umami instance, build a custom image with both of these Docker build arguments:
| Build Argument | Description |
|---|---|
VITE_UMAMI_SCRIPT_URL | Absolute HTTPS URL of your Umami tracker script |
VITE_UMAMI_WEBSITE_ID | Your Umami website UUID |
The build fails if you set only one value or if the script URL is not a valid HTTPS URL. BillManager adds only the tracker's origin to its Content Security Policy. Runtime environment variables cannot enable the tracker; rebuild the image to add, change, or remove it.
The tracker honors Do Not Track and does not send URL query strings or fragments (requires Umami 2.17 or newer). Events include actions such as creating a bill, recording a payment, sharing a bill, and exporting data. Event properties are limited to values such as the bill type, split mode, or export format; bill names and amounts are not sent.
Stripe Billing (SaaS Mode Only)
Self-hosted deployments do not use Stripe billing, even when Stripe variables are set. You can leave all STRIPE_* variables unset.
Billing is available only when DEPLOYMENT_MODE=saas and all of these values are set:
| Variable | Description |
|---|---|
STRIPE_SECRET_KEY | Stripe secret API key |
STRIPE_WEBHOOK_SECRET | Stripe webhook signing secret |
STRIPE_PRICE_PRO_MONTHLY | Stripe price ID for Pro monthly billing |
STRIPE_PRICE_PRO_ANNUAL | Stripe price ID for Pro annual billing |
If any required value is missing, checkout returns an error instead of falling back to another price. Keep the legacy STRIPE_PRICE_BASIC_* and STRIPE_PRICE_PLUS_* price IDs while older subscriptions still reference them. BillManager uses them only to grant Pro access to those subscriptions; they cannot be purchased.
Language, Currency, and Mobile Compatibility
| Variable | Description | Default |
|---|---|---|
DEFAULT_LOCALE | BCP 47 locale used for deployment-level number and date formatting | en-US |
MINIMUM_MOBILE_VERSION | Optional minimum compatible mobile client version advertised by the server | Unset |
OAUTH_REDIRECT_URIS | Additional comma-separated OAuth callback URIs, such as development-client or universal links | Unset |
Currency is now a per-user setting selected in the web or mobile Settings screen. New users begin with USD and may choose from USD, EUR, JPY, GBP, CNY, CHF, AUD, CAD, HKD, SGD, INR, KRW, SEK, NZD, and MXN.
DEFAULT_CURRENCY is no longer a runtime setting. During the upgrade that introduced personal currencies, existing users inherited its former value once; changing or retaining that environment variable afterward has no effect. Currency selection changes formatting and validation, not the numeric value of stored amounts.
Social Login (OAuth/OIDC)
Enable social sign-in providers and generic OIDC SSO.
| Variable | Description | Default |
|---|---|---|
OAUTH_AUTO_REGISTER | Auto-create users on first social login | true (self-hosted) |
OAUTH_GOOGLE_ENABLED | Enable Google login | false |
OAUTH_APPLE_ENABLED | Enable Apple login | false |
OAUTH_MICROSOFT_ENABLED | Enable Microsoft login | false |
OAUTH_OIDC_ENABLED | Enable generic OIDC login | false |
Provider-specific credentials and advanced OIDC claim mapping are documented in Social Login (OIDC).
Email Configuration
Required for user invitations, password resets, email verification, and email OTP.
| Variable | Description | Default |
|---|---|---|
EMAIL_PROVIDER | Outbound provider: smtp, resend, or none | Auto-detects Resend/SMTP config |
SMTP_HOST | SMTP server hostname | None |
SMTP_PORT | SMTP server port | 587 or 465 when SSL is enabled |
SMTP_USERNAME | SMTP username, optional for relays | None |
SMTP_PASSWORD | SMTP password, optional for relays | None |
SMTP_USE_TLS | Use STARTTLS | true unless SSL is enabled |
SMTP_USE_SSL | Use implicit SSL/TLS | false |
SMTP_TIMEOUT | SMTP connection timeout in seconds | 10 |
RESEND_API_KEY | Resend API key for Resend provider | None |
FROM_EMAIL | Sender email address | [email protected] |
APP_URL | Application URL for email links | http://localhost:5000 |
Without email configured, invitation emails, password reset emails, and email OTP codes cannot be sent. See Email Setup for SMTP and Resend examples.
CORS Configuration
Control which domains can access your BillManager API.
| Variable | Description | Default |
|---|---|---|
ALLOWED_ORIGINS | Comma-separated list of allowed origins | Uses APP_URL or localhost |
Priority Order
The application determines allowed CORS origins using this priority:
ALLOWED_ORIGINS- Explicit comma-separated list (recommended for multiple frontends)APP_URL- Single origin (typical for production)- Localhost defaults - Development only (
http://localhost:5173,http://localhost:5001,http://127.0.0.1:5173,http://127.0.0.1:5001)
Examples
Single production domain:
environment:
- APP_URL=https://bills.yourdomain.com
Multiple domains (e.g., mobile app + web):
environment:
- ALLOWED_ORIGINS=https://bills.yourdomain.com,https://app.yourdomain.com,https://mobile.yourdomain.com
Development (automatically uses localhost):
environment:
# No CORS configuration needed - automatically allows localhost
- DATABASE_URL=postgresql://...
- FLASK_SECRET_KEY=dev-key
- Use
ALLOWED_ORIGINSwhen you have multiple frontends (web app, mobile app, admin panel, etc.) - Use
APP_URLfor simple single-domain deployments - Don't set either for local development (localhost is allowed by default)
Social Login & Two-Factor Authentication
BillManager supports social login (Google, Apple, Microsoft, and generic OIDC providers) and two-factor authentication (email OTP, passkeys, recovery codes). All providers and 2FA are disabled by default.
For full setup instructions, see Social Login Setup.
Quick reference:
| Variable | Description | Default |
|---|---|---|
OAUTH_GOOGLE_ENABLED | Enable Google login | false |
OAUTH_APPLE_ENABLED | Enable Apple login | false |
OAUTH_MICROSOFT_ENABLED | Enable Microsoft login | false |
OAUTH_OIDC_ENABLED | Enable generic OIDC login | false |
OAUTH_OIDC_TOKEN_AUTH_METHOD | Generic OIDC token endpoint auth method | client_secret_post |
OAUTH_AUTO_REGISTER | Auto-create accounts for new social login users | true (self-hosted) |
ENABLE_2FA | Allow users to enable two-factor authentication | false |
ENABLE_PASSKEYS | Allow passkey/WebAuthn as a 2FA method | false |
WEBAUTHN_RP_ID | WebAuthn relying-party domain | Derived from APP_URL |
WEBAUTHN_RP_NAME | Name shown by passkey prompts | BillManager |
WEBAUTHN_ORIGIN | Exact web origin accepted for passkeys | APP_URL |
WEBAUTHN_ANDROID_ORIGINS | Comma-separated android:apk-key-hash: origins for trusted Android signing certificates | Unset |
Built-in Security Features
BillManager includes comprehensive security protections enabled by default:
| Feature | Description |
|---|---|
| JWT Authentication | Secure token-based authentication with access + refresh tokens |
| Rate Limiting | Tiered rate limits: 60/min for reads, 30/min for writes |
| Content Security Policy | Strict CSP headers prevent XSS and injection attacks |
| CORS Protection | Configurable allowed origins for API security |
| Input Validation | Server-side validation for all user inputs |
| Password Enforcement | Strong password requirements (8+ chars, mixed case, digit) |
| Two-Factor Authentication | Optional email OTP, passkeys, and recovery codes |
| Social Login | Sign in with Google, Apple, Microsoft, or generic OIDC |
| Row-Level Isolation | Complete data separation between user groups |
These security features are enabled automatically. No additional configuration is required.
Security Best Practices
1. Generate Strong Secrets
Always use cryptographically secure random values:
openssl rand -hex 32
2. Use Environment Files
Keep secrets out of docker-compose.yml:
services:
billmanager:
image: ghcr.io/brdweb/billmanager:latest
env_file:
- .env
Create a .env file (never commit this to version control):
DATABASE_URL=postgresql://billsuser:securepassword@db:5432/billmanager
FLASK_SECRET_KEY=abc123...
JWT_SECRET_KEY=def456...
EMAIL_PROVIDER=smtp
SMTP_HOST=smtp.example.com
SMTP_USERNAME=billmanager
SMTP_PASSWORD=...
3. Use Docker Secrets (Production)
For production deployments, consider using Docker secrets:
services:
billmanager:
secrets:
- flask_secret
- jwt_secret
environment:
- FLASK_SECRET_KEY_FILE=/run/secrets/flask_secret
- JWT_SECRET_KEY_FILE=/run/secrets/jwt_secret
secrets:
flask_secret:
file: ./secrets/flask_secret.txt
jwt_secret:
file: ./secrets/jwt_secret.txt
Example Configurations
Minimal (Development)
environment:
- DEPLOYMENT_MODE=self-hosted
- DATABASE_URL=postgresql://billsuser:password@db:5432/billmanager
- FLASK_SECRET_KEY=development-only-key
Production with SMTP Email
environment:
- DEPLOYMENT_MODE=self-hosted
- DATABASE_URL=postgresql://billsuser:${DB_PASSWORD}@db:5432/billmanager
- FLASK_SECRET_KEY=${FLASK_SECRET}
- JWT_SECRET_KEY=${JWT_SECRET}
- EMAIL_PROVIDER=smtp
- SMTP_HOST=smtp.example.com
- SMTP_PORT=587
- SMTP_USERNAME=${SMTP_USERNAME}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- SMTP_USE_TLS=true
- SMTP_USE_SSL=false
- APP_URL=https://bills.yourdomain.com
With Google Login and 2FA
environment:
- DEPLOYMENT_MODE=self-hosted
- DATABASE_URL=postgresql://billsuser:${DB_PASSWORD}@db:5432/billmanager
- FLASK_SECRET_KEY=${FLASK_SECRET}
- JWT_SECRET_KEY=${JWT_SECRET}
- EMAIL_PROVIDER=smtp
- SMTP_HOST=smtp.example.com
- SMTP_PORT=587
- SMTP_USERNAME=${SMTP_USERNAME}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- SMTP_USE_TLS=true
- APP_URL=https://bills.yourdomain.com
- OAUTH_GOOGLE_ENABLED=true
- OAUTH_GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- OAUTH_GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
- ENABLE_2FA=true
See Social Login Setup for detailed provider configuration and passkey setup.
With Public Registration
environment:
- DEPLOYMENT_MODE=self-hosted
- ENABLE_REGISTRATION=true
- REQUIRE_EMAIL_VERIFICATION=true
- EMAIL_PROVIDER=smtp
- SMTP_HOST=smtp.example.com
- SMTP_PORT=587
- SMTP_USERNAME=${SMTP_USERNAME}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- SMTP_USE_TLS=true
- APP_URL=https://bills.yourdomain.com