Deployment¶
Comaney is distributed as a Docker image and requires a MariaDB database. A docker-compose.yml is the recommended way to run it.
Minimal docker-compose.yml¶
services:
web:
image: leonetienne/comaney:latest
restart: unless-stopped
ports:
- "80:8000"
depends_on:
- mariadb
environment:
# Generate with:
# python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
DJANGO_SECRET_KEY: "change-me-to-a-long-random-string"
DB_HOST: mariadb
DB_PORT: 3306
DB_NAME: comaney
DB_USER: comaney
DB_PASSWORD: "change-me"
SITE_URL: "http://localhost:80"
ALLOWED_HOSTS: "localhost"
CSRF_TRUSTED_ORIGINS: "http://localhost"
# Allow new users to register (disable after initial setup)
ENABLE_REGISTRATION: "TRUE"
# No SMTP server? Disable emailing for a quick start.
# Note: disabling email also disables email verification on registration.
DISABLE_EMAILING: "TRUE"
GUNICORN_WORKERS: 1
volumes:
- comaney_data:/app/data # persistent user data (profile pictures, etc.)
mariadb:
image: mariadb:lts
restart: unless-stopped
environment:
MARIADB_DATABASE: comaney
MARIADB_USER: comaney
MARIADB_PASSWORD: "change-me"
MARIADB_ROOT_PASSWORD: "change-root-too"
volumes:
- mariadb_data:/var/lib/mysql
volumes:
mariadb_data:
comaney_data:
Production docker-compose.yml (with SMTP and HTTPS)¶
services:
web:
image: leonetienne/comaney:latest
restart: unless-stopped
ports:
- "127.0.0.1:8000:8000" # bind to localhost; reverse proxy handles TLS
depends_on:
- mariadb
environment:
DJANGO_SECRET_KEY: "your-secret-key-here"
DB_HOST: mariadb
DB_PORT: 3306
DB_NAME: comaney
DB_USER: comaney
DB_PASSWORD: "strong-db-password"
SITE_URL: "https://budget.example.com"
ALLOWED_HOSTS: "budget.example.com"
CSRF_TRUSTED_ORIGINS: "https://budget.example.com"
ENABLE_REGISTRATION: "FALSE"
EMAIL_HOST: "smtp.example.com"
EMAIL_PORT: 587
EMAIL_USE_TLS: "TRUE"
EMAIL_HOST_USER: "noreply@example.com"
EMAIL_HOST_PASSWORD: "smtp-password"
DEFAULT_FROM_EMAIL: "Comaney <noreply@example.com>"
ADMIN_NOTIFICATION_EMAIL: "admin@example.com"
GUNICORN_WORKERS: 2
volumes:
- comaney_data:/app/data # persistent user data (profile pictures, AI trial flag, etc.)
mariadb:
image: mariadb:lts
restart: unless-stopped
environment:
MARIADB_DATABASE: comaney
MARIADB_USER: comaney
MARIADB_PASSWORD: "strong-db-password"
MARIADB_ROOT_PASSWORD: "strong-root-password"
volumes:
- mariadb_data:/var/lib/mysql
volumes:
mariadb_data:
comaney_data:
The /data volume¶
Comaney stores user-generated files under /app/data inside the container. This directory must be a persistent mounted volume — if it is missing, the application will refuse to start and display a configuration error page instead.
What is stored there:
| Path | Contents |
|---|---|
/app/data/media/ppics/ |
User profile pictures (resized JPEG, one per user) |
/app/data/ai_trial_disabled.flag |
AI trial deactivation flag (written by the admin panel) |
Always mount a named volume (or a host path) to /app/data. Do not use a tmpfs mount, as data would be lost on container restart.
First run¶
When the container starts for the first time, the entrypoint runs Django migrations automatically. No manual migration step is needed.
The web service is available on port 8000 inside the container (mapped to 80 or wherever you choose on the host).
Creating user accounts¶
With registration enabled (ENABLE_REGISTRATION=TRUE) users can sign up through the web UI. You can also create accounts directly from the command line, bypassing the registration flow. Accounts created this way are immediately active and confirmed.
# Prompted interactively (recommended):
docker exec -it comaney-web-1 python manage.py create_user user@example.com
# Or with password provided directly:
docker exec -it comaney-web-1 python manage.py create_user user@example.com -p "SecurePassword123"
To change a user's password later:
Account recovery¶
If a user forgets their password or loses access to their TOTP device, you can recover their account from the command line without any downtime.
Reset a forgotten password:
Remove a lost TOTP device so the user can log in with their password again:
See Console Commands for the full reference.
Creating a superuser¶
A superuser account is purely optional but required to access the Django admin at /admin/ and to re-enable the AI trial at /admin/ai-trial/. The AI trial deactivates itself if your trial API key runs out of funds.
Replace <container_name> with the name shown by docker compose ps (typically comaney-web-1).
Generating a secret key¶
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
Or with openssl:
Updating¶
Pull the new image and recreate the container. Migrations run automatically on startup.
Worker count¶
The GUNICORN_WORKERS variable controls how many Gunicorn worker processes are started. The default is 1. For a small private instance, 1–2 workers is sufficient. Each worker holds a database connection, so set this in proportion to your MariaDB max_connections.