Self-host Firefly III
A powerful self-hosted personal finance manager built on double-entry accounting — budgets, rules, reports, and bank import. Serious money management, privately.
Key facts
Pick Firefly III when you want real double-entry bookkeeping — withdrawals, deposits and transfers across asset, expense and liability accounts, with budgets, categories, tags, piggy banks, bills, rules and a REST API that "covers almost every part" of the app — and you accept a PHP + database stack to get it. It is AGPL-3.0, at v6.7.3 as of September 2026, and "will never contact external servers until you explicitly tell it to". Bank import lives in a separate Data Importer container, and several headline features do nothing until a cron job runs.
Follow the Firefly III deploy guide →What you need
- Any VPS with at least 512 MB of RAM
- A domain you control — most self-hosted setups need HTTPS in front of them
- About an afternoon — budget time for troubleshooting
Paid link — we earn a commission if you shop through it.
Install with Docker Compose
Save this as compose.yml and run docker compose up -d:
# Firefly III + MariaDB — replace APP_KEY (exactly 32 chars) and both copies of the DB password before real use
services:
app:
image: fireflyiii/core:latest
ports: ["8080:8080"]
environment: { DB_CONNECTION: mysql, DB_HOST: db, DB_DATABASE: firefly, DB_USERNAME: firefly, DB_PASSWORD: secret, APP_KEY: SomeRandomStringOf32CharsExactly }
db: { image: mariadb:11, environment: { MARIADB_RANDOM_ROOT_PASSWORD: "yes", MARIADB_DATABASE: firefly, MARIADB_USER: firefly, MARIADB_PASSWORD: secret } }
# docker compose up -d → http://SERVER_IP:8080What you take on
Firefly III's docs are written by one maintainer who has seen every support ticket; follow them literally:
An alternative to
Head-to-head
More self-hosted tools
Actual Budget
Ghostfolio
Matomo
SuiteCRM
Common questions
Firefly III hangs on "wait-for-it.sh: waiting 60 seconds for db:3306". Why?
The database container has already exited. Its log shows "[ERROR] [Entrypoint]: Database is uninitialized and password option is not specified": the MariaDB service was started without any environment, so it refuses to create a database and the app waits for a server that never comes up. Give the db service MARIADB_DATABASE, MARIADB_USER and MARIADB_PASSWORD (matching the app's DB_DATABASE, DB_USERNAME and DB_PASSWORD) plus a root-password option such as MARIADB_RANDOM_ROOT_PASSWORD=yes, as the compose above does, then run docker compose up -d again.