Messages Environment Variables
.env File
# Django
DJANGO_CONFIGURATION=Production
DJANGO_SECRET_KEY=<generate-50-char-random>
DJANGO_ALLOWED_HOSTS=messages.<domain>,api.messages.<domain>,backend,localhost,127.0.0.1
DJANGO_SETTINGS_MODULE=messages.settings
PYTHONPATH=/app
# Database
DB_HOST=postgresql
DB_NAME=messages
DB_USER=messages
DB_PASSWORD=<db-password>
DB_PORT=5432
# Redis / Celery
REDIS_URL=redis://redis:6379
CELERY_BROKER_URL=redis://redis:6379
# OpenSearch
OPENSEARCH_URL=["http://opensearch:9200"]
# Object storage (MinIO)
AWS_S3_ENDPOINT_URL=http://minio:9000
AWS_S3_ACCESS_KEY_ID=messages
AWS_S3_SECRET_ACCESS_KEY=<minio-password>
AWS_S3_SIGNATURE_VERSION=s3v4
AWS_STORAGE_BUCKET_NAME=messages-media
MEDIA_BASE_URL=https://s3.messages.<domain>
# Message imports storage
STORAGE_MESSAGE_IMPORTS_ENDPOINT_URL=http://minio:9000
STORAGE_MESSAGE_IMPORTS_BUCKET_NAME=msg-imports
STORAGE_MESSAGE_IMPORTS_ACCESS_KEY=messages
STORAGE_MESSAGE_IMPORTS_SECRET_KEY=<minio-password>
# Tiered blob storage
STORAGE_MESSAGE_BLOBS_ENDPOINT_URL=http://minio:9000
STORAGE_MESSAGE_BLOBS_BUCKET_NAME=msg-blobs
STORAGE_MESSAGE_BLOBS_ACCESS_KEY=messages
STORAGE_MESSAGE_BLOBS_SECRET_KEY=<minio-password>
# Static files
STORAGES_STATICFILES_BACKEND=django.contrib.staticfiles.storage.StaticFilesStorage
DJANGO_DATA_DIR=/data
# OIDC (Keycloak — messages realm)
OIDC_RP_CLIENT_ID=messages
OIDC_RP_CLIENT_SECRET=<oidc-client-secret>
OIDC_RP_SIGN_ALGO=RS256
OIDC_RP_SCOPES=openid email
OIDC_CREATE_USER=True
OIDC_OP_JWKS_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/certs
OIDC_OP_AUTHORIZATION_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/auth
OIDC_OP_TOKEN_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/token
OIDC_OP_USER_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/userinfo
OIDC_OP_LOGOUT_ENDPOINT=https://auth.messages.<domain>/realms/messages/protocol/openid-connect/logout
OIDC_REDIRECT_ALLOWED_HOSTS=["https://auth.messages.<domain>","https://messages.<domain>"]
OIDC_AUTH_REQUEST_EXTRA_PARAMS={}
OIDC_STORE_ID_TOKEN=True
OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION=True
OIDC_REDIRECT_REQUIRE_HTTPS=True
# Keycloak admin API (for mailbox/group management)
IDENTITY_PROVIDER=keycloak
KEYCLOAK_REALM=messages
KEYCLOAK_URL=https://auth.messages.<domain>
KEYCLOAK_CLIENT_ID=rest-api
KEYCLOAK_CLIENT_SECRET=<kc-rest-api-secret>
KEYCLOAK_GROUP_PATH_PREFIX=/maildomain-
# Login redirects
LOGIN_REDIRECT_URL=https://messages.<domain>
LOGIN_REDIRECT_URL_FAILURE=https://messages.<domain>
LOGOUT_REDIRECT_URL=https://messages.<domain>
ALLOW_LOGOUT_GET_METHOD=True
# Security
CSRF_TRUSTED_ORIGINS=["https://messages.<domain>","https://api.messages.<domain>"]
CORS_ALLOW_ALL_ORIGINS=False
CORS_ALLOWED_ORIGINS=["https://messages.<domain>"]
# Outbound mail (direct to Brevo relay)
MTA_OUT_MODE=relay
MTA_OUT_RELAY_HOST=smtp-relay.brevo.com:587
MTA_OUT_RELAY_USERNAME=<brevo-username>
MTA_OUT_RELAY_PASSWORD=<brevo-password>
MTA_OUT_SMTP_TLS_SECURITY_LEVEL=may
# Server-to-server API tokens (for Calendars integration)
DJANGO_SERVER_TO_SERVER_API_TOKENS=<api-token>
# MDA shared secret (backend ↔ mta-in)
MDA_API_SECRET=<mda-secret>
MDA_API_BASE_URL=http://backend:8000/api/v1.0/
# Salt
SALT_KEY=<random-salt>
# Email brand
DJANGO_EMAIL_BRAND_NAME=Messages
DJANGO_EMAIL_HOST=mta-out
DJANGO_EMAIL_PORT=587
# Frontend (Next.js)
NEXT_PUBLIC_API_ORIGIN=https://api.messages.<domain>
NEXT_TELEMETRY_DISABLED=1
NEXT_PUBLIC_DEFAULT_LANGUAGE=en-US
NEXT_PUBLIC_LANGUAGES=[["en-US","English"],["fr-FR","Français"]]
NEXT_PUBLIC_THEME_CONFIG={"theme":"white-label"}
FRONTEND_THEME=white-label
FRONTEND_SILENT_LOGIN_ENABLED=True
MESSAGES_FRONTEND_BACKEND_SERVER=172.29.0.10:8000
# AI features (disabled)
FEATURE_AI_SUMMARY=False
FEATURE_AI_AUTOLABELS=False
AI_BASE_URL=
AI_API_KEY=
AI_MODEL=
# Logging
LOGGING_LEVEL_HANDLERS_CONSOLE=INFO
LOGGING_LEVEL_LOGGERS_ROOT=INFO
LOGGING_LEVEL_LOGGERS_APP=INFO
Critical Settings
| Variable |
Why it matters |
DJANGO_ALLOWED_HOSTS |
Must include messages.<domain> — Caddy proxies with this Host header |
OIDC_CREATE_USER=True |
Auto-creates Messages users on first OIDC login |
DJANGO_SERVER_TO_SERVER_API_TOKENS |
Uses DJANGO_ prefix (django-configurations convention) |
FRONTEND_SILENT_LOGIN_ENABLED=True |
Skips ProConnect button, redirects directly to Keycloak |
MESSAGES_FRONTEND_BACKEND_SERVER=172.29.0.10:8000 |
Static IP — avoids Caddy DNS caching issues |
Generating Secrets
python3 -c "import secrets; print(secrets.token_hex(32))"