Skip to content

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:

ALLOWED_HOSTS: "budget.example.com,www.budget.example.com"

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:

CSRF_TRUSTED_ORIGINS: "https://budget.example.com"

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.

SITE_URL: "https://budget.example.com"

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:

DEFAULT_FROM_EMAIL: "Comaney <noreply@budget.example.com>"

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 flagged is_demo is denied login (credentials are silently rejected) and existing demo sessions are invalidated.
  • run_cron runs 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 Anthropic
  • deepseek: DeepSeek
  • local: 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_IMPRINT_MD: /app/legal/impressum.md

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).

PUBLIC_PAGE_EUDATENSCHUTZ_MD: /app/legal/datenschutz.md

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.