Firefly III is a mature, open-source personal finance manager. You record income and expenses across accounts, set budgets, categorise spending with rules, track bills and piggy banks (savings goals), and get reports over time. It uses double-entry bookkeeping under the hood, and keeps your financial data on your own server instead of a budgeting app’s cloud.

Simpler, envelope-style alternative: Actual Budget.

Requirements

  • 1 vCPU and 1 GB RAM.
  • A database: MariaDB/MySQL or PostgreSQL (SQLite also works for one user).
  • HTTPS. This is financial data.

Install with Docker Compose

mkdir -p /opt/firefly && cd /opt/firefly
curl -o .env https://raw.githubusercontent.com/firefly-iii/firefly-iii/main/.env.example
curl -o .db.env https://raw.githubusercontent.com/firefly-iii/docker/main/database.env

Edit .env:

APP_KEY=<exactly 32 characters>          # e.g. head -c 32 /dev/urandom | base64 | head -c 32
SITE_OWNER[email protected]
TZ=Europe/London
TRUSTED_PROXIES=**
APP_URL=https://money.example.com
DB_CONNECTION=mysql
DB_HOST=db
DB_DATABASE=firefly
DB_USERNAME=firefly
DB_PASSWORD=<strong password>
STATIC_CRON_TOKEN=<exactly 32 characters>

Set the matching database values in .db.env. Then:

# /opt/firefly/compose.yaml
services:
  app:
    image: fireflyiii/core:latest
    restart: unless-stopped
    env_file: .env
    volumes:
      - ./upload:/var/www/html/storage/upload
    ports:
      - "127.0.0.1:8080:8080"
    depends_on: [db]
  db:
    image: mariadb:lts
    restart: unless-stopped
    env_file: .db.env
    volumes:
      - ./db:/var/lib/mysql
  cron:
    image: alpine
    restart: unless-stopped
    command: sh -c "echo '0 3 * * * wget -qO- http://app:8080/api/v1/cron/$${STATIC_CRON_TOKEN}' | crontab - && crond -f -L /dev/stdout"
    env_file: .env
docker compose up -d

The cron container is important: recurring transactions, bill reminders and auto-budgets only run when the cron endpoint is called daily.

Keep .env private (chmod 600). Never change APP_KEY after setup: it encrypts data, and changing it breaks existing data. See secrets management.

HTTPS with Nginx

server {
    server_name money.example.com;
    client_max_body_size 50M;
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    # listen 443 ssl; certbot --nginx -d money.example.com
}

TRUSTED_PROXIES=** and APP_URL make Firefly III generate correct HTTPS links behind the proxy. See Let’s Encrypt.

Register the first account immediately: the first user becomes the admin. Then enable 2FA (Profile → 2FA). Consider restricting access further with a VPN or IP allowlist, since this holds your financial history. See Tailscale.

Importing bank data

Firefly III doesn’t connect to banks directly. Use the separate Data Importer:

  importer:
    image: fireflyiii/data-importer:latest
    restart: unless-stopped
    environment:
      FIREFLY_III_URL: http://app:8080
      VANITY_URL: https://money.example.com
      FIREFLY_III_ACCESS_TOKEN: <personal access token from Firefly III>
    ports:
      - "127.0.0.1:8081:8080"
  • CSV import: export statements from your bank, map the columns once, and save the configuration for next time.
  • Bank connections: the importer supports some open-banking providers (availability depends on your country, and may need your own API credentials).

Protect the importer too (basic auth or VPN). It has a token with full access.

Getting organised

  • Accounts: asset accounts (bank, cash), expense and revenue accounts are created automatically from transactions.
  • Rules: auto-categorise and tag transactions (“description contains NETFLIX → category Subscriptions”). Rules make imports painless.
  • Budgets with monthly limits, and auto-budgets.
  • Bills and subscriptions to track recurring payments.
  • Piggy banks for savings goals.
  • Reports: spending by category, budget versus actual, net worth.

Backups

Your financial history is irreplaceable:

docker compose exec db mariadb-dump -u firefly -p"$DB_PASSWORD" firefly > /backups/firefly-$(date +%F).sql

Also back up ./upload (attachments) and .env (especially APP_KEY). Encrypt off-site backups. See mysqldump and off-site VPS backups.

Updates

docker compose pull && docker compose up -d. Migrations run automatically. Back up first, and read the release notes for major versions. See updating self-hosted apps.

Quick reference

Item Value
Port 8080
Key settings APP_KEY (32 chars, never change), APP_URL, TRUSTED_PROXIES
Daily cron /api/v1/cron/<STATIC_CRON_TOKEN>
Bank import Firefly III Data Importer (CSV, some APIs)
2FA Profile → 2FA

Related: Actual Budget and Invoice Ninja.

  • Self-Hosting
  • Docker
  • Finance