Firefly III Personal Finance: Track Your Budget and Accounts via Docker
Complete guide to self-hosting Firefly III personal finance manager on a VPS with Docker Compose. Organize your budgets and track expenses.
Self-Hosting Firefly III with Docker Compose
1. Database Configuration and Bindings
Firefly III supports MySQL, MariaDB, and PostgreSQL. For a robust self-hosted setup, MariaDB is highly recommended. The database service requires persistent volume bindings to ensure transaction logs and financial data survive container recreations.
Recommended Environment Variables for Database Connection
Within the Firefly III container, the database connection is configured using the following environment variables:
| Variable | Description | Recommended Value |
|---|---|---|
DB_CONNECTION |
Database driver | mysql (works for MariaDB) or pgsql |
DB_HOST |
Hostname of the database service in the Docker network | firefly_iii_db |
DB_PORT |
Network port for database communication | 3306 (MariaDB/MySQL) or 5432 (PostgreSQL) |
DB_DATABASE |
Name of the database | firefly |
DB_USERNAME |
Username for database access | firefly |
DB_PASSWORD |
Password for database access | Use a secure, randomly generated string |
Persistent Volume Mapping
To prevent data loss, map a local directory or named volume to the database container's data directory. For MariaDB:
volumes:
- /var/lib/firefly/db:/var/lib/mysql
For PostgreSQL:
volumes:
- /var/lib/firefly/db:/var/lib/postgresql/data
2. Web Server Parameters and Reverse Proxy
Firefly III runs internally on port 8080 (HTTP). Exposure to the public internet must be mediated by a reverse proxy handling SSL termination.
Caddy Reverse Proxy Configuration
Caddy simplifies SSL handling by automatically provisioning Let's Encrypt certificates.
firefly.yourdomain.com {
reverse_proxy firefly_iii_app:8080 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
Nginx Reverse Proxy Configuration
If using Nginx, configure the virtual host with the following parameters:
server {
listen 443 ssl http2;
server_name firefly.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/firefly.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/firefly.yourdomain.com/privkey.pem;
client_max_body_size 64M;
location / {
proxy_pass http://firefly_iii_app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Trusting Proxies
Firefly III must know it is behind a reverse proxy to correctly generate HTTPS links. Configure these environment variables in your Firefly III container:
TRUSTED_PROXIES=**(or specify the specific IP address of your reverse proxy/docker gateway, e.g.,172.16.0.0/12)APP_URL=https://firefly.yourdomain.com
3. Cron Job Setup for Automated Tasks
Firefly III relies on a recurring cron job to process recurring transactions, fetch currency exchange rates, and run system checks.
Method A: Docker Compose Sidecar (Recommended)
You can run a lightweight Alpine container alongside your application that queries the Firefly III cron endpoint via curl at regular intervals.
Add this service to your docker-compose.yml:
firefly_iii_cron:
image: alpine:latest
restart: always
container_name: firefly_iii_cron
depends_on:
- firefly_iii_app
entrypoint: |
sh -c "
echo '0 * * * * wget -qO- http://firefly_iii_app:8080/api/v1/cron/$STATIC_CRON_TOKEN' | crontab - &&
crond -f -L /dev/stdout
"
environment:
- STATIC_CRON_TOKEN=your_secure_cron_token_here
Method B: Host-Level Crontab
Alternatively, use the host system's crontab to hit the API endpoint hourly:
0 * * * * curl -s http://localhost:8080/api/v1/cron/your_secure_cron_token_here > /dev/null 2>&1
4. Complete docker-compose.yml Specification
Create a directory (e.g., /opt/firefly) and place the following configuration inside docker-compose.yml.
version: '3.8'
services:
firefly_iii_db:
image: mariadb:10.11
container_name: firefly_iii_db
restart: always
environment:
- MYSQL_RANDOM_ROOT_PASSWORD=yes
- MYSQL_DATABASE=firefly
- MYSQL_USER=firefly
- MYSQL_PASSWORD=your_db_secure_password
volumes:
- firefly_db:/var/lib/mysql
networks:
- firefly_network
firefly_iii_app:
image: fireflyiii/core:latest
container_name: firefly_iii_app
restart: always
depends_on:
- firefly_iii_db
volumes:
- firefly_upload:/var/www/html/storage/upload
environment:
- APP_KEY=ChangeThisToExactly32CharsLongString!
- APP_ENV=local
- APP_DEBUG=false
- APP_URL=https://firefly.yourdomain.com
- TRUSTED_PROXIES=**
- DB_CONNECTION=mysql
- DB_HOST=firefly_iii_db
- DB_PORT=3306
- DB_DATABASE=firefly
- DB_USERNAME=firefly
- DB_PASSWORD=your_db_secure_password
- STATIC_CRON_TOKEN=your_secure_cron_token_here
- TZ=UTC
ports:
- "127.0.0.1:8080:8080"
networks:
- firefly_network
firefly_iii_cron:
image: alpine:latest
container_name: firefly_iii_cron
restart: always
depends_on:
- firefly_iii_app
entrypoint: >
sh -c "
echo '0 * * * * wget -qO- http://firefly_iii_app:8080/api/v1/cron/your_secure_cron_token_here' | crontab - &&
crond -f -L /dev/stdout
"
networks:
- firefly_network
volumes:
firefly_db:
driver: local
firefly_upload:
driver: local
networks:
firefly_network:
driver: bridge
5. Deployment and Verification
- Generate a Secure Encryption Key: Firefly III requires a 32-character application key (
APP_KEY). Generate one using:bash head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32 ; echoUpdate theAPP_KEYenvironment variable in yourdocker-compose.ymlwith this output. - Launch the Stack: Execute the following command in the directory containing
docker-compose.yml:bash docker compose up -d - Run Database Migrations and Seed Data: The container automatically runs migrations on start. You can monitor the progress with:
bash docker compose logs -f firefly_iii_appWait for the log entry indicating that the web server is running. - Create Your User Account: Access Firefly III through your configured reverse proxy URL (e.g.,
https://firefly.yourdomain.com). The first account registered automatically becomes the administrator.