Environment Variables Reference
Environment variables configure your Frappe Docker setup. They can be set directly in the container or defined in a .env file referenced by Docker Compose.
Getting Started:
cp example.env .envThen edit .env and set variables according to your needs.
Required Variables
| Variable | Purpose | Example | Notes |
|---|---|---|---|
FRAPPE_PATH | Frappe framework path | https://github.com/frappe/frappe | |
FRAPPE_BRANCH | Frappe Branch | version-15 | See Frappe releases |
ERPNEXT_VERSION | ERPNext release version | v15.67.0 | Required although its never used |
DB_PASSWORD | Password for database root (MariaDB or Postgres) | secure_password_123 | Not needed if using DB_PASSWORD_SECRETS_FILE |
Database Configuration
| Variable | Purpose | Default | When to Set |
|---|---|---|---|
DB_PASSWORD | Database root user password | 123 | Always (unless using secrets file) |
DB_PASSWORD_SECRETS_FILE | Path to file containing database password | — | Setup mariadb-secrets overrider |
DB_HOST | Database hostname or IP | db (service name) | Only if using external database |
DB_PORT | Database port | 3306 (MariaDB) / 5432 (Postgres) | Only if using external database |
Redis Configuration
| Variable | Purpose | Default | When to Set |
|---|---|---|---|
REDIS_CACHE | Redis hostname for caching | redis-cache (service name) | Only if using external Redis instance |
REDIS_QUEUE | Redis hostname for job queues and real-time updates | redis-queue (service name) | Only if using external Redis instance |
Volume Bind Mounts
| Variable | Purpose | Default | When to Set |
|---|---|---|---|
SITES_DATA_LOCATION | Host directory for the sites volume; must be an absolute path and already exist | - | Required for compose.bind-mount-sites.yaml |
DB_DATA_LOCATION | Host directory for the db-data volume; must be an absolute path and already exist | - | Required for compose.bind-mount-db-data.yaml |
REDIS_QUEUE_DATA_LOCATION | Host directory for the redis-queue-data volume; must be an absolute path and already exist | - | Required for compose.bind-mount-redis-queue.yaml |
The host directory must exist before docker compose up -d and must be writable by the user the container runs as:
| Directory | Owner |
|---|---|
sites | uid/gid 1000 (the frappe user of the image) |
db-data | uid/gid 999 (the mariadb or postgres image) |
redis-queue-data | uid/gid 999 (the redis image) |
Warning: with a bind mount, the data lives on the host, not inside the Docker volume. Removing the volume (for example with
docker compose down -v) will not delete the data. To actually erase the data, delete the host directory manually withrm -r <data path>.
Example:
mkdir -p /srv/frappe/{sites,db-data,redis-queue-data}
chown 1000:1000 /srv/frappe/sites
chown 999:999 /srv/frappe/db-data /srv/frappe/redis-queue-dataSITES_DATA_LOCATION=/srv/frappe/sites
DB_DATA_LOCATION=/srv/frappe/db-data
REDIS_QUEUE_DATA_LOCATION=/srv/frappe/redis-queue-dataReverse Proxy and SSL (HTTPS) Configuration
Traefik (compose.proxy.yaml / compose.https.yaml)
| Variable | Purpose | Default | When to Set |
|---|---|---|---|
LETSENCRYPT_EMAIL | Email for Let's Encrypt certificate registration | - | Required for compose.https.yaml |
SITES_RULE | Domains for routing (Traefik rule expression) | - | Required for Traefik routing/HTTPS overrides |
Format for SITES_RULE:
# Single site
SITES_RULE=Host(`mysite.example.com`)
# Multiple sites
SITES_RULE=Host(`a.example.com`) || Host(`b.example.com`)Note: The Traefik v3 migration is complete. Use
SITES_RULEas a full v3 rule expression;SITESis deprecated. Rule syntax now defaults to v3, so nocore.defaultRuleSyntaxor per-routerruleSyntaxsettings are required.
nginx-proxy + acme-companion (compose.nginxproxy*.yaml)
| Variable | Purpose | Default | When to Set |
|---|---|---|---|
LETSENCRYPT_EMAIL | Email for Let's Encrypt certificate | - | Required for compose.nginxproxy-ssl.yaml |
NGINX_PROXY_HOSTS | Comma-separated hostnames for nginx-proxy | - | Required for compose.nginxproxy*.yaml |
Example:
NGINX_PROXY_HOSTS=example.com,www.example.comNote: Automatic certificates require port 80 to be reachable (HTTP-01).
Published Ports (Traefik and nginx-proxy)
| Variable | Purpose | Default | When to Set |
|---|---|---|---|
HTTP_PUBLISH_PORT | Published HTTP port | 80 (proxy) / 8080 (noproxy) | Change if port is in use |
HTTPS_PUBLISH_PORT | Published HTTPS port | 443 | Change if port 443 is in use |
Site Configuration
| Variable | Purpose | Default | When to Set |
|---|---|---|---|
FRAPPE_SITE_NAME_HEADER | Site name for multi-tenant setup | $host (resolved from request hostname) | When accessing by IP or need explicit site name |
Examples:
If your site is named mysite but you want to access it via 127.0.0.1:
FRAPPE_SITE_NAME_HEADER=mysiteIf your site is named example.com and you access it via that domain, no need to set this (defaults to hostname).
Image Configuration
| Variable | Purpose | Default | Notes |
|---|---|---|---|
CUSTOM_IMAGE | Custom Docker image repository | Frappe official image | Leave empty to use default |
CUSTOM_TAG | Custom Docker image tag | Latest stable | Corresponds to FRAPPE_VERSION |
PULL_POLICY | Image pull behavior | always | Options: always, never, if-not-present |
RESTART_POLICY | Container restart behavior | unless-stopped | Options: no, always, unless-stopped, on-failure |
Backend (Gunicorn) Configuration
| Variable | Purpose | Default | When to Set / Allowed Values |
|---|---|---|---|
GUNICORN_WORKERS | Number of worker processes handling web requests | 2 | Scale up for multi-core CPUs. Formula: (2 x Cores) + 1 |
GUNICORN_THREADS | Number of concurrent threads per worker process | 4 | Increase to handle more simultaneous I/O-bound requests without high memory cost |
GUNICORN_TIMEOUT | Max time a worker can spend on a single request before restart | 120 | Increase if long-running reports or data imports time out |
Frontend Nginx Configuration (inside the frontend container)
| Variable | Purpose | Default | Allowed Values |
|---|---|---|---|
NGINX_LISTEN_PORT | Sets the listen directive | 8080 | {port} |
BACKEND | Backend service address and port | 0.0.0.0:8000 | {host}:{port} |
SOCKETIO | Socket.IO service address and port | 0.0.0.0:9000 | {host}:{port} |
PROXY_READ_TIMEOUT | Upstream request timeout | 120s | Any nginx timeout value (e.g., 300s, 5m) |
CLIENT_MAX_BODY_SIZE | Maximum upload file size | 50m | Any nginx size value (e.g., 100m, 1g) |
Real IP Configuration (Behind Proxy)
Use these variables when running behind a reverse proxy or load balancer:
| Variable | Purpose | Default |
|---|---|---|
UPSTREAM_REAL_IP_ADDRESS | Trusted upstream IP address for real IP detection | 127.0.0.1 |
UPSTREAM_REAL_IP_HEADER | Request header containing client IP | X-Forwarded-For |
UPSTREAM_REAL_IP_RECURSIVE | Enable recursive IP search | off |
Migration Service
| Variable | Purpose | Default | Allowed Values |
|---|---|---|---|
MIGRATE_SITES | Switch auto migration on or off | true - auto migration on | true , false |
