Environment Variables¶
All Comaney configuration is done via environment variables. This page documents every variable, its default, and its full behaviour.
Core Django¶
DJANGO_SECRET_KEY¶
Default: a hardcoded development placeholder (insecure)
The Django secret key is used to sign sessions, CSRF tokens, and other cryptographic primitives. In production, this must be set to a long random string.
Generate one:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
Keep this value secret. Rotating the secret key invalidates all existing sessions (everyone is logged out) and CSRF tokens.
DEBUG¶
Default: FALSE
Set to TRUE to enable Django debug mode. In debug mode:
- Detailed error pages with full tracebacks are shown in the browser instead of the generic error page.
- Static files are served by Django directly (no WhiteNoise compression).
- Additional Django developer tooling is activated.
Never run with DEBUG=TRUE in production. Debug pages can expose sensitive configuration.
ALLOWED_HOSTS¶
Default: * (any host) in development (DEBUG=TRUE); empty (must be configured) in production.
A comma-separated list of hostnames that the Django application will accept requests for. Example:
In production, this should list only your actual domain(s). The wildcard * is no longer the production fallback: if you leave this unset while DEBUG is off, Django will reject every request until you configure a host, so this must be set for any public-facing deployment.
CSRF_TRUSTED_ORIGINS¶
Default: (empty; no extra trusted origins)
A comma-separated list of origins (scheme + host) that are trusted for CSRF. Required when running behind a reverse proxy that terminates TLS:
Without this, every form submission (login, expense creation, etc.) will fail with a CSRF verification error when accessed over HTTPS through a proxy.
Transport security¶
Comaney is designed to run behind a reverse proxy that terminates HTTPS and forwards plain HTTP to the app. The app speaks HTTP and does not enforce HTTPS itself: it never redirects HTTP to HTTPS and never sends HSTS. Handle HTTPS redirection and HSTS on your proxy instead (see the "Transport security behind a reverse proxy" section of the deployment guide).
There are therefore no HTTPS environment variables to set on the app. The only transport hardening it applies automatically in production (DEBUG=FALSE) is turning on SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE, so the login and CSRF cookies are only ever sent over the encrypted connection to your proxy. Local HTTP development (DEBUG=TRUE) is never affected.
Database¶
DB_HOST¶
Default: 127.0.0.1
Hostname or IP of the MariaDB server. When using Docker Compose with a mariadb service, set this to mariadb (the service name).
DB_PORT¶
Default: 3306
TCP port of the MariaDB server.
DB_NAME¶
Default: comaney
Name of the MariaDB database.
DB_USER¶
Default: comaney
MariaDB login username.
DB_PASSWORD¶
Default: comaney (insecure placeholder)
MariaDB login password. Change this to a strong random string in production.
Site & URLs¶
SITE_URL¶
Default: http://localhost:8080
The public base URL of your Comaney instance, without a trailing slash. This is embedded in outgoing emails (notification links, confirmation links, password reset links). If this is wrong, all email links will point to the wrong address.
Email¶
DISABLE_EMAILING¶
Default: (unset; emailing is enabled)
Set to TRUE (or 1, YES) to suppress all outgoing emails and disable email verification on account registration. When set:
- New users are auto-confirmed without clicking an email link.
- No notification emails are sent for any expense.
- No password reset emails are sent (the forgot-password flow is broken).
- No admin notification emails are sent.
Use this when you have no SMTP server available (development, quick self-hosting). Note that if neither DISABLE_EMAILING nor valid EMAIL_HOST/EMAIL_PORT are set, the application starts in a system misconfigured state and shows a banner on every page.
EMAIL_HOST¶
Default: localhost
SMTP server hostname. Required unless DISABLE_EMAILING is set.
EMAIL_PORT¶
Default: 1025
SMTP server port. Required unless DISABLE_EMAILING is set.
Common ports:
25: unencrypted SMTP (rarely usable in production)465: SMTPS (implicit TLS)587: STARTTLS submission (most common for external SMTP relays)1025: Mailpit dev relay (no auth, no TLS)
EMAIL_USE_TLS¶
Default: (unset; TLS disabled)
Set to TRUE to enable STARTTLS. Use with port 587. Do not confuse with implicit TLS (port 465), which Django handles differently.
EMAIL_HOST_USER¶
Default: (empty)
Username for SMTP authentication. Leave empty for unauthenticated relays (e.g., Mailpit, a local Postfix relay).
EMAIL_HOST_PASSWORD¶
Default: (empty)
Password for SMTP authentication.
DEFAULT_FROM_EMAIL¶
Default: noreply@comaney.local
The From: address used on all outgoing emails. Should be an address that either does not receive mail or is monitored:
ADMIN_NOTIFICATION_EMAIL¶
Default: (empty; admin notifications disabled)
When set, the application sends system notifications to this address:
- When a new user registers.
- When the AI trial API key runs out of funds.
- When a contact form submission is received.
Also, setting this variable (together with ENABLE_REGISTRATION=TRUE) enables the contact form at /contact/.
Registration¶
ENABLE_REGISTRATION¶
Default: FALSE
Set to TRUE to allow new users to create accounts via the registration page. For private single-user or small-group instances, enable this to create your account(s) and then disable it.
When disabled, the registration page returns a 403 and no new accounts can be created.
Two-factor authentication¶
YUBICO_CLIENT_ID¶
Default: (empty; YubiKey OTP second factor hidden)
Client ID for the Yubico OTP validation API. Together with YUBICO_SECRET_KEY, this enables the YubiKey OTP second-factor method: users can register a physical YubiKey and use it to sign in. When either YUBICO_CLIENT_ID or YUBICO_SECRET_KEY is unset, this method is hidden everywhere in the app (setup, login, profile).
Get a client ID and secret key by requesting one from Yubico (or your own self-hosted validation server, see YUBICO_SERVER).
YUBICO_SECRET_KEY¶
Default: (empty; YubiKey OTP second factor hidden)
Secret key paired with YUBICO_CLIENT_ID, used to sign and verify requests to the Yubico OTP validation server. Keep this value secret.
YUBICO_SERVER¶
Default: https://api.yubico.com
Base URL of the Yubico OTP validation server. Only needs to be changed if you run your own self-hosted validation server instead of Yubico's public one.
Demo user¶
These variables enable a public demo account that visitors can use without signing up. When enabled, a landing page advert is shown and the account is reset automatically by run_cron once it has been inactive for at least one week.
Note: the demo banner (shown to any is_demo user at every login) is always active regardless of this flag. ENABLE_DEMO_USERS only controls the landing page advert, the login gate, and the automatic reset.
ENABLE_DEMO_USERS¶
Default: FALSE
Set to TRUE to activate the public demo user feature. When set:
- The landing page shows a "try the live demo" advert with the demo email address.
- Demo users can log in. When
FALSE, any account flaggedis_demois denied login (credentials are silently rejected) and existing demo sessions are invalidated. run_cronruns the automatic reset check.
Requires DEMO_USER_EMAIL and DEMO_USER_PASSWORD to also be set.
DEMO_USER_EMAIL¶
Default: (empty)
Email address for the demo account. On reset, reset_demo_user deletes all is_demo users and creates a fresh account at this address. The account does not need to exist beforehand.
DEMO_USER_PASSWORD¶
Default: (empty)
Password used when recreating the demo account after a reset.
DEMO_USER_AI_BUDGET¶
Default: 0 (use global AI_TRIAL_USAGE_LIMIT)
Per-reset AI trial allowance for the demo user, in US cents. Overrides AI_TRIAL_USAGE_LIMIT for this account only. Set to a small value (e.g. 10 for $0.10) to limit trial spend per demo cycle. 0 means the global limit applies.
AI / Express Creation¶
AI_PROVIDER¶
Default: (unset; no AI)
Which AI service Comaney uses for its AI features (AI Express Creation, dashboard card assistant, Catalog Partnership mapping, Unclassified Expenses). Possible values:
claude: Claude by Anthropicdeepseek: DeepSeeklocal: a model on any OpenAI-compatible server, your own or someone else's- the file name of a community provider you mounted
none: switch all AI features off; every AI button and page is hidden, and users' saved AI settings are kept
If it is unset, AI is off as well. There is one exception, so that an upgrade never switches AI off without you noticing: if other AI settings are present (AI_TRIAL_API_KEY or any variable starting with AI_PROVIDER_) but AI_PROVIDER is not set, the site shows a configuration error page asking you to set it.
An unknown value, or invalid settings for the chosen AI service, also take the site down with a configuration error page that names the variable to fix. AI is never switched off silently: fix the setting, or set AI_PROVIDER=none.
Settings of the chosen AI service start with AI_PROVIDER_<NAME>_, for example AI_PROVIDER_CLAUDE_API_KEY. The prefix scopes them: Comaney hands each AI service only the variables with its own prefix (a naming convention, not a security boundary). The settings of every built-in service (keys, models, prices, ...), with examples, are on AI Providers.
AI_TRIAL_API_KEY¶
Deprecated: use AI_PROVIDER_CLAUDE_API_KEY instead.
The old name of AI_PROVIDER_CLAUDE_API_KEY. It still works with AI_PROVIDER=claude (a warning is logged at startup). If both are set to different keys, the site shows a configuration error page. With any other AI_PROVIDER it is ignored.
AI_TRIAL_USAGE_LIMIT¶
Default: 0 (cents)
The per-user, per-month spending cap on the shared AI access, in US cents. When a user's share of shared usage reaches this limit in the current calendar month, the AI features are disabled for that user until the next month. Users with their own AI settings are never limited.
Example: AI_TRIAL_USAGE_LIMIT=10 gives each user a $0.10/month allowance on the shared access.
Set to 0 (the default) to impose no per-user limit: everyone without their own settings can use the shared access without a cap (only the AI service's own account budget applies). Spending is still recorded per user, and Comaney logs a startup warning so this is not set by accident.
AI_NOTIFY_ADMIN_JSON_REPAIR¶
Default: TRUE
When the AI answers in a broken format, Comaney asks it once more to repair the answer and emails ADMIN_NOTIFICATION_EMAIL about it (no user data, only which feature was affected and whether the repair worked). Set to FALSE to stop these emails, for example if they become frequent with a weaker model.
AI_TRIAL_DISABLED_FLAG¶
Default: {app_root}/ai_trial_disabled.flag
Path to the flag file used to indicate that shared AI access has been globally disabled (e.g., because the AI service's account ran out of credit). When this file exists, shared access is disabled for all users.
Normally you don't need to set this. Override it if the default path is not writable in your container setup. See Shared AI Access for management instructions.
Public pages¶
PUBLIC_PAGE_IMPRINT_MD¶
Default: (unset)
Path to a Markdown file. When set, a page is added to the site at /impressum/ with the content of the file, rendered as HTML. Required for hosting a public instance in Germany (legal imprint / Impressum).
PUBLIC_PAGE_EUDATENSCHUTZ_MD¶
Default: (unset)
Path to a Markdown file. When set, a page is added at /datenschutzerklaerung/ with the rendered content. Required for hosting a public instance subject to GDPR (Datenschutzerklärung / Privacy Policy).
Performance¶
GUNICORN_WORKERS¶
Default: 1
Number of Gunicorn worker processes. Each worker handles one request at a time and holds one database connection. For a single-user private instance, 1 is sufficient. For a multi-user instance under load, use 2 × CPU_cores + 1.