Every environment variable RedScribe reads, grouped by area, with its purpose and default.
All configuration is via environment variables, normally set in .env
(copied from .env.example). This page is the complete, authoritative list.
For the reasoning behind the encryption, audit, and backup groups
specifically, see Encryption model, Audit
log, and Backup & restore.
This page is just the “what,” and those are the “why.”
Which settings module to run, config.settings.dev or config.settings.prod. See Configuration.
config.settings.dev
DJANGO_SECRET_KEY
Secret. Session/CSRF signing key. Generate a random 50-char value; never reuse the placeholder. Under Docker Compose, delivered as a file-based secret by default (secrets/django_secret_key.txt) — see the tip above.
change-me-to-a-random-50-char-value
DJANGO_DEBUG
Django debug mode: verbose error pages, no static file caching. Never enable in a real deployment.
true
DJANGO_ALLOWED_HOSTS
Comma-separated hostnames Django will serve; must include whatever NGINX_SERVER_NAME is set to.
localhost,127.0.0.1
REDSCRIBE_ALLOW_DEBUG_IN_PROD
Explicit opt-in escape hatch: config.settings.prod normally refuses to start at all with DJANGO_DEBUG=true. Set to 1 only for a specific debugging session, never leave it set. See Local development.
(unset)
DJANGO_LOG_LEVEL
Log level for Django’s root, django, and django.request/django.security loggers (console output).
docker-compose.yml caps each service’s memory and CPU. Defaults match
the “Solo” tier from Requirements & sizing
— the documented floor for “just trying it out”. Docker’s own cpus:
refuses to start a container at all if the value exceeds the host’s
actual CPU count, so the shipped default has to work unmodified on that
floor, not just on a beefier host; raise these for a bigger tier, or set
them very high to effectively remove the cap.
Variable
Purpose
Default
WEB_MEM_LIMIT
Memory cap for the web container. Gets the larger share, since report export (WeasyPrint/docxtpl) is the most memory-hungry thing this app does.
Secret. Database password. Set this to something of your own choosing. Under Docker Compose, delivered as a file-based secret by default (secrets/postgres_password.txt) — see the tip above.
change-me
POSTGRES_HOST
Database hostname: db under Docker Compose, localhost for Method 4.
db
POSTGRES_PORT
Database port.
5432
POSTGRES_SSLMODE
TLS mode for the Postgres connection (prefer, require, verify-ca, verify-full, …). The shipped default is safe for the same-host Docker Compose topology, where db and web only ever talk over the Docker-internal network, but prefer silently allows a plaintext fallback and never validates the server certificate. Set this to verify-full if POSTGRES_HOST ever points at a separate host.
prefer
POSTGRES_SSLROOTCERT
Path to a CA certificate file to validate the Postgres server’s certificate against. Only meaningful alongside verify-ca/verify-full.
Secret. Instance root key wrapping every engagement’s own per-project data key. Generate with python manage.py generate_root_key. Required in production, since config.settings.prod refuses to start without it. Under Docker Compose this is mounted as a Docker secret from secrets/root_key.txt instead, and this var is left unset; only set it directly for a non-Docker/bare-metal run or CI. Never commit the real value.
"google", "microsoft", or empty for local-auth-only.
(empty)
OAUTH_ALLOWED_DOMAIN
The single email domain OAuth sign-in is locked to. Required whenever OAUTH_PROVIDER is set. RedScribe is single-tenant per instance, so anyone authenticating with a valid provider account outside this domain is rejected before an account is created.
(unset)
SESSION_IDLE_TIMEOUT_SECONDS
Signs a session out after this many seconds of no requests, automatic-logoff behavior, distinct from the session’s fixed 4-hour cap (SESSION_COOKIE_AGE, not separately configurable).
1800 (30 min)
LOCKOUT_THRESHOLD
Failed login attempts before an account is locked out.
5
LOCKOUT_DURATION_SECONDS
How long a lockout lasts, in seconds.
86400 (24h)
IP_LOCKOUT_THRESHOLD
Failed login attempts from one source IP before that address is locked out, independent of which usernames it tried. Higher than LOCKOUT_THRESHOLD so shared/NAT’d networks aren’t locked out too easily. See Per-IP lockout.
20
IP_LOCKOUT_DURATION_SECONDS
Base per-IP lockout window. Doubles with each further threshold’s worth of failures from that address, up to the cap below.
3600 (1h)
IP_LOCKOUT_MAX_DURATION_SECONDS
Upper bound the escalating per-IP lockout window never exceeds.
86400 (24h)
SUPERADMIN_RATE_LIMIT_WINDOW_SECONDS
Rate-limit window for Superadmin-sensitive actions.
60
SUPERADMIN_RATE_LIMIT_MAX_ATTEMPTS
Max attempts allowed within that window.
10
MFA_THROTTLE_MAX_ATTEMPTS
Wrong TOTP codes allowed within the throttle window, separate from login lockout above. Not listed in .env.example, since the default rarely needs changing. See Authentication & sessions.
Checks new passwords against Have I Been Pwned’s breach corpus (a k-anonymity API, so only a 5-char hash prefix ever leaves the instance). Set to false for air-gapped deployments with no outbound internet access.
Only required when OAUTH_PROVIDER selects that provider.
Variable
Purpose
Default
GOOGLE_OAUTH_CLIENT_ID
Required only when OAUTH_PROVIDER=google. Create at console.cloud.google.com/apis/credentials: an OAuth 2.0 Client ID of type “Web application,” with an authorized redirect URI of https://<your-domain>/accounts/social/google/login/callback/.
(unset)
GOOGLE_OAUTH_CLIENT_SECRET
Secret. Paired secret for the above. File-based delivery available (see the tip above); not mounted by default since OAuth is opt-in.
(unset)
MICROSOFT_OAUTH_CLIENT_ID
Required only when OAUTH_PROVIDER=microsoft. Create at entra.microsoft.com under App registrations, with a redirect URI of https://<your-domain>/accounts/social/microsoft/login/callback/.
(unset)
MICROSOFT_OAUTH_CLIENT_SECRET
Secret. Paired secret for the above. File-based delivery available (see the tip above); not mounted by default since OAuth is opt-in.
(unset)
MICROSOFT_OAUTH_TENANT_ID
Leave as organizations unless the consultancy needs a specific Entra ID tenant restricted at the login-screen level too, in which case set it to that tenant’s ID. This is a stricter belt-and-braces measure alongside OAUTH_ALLOWED_DOMAIN, not a replacement for it.
Password reset links and change notifications. Leave EMAIL_HOST blank to
use the console backend (emails printed to the app log), which is fine for
local/dev, but not for production.
Variable
Purpose
Default
EMAIL_HOST
SMTP host.
(empty, console backend)
EMAIL_PORT
SMTP port.
587
EMAIL_HOST_USER
SMTP username.
(empty)
EMAIL_HOST_PASSWORD
Secret. SMTP password. File-based delivery available (see the tip above); not mounted by default since SMTP is opt-in (console backend otherwise).
Where create_backup writes encrypted backups, server-side.
/app/backups
BACKUP_ENCRYPTION_PASSPHRASE
Encrypts/decrypts backups. Required for create_backup to run unattended (host cron); restore_backup prompts interactively if this isn’t set. Same trust level as this app’s other .env secrets, so never commit the real value.
(empty)
BACKUP_RETENTION_DAYS
How long create_backup keeps old backups in BACKUP_DIR before pruning them.