All checks were successful
- Prometheus alert rules (host, container, API, Celery, target-down) - Alertmanager with email routing (critical 1h, warning 4h repeat) - Docker network segmentation (frontend/backend/monitoring) - Incident response runbook with 8 copy-paste runbooks - Environment variables reference (55+ vars documented) - Hetzner setup docs updated with Steps 19-24 - Launch readiness updated with Feb 2026 infrastructure status Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
378 lines
14 KiB
Markdown
378 lines
14 KiB
Markdown
# Environment Variables Reference
|
|
|
|
All configuration for the Orion platform is managed through environment variables, loaded
|
|
via Pydantic Settings from an `.env` file or the process environment. This page provides a
|
|
complete reference for every variable recognised by `app/core/config.py`.
|
|
|
|
Variables are read at startup and exposed through the `settings` singleton. In most cases
|
|
the defaults are tuned for local development; production deployments **must** override the
|
|
security-sensitive values listed in the [Production Checklist](#production-checklist) at the
|
|
bottom of this page.
|
|
|
|
---
|
|
|
|
## Core / Project
|
|
|
|
Metadata used in the OpenAPI schema and health endpoints.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `PROJECT_NAME` | Display name shown in API docs and health responses | `Orion - Multi-Store Marketplace Platform` | No |
|
|
| `VERSION` | Semantic version reported by the platform | `2.2.0` | No |
|
|
|
|
---
|
|
|
|
## Database
|
|
|
|
!!! danger "Production requirement"
|
|
You **must** set `DATABASE_URL` to a real PostgreSQL connection string in every
|
|
non-development environment. The default value contains a placeholder password and
|
|
should never be used in production.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `DATABASE_URL` | PostgreSQL connection string (`postgresql://user:pass@host:port/db`) | `postgresql://orion_user:secure_password@localhost:5432/orion_db` | **Yes** |
|
|
|
|
---
|
|
|
|
## Admin Initialisation
|
|
|
|
Used by `init_production.py` and the database seeder to create the initial platform
|
|
administrator account.
|
|
|
|
!!! warning "Change the default password"
|
|
The default `ADMIN_PASSWORD` is `admin123`. The production validation check will emit a
|
|
warning if this value is left unchanged.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `ADMIN_EMAIL` | Email address for the initial admin account | `admin@orion.lu` | No |
|
|
| `ADMIN_USERNAME` | Username for the initial admin account | `admin` | No |
|
|
| `ADMIN_PASSWORD` | Password for the initial admin account | `admin123` | No (but **must change** in production) |
|
|
| `ADMIN_FIRST_NAME` | First name of the admin user | `Platform` | No |
|
|
| `ADMIN_LAST_NAME` | Last name of the admin user | `Administrator` | No |
|
|
|
|
---
|
|
|
|
## JWT Authentication
|
|
|
|
Controls JSON Web Token generation and expiry.
|
|
|
|
!!! danger "Production requirement"
|
|
`JWT_SECRET_KEY` **must** be replaced with a strong random value. Generate one with:
|
|
|
|
```bash
|
|
openssl rand -hex 32
|
|
```
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `JWT_SECRET_KEY` | Secret used to sign and verify JWTs | `change-this-in-production` | **Yes** |
|
|
| `JWT_EXPIRE_HOURS` | Hours component of the token lifetime | `24` | No |
|
|
| `JWT_EXPIRE_MINUTES` | Minutes component of the token lifetime | `30` | No |
|
|
|
|
---
|
|
|
|
## API Server
|
|
|
|
Settings passed to Uvicorn when the application starts.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `API_HOST` | Bind address for the API server | `0.0.0.0` | No |
|
|
| `API_PORT` | Port the API server listens on | `8000` | No |
|
|
| `DEBUG` | Enable debug mode (extra logging, auto-reload) | `True` | No (set `False` in production) |
|
|
|
|
---
|
|
|
|
## Documentation
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `DOCUMENTATION_URL` | URL where the MkDocs site is served | `http://localhost:8001` | No |
|
|
|
|
---
|
|
|
|
## Security / Middleware
|
|
|
|
!!! warning "Restrict allowed hosts"
|
|
The default `ALLOWED_HOSTS` value of `["*"]` accepts requests with any `Host` header.
|
|
In production, restrict this to your actual domain names.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `ALLOWED_HOSTS` | JSON list of permitted `Host` header values | `["*"]` | No (but **restrict** in production) |
|
|
| `RATE_LIMIT_ENABLED` | Enable request rate limiting | `True` | No |
|
|
| `RATE_LIMIT_REQUESTS` | Maximum number of requests per window | `100` | No |
|
|
| `RATE_LIMIT_WINDOW` | Rate limit window duration in seconds | `3600` | No |
|
|
|
|
---
|
|
|
|
## Logging
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `LOG_LEVEL` | Python log level (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`) | `INFO` | No |
|
|
| `LOG_FILE` | Path to a log file; `None` means stdout only | `None` | No |
|
|
|
|
---
|
|
|
|
## Platform Domain
|
|
|
|
Controls the base domain for store subdomains and custom-domain features.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `PLATFORM_DOMAIN` | Root domain under which store subdomains are created | `wizard.lu` | No |
|
|
| `ALLOW_CUSTOM_DOMAINS` | Allow stores to use their own domain names | `True` | No |
|
|
| `REQUIRE_DOMAIN_VERIFICATION` | Require DNS verification before activating a custom domain | `True` | No |
|
|
| `SSL_PROVIDER` | SSL certificate provider (`letsencrypt`, `cloudflare`, `manual`) | `letsencrypt` | No |
|
|
| `AUTO_PROVISION_SSL` | Automatically provision SSL certificates for custom domains | `False` | No |
|
|
| `DNS_VERIFICATION_PREFIX` | TXT record prefix used for domain ownership verification | `_orion-verify` | No |
|
|
| `DNS_VERIFICATION_TTL` | TTL in seconds for DNS verification records | `3600` | No |
|
|
|
|
---
|
|
|
|
## Platform Limits
|
|
|
|
Guard-rails for multi-tenant resource usage.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `MAX_STORES_PER_USER` | Maximum number of stores a single user can own | `5` | No |
|
|
| `MAX_TEAM_MEMBERS_PER_STORE` | Maximum team members allowed per store | `50` | No |
|
|
| `INVITATION_EXPIRY_DAYS` | Days before a team invitation link expires | `7` | No |
|
|
|
|
---
|
|
|
|
## Stripe Billing
|
|
|
|
!!! info "Required for payments"
|
|
All three Stripe keys must be set to enable subscription billing and payment
|
|
processing. Obtain them from the [Stripe Dashboard](https://dashboard.stripe.com/apikeys).
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `STRIPE_SECRET_KEY` | Stripe secret API key | `""` (empty) | Yes (for payments) |
|
|
| `STRIPE_PUBLISHABLE_KEY` | Stripe publishable API key | `""` (empty) | Yes (for payments) |
|
|
| `STRIPE_WEBHOOK_SECRET` | Stripe webhook signing secret | `""` (empty) | Yes (for payments) |
|
|
| `STRIPE_TRIAL_DAYS` | Length of the free trial period in days | `30` | No |
|
|
|
|
---
|
|
|
|
## Email Configuration
|
|
|
|
Orion supports multiple email providers. Set `EMAIL_PROVIDER` to choose one, then
|
|
configure the matching provider-specific variables below.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `EMAIL_PROVIDER` | Email transport backend (`smtp`, `sendgrid`, `mailgun`, `ses`) | `smtp` | No |
|
|
| `EMAIL_FROM_ADDRESS` | Sender address for outgoing emails | `noreply@orion.lu` | No |
|
|
| `EMAIL_FROM_NAME` | Sender display name | `Orion` | No |
|
|
| `EMAIL_REPLY_TO` | Optional reply-to address | `""` (empty) | No |
|
|
| `EMAIL_ENABLED` | Master switch to enable/disable all outgoing email | `True` | No |
|
|
| `EMAIL_DEBUG` | Log emails to console instead of sending (development only) | `False` | No |
|
|
|
|
### SMTP Settings
|
|
|
|
Used when `EMAIL_PROVIDER=smtp`.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `SMTP_HOST` | SMTP server hostname | `localhost` | No |
|
|
| `SMTP_PORT` | SMTP server port | `587` | No |
|
|
| `SMTP_USER` | SMTP authentication username | `""` (empty) | No |
|
|
| `SMTP_PASSWORD` | SMTP authentication password | `""` (empty) | No |
|
|
| `SMTP_USE_TLS` | Use STARTTLS (port 587) | `True` | No |
|
|
| `SMTP_USE_SSL` | Use implicit SSL (port 465) | `False` | No |
|
|
|
|
### SendGrid Settings
|
|
|
|
Used when `EMAIL_PROVIDER=sendgrid`.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `SENDGRID_API_KEY` | SendGrid API key | `""` (empty) | Yes (if using SendGrid) |
|
|
|
|
### Mailgun Settings
|
|
|
|
Used when `EMAIL_PROVIDER=mailgun`.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `MAILGUN_API_KEY` | Mailgun API key | `""` (empty) | Yes (if using Mailgun) |
|
|
| `MAILGUN_DOMAIN` | Mailgun sending domain | `""` (empty) | Yes (if using Mailgun) |
|
|
|
|
### Amazon SES Settings
|
|
|
|
Used when `EMAIL_PROVIDER=ses`.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `AWS_ACCESS_KEY_ID` | AWS access key for SES | `""` (empty) | Yes (if using SES) |
|
|
| `AWS_SECRET_ACCESS_KEY` | AWS secret key for SES | `""` (empty) | Yes (if using SES) |
|
|
| `AWS_REGION` | AWS region for the SES endpoint | `eu-west-1` | No |
|
|
|
|
---
|
|
|
|
## Storefront Defaults
|
|
|
|
Default locale and currency applied to new storefronts. Individual stores can override
|
|
these through the admin interface or the `AdminSetting` database table.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `DEFAULT_STOREFRONT_LOCALE` | Locale code for currency and number formatting | `fr-LU` | No |
|
|
| `DEFAULT_CURRENCY` | ISO 4217 currency code | `EUR` | No |
|
|
|
|
---
|
|
|
|
## Seed Data
|
|
|
|
Controls the volume of demo data generated by the database seeder.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `SEED_DEMO_STORES` | Number of demo stores to create | `3` | No |
|
|
| `SEED_CUSTOMERS_PER_STORE` | Number of demo customers per store | `15` | No |
|
|
| `SEED_PRODUCTS_PER_STORE` | Number of demo products per store | `20` | No |
|
|
| `SEED_ORDERS_PER_STORE` | Number of demo orders per store | `10` | No |
|
|
|
|
---
|
|
|
|
## Celery / Redis
|
|
|
|
Background task processing. When `USE_CELERY` is `False`, tasks fall back to FastAPI's
|
|
built-in `BackgroundTasks`.
|
|
|
|
!!! tip "Enable Celery in production"
|
|
Set `USE_CELERY=True` and ensure a Redis instance is reachable at `REDIS_URL` for
|
|
reliable background task processing.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `REDIS_URL` | Redis connection string used as Celery broker and result backend | `redis://localhost:6379/0` | No |
|
|
| `USE_CELERY` | Use Celery for background tasks instead of FastAPI BackgroundTasks | `False` | No (set `True` in production) |
|
|
| `FLOWER_URL` | URL of the Flower monitoring dashboard | `http://localhost:5555` | No |
|
|
| `FLOWER_PASSWORD` | Password for Flower authentication | `changeme` | No (but **change** in production) |
|
|
|
|
---
|
|
|
|
## Sentry
|
|
|
|
Error tracking and performance monitoring via [Sentry](https://sentry.io).
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `SENTRY_DSN` | Sentry Data Source Name; `None` disables Sentry | `None` | No |
|
|
| `SENTRY_ENVIRONMENT` | Environment tag sent with events (`development`, `staging`, `production`) | `development` | No |
|
|
| `SENTRY_TRACES_SAMPLE_RATE` | Fraction of transactions sampled for performance monitoring (0.0--1.0) | `0.1` | No |
|
|
|
|
---
|
|
|
|
## Monitoring
|
|
|
|
Prometheus metrics and Grafana dashboard integration.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `ENABLE_METRICS` | Expose a `/metrics` endpoint for Prometheus scraping | `False` | No (set `True` in production) |
|
|
| `GRAFANA_URL` | URL of the Grafana instance | `https://grafana.wizard.lu` | No |
|
|
| `GRAFANA_ADMIN_USER` | Grafana admin username | `admin` | No |
|
|
| `GRAFANA_ADMIN_PASSWORD` | Grafana admin password | `""` (empty) | No |
|
|
|
|
---
|
|
|
|
## Cloudflare R2 Storage
|
|
|
|
Object storage for media uploads. When `STORAGE_BACKEND` is `local`, files are stored on
|
|
the server filesystem.
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `STORAGE_BACKEND` | Storage backend to use (`local` or `r2`) | `local` | No |
|
|
| `R2_ACCOUNT_ID` | Cloudflare account ID | `None` | Yes (if using R2) |
|
|
| `R2_ACCESS_KEY_ID` | R2 API access key | `None` | Yes (if using R2) |
|
|
| `R2_SECRET_ACCESS_KEY` | R2 API secret key | `None` | Yes (if using R2) |
|
|
| `R2_BUCKET_NAME` | R2 bucket name | `orion-media` | No |
|
|
| `R2_PUBLIC_URL` | Custom public URL for media access (e.g. `https://media.yoursite.com`) | `None` | No |
|
|
|
|
---
|
|
|
|
## Cloudflare CDN / Proxy
|
|
|
|
| Variable | Description | Default | Required |
|
|
|---|---|---|---|
|
|
| `CLOUDFLARE_ENABLED` | Set to `True` when the application sits behind Cloudflare proxy (adjusts trusted-proxy headers) | `False` | No (set `True` when proxied) |
|
|
|
|
---
|
|
|
|
## Production Checklist
|
|
|
|
Before deploying to production, ensure the following variables are set correctly. Items
|
|
marked **critical** will trigger a startup warning if left at their default values.
|
|
|
|
!!! danger "Critical -- must change"
|
|
- [x] `DATABASE_URL` -- point to a production PostgreSQL instance
|
|
- [x] `JWT_SECRET_KEY` -- generate with `openssl rand -hex 32`
|
|
- [x] `ADMIN_PASSWORD` -- choose a strong, unique password
|
|
- [x] `DEBUG` -- set to `False`
|
|
- [x] `ALLOWED_HOSTS` -- restrict to your domain(s)
|
|
|
|
!!! warning "Strongly recommended"
|
|
- [x] `USE_CELERY` -- set to `True` with a production Redis instance
|
|
- [x] `FLOWER_PASSWORD` -- change from the default `changeme`
|
|
- [x] `ENABLE_METRICS` -- set to `True` for observability
|
|
- [x] `SENTRY_DSN` -- configure for error tracking
|
|
- [x] `SENTRY_ENVIRONMENT` -- set to `production`
|
|
- [x] `STORAGE_BACKEND` -- set to `r2` for scalable media storage
|
|
- [x] `CLOUDFLARE_ENABLED` -- set to `True` if behind Cloudflare proxy
|
|
|
|
!!! info "Required for specific features"
|
|
- [x] **Payments:** `STRIPE_SECRET_KEY`, `STRIPE_PUBLISHABLE_KEY`, `STRIPE_WEBHOOK_SECRET`
|
|
- [x] **Email (SendGrid):** `SENDGRID_API_KEY`
|
|
- [x] **Email (Mailgun):** `MAILGUN_API_KEY`, `MAILGUN_DOMAIN`
|
|
- [x] **Email (SES):** `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`
|
|
- [x] **R2 Storage:** `R2_ACCOUNT_ID`, `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`
|
|
|
|
### Example `.env` file (production)
|
|
|
|
```bash
|
|
# Core
|
|
DATABASE_URL=postgresql://orion:STRONG_PASSWORD@db.internal:5432/orion
|
|
JWT_SECRET_KEY=a]3f...your-random-hex-here...9c2b
|
|
DEBUG=False
|
|
ALLOWED_HOSTS=["wizard.lu","*.wizard.lu"]
|
|
|
|
# Admin
|
|
ADMIN_PASSWORD=your-strong-admin-password
|
|
|
|
# Celery / Redis
|
|
REDIS_URL=redis://redis.internal:6379/0
|
|
USE_CELERY=True
|
|
FLOWER_PASSWORD=a-secure-flower-password
|
|
|
|
# Stripe
|
|
STRIPE_SECRET_KEY=sk_live_...
|
|
STRIPE_PUBLISHABLE_KEY=pk_live_...
|
|
STRIPE_WEBHOOK_SECRET=whsec_...
|
|
|
|
# Email (example: SendGrid)
|
|
EMAIL_PROVIDER=sendgrid
|
|
SENDGRID_API_KEY=SG....
|
|
|
|
# R2 Storage
|
|
STORAGE_BACKEND=r2
|
|
R2_ACCOUNT_ID=your-account-id
|
|
R2_ACCESS_KEY_ID=your-access-key
|
|
R2_SECRET_ACCESS_KEY=your-secret-key
|
|
R2_PUBLIC_URL=https://media.wizard.lu
|
|
|
|
# Monitoring
|
|
ENABLE_METRICS=True
|
|
SENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0
|
|
SENTRY_ENVIRONMENT=production
|
|
CLOUDFLARE_ENABLED=True
|
|
```
|