How to Install Firefly III with Docker
Table of contents
- Key takeaways
- What is Firefly III?
- What do you need before you start?
- The docker-compose.yml with a database and the data importer
- APP_KEY and mandatory variables
- How do you import bank transactions?
- Backups and security
- Frequently asked questions
- Can I use Firefly III without connecting to my bank?
- Why should I not use the image's latest tag?
- Which database do I choose, MariaDB or PostgreSQL?
- Conclusion
- Sources
Firefly III is an open-source personal finance manager you self-host with Docker. With one docker-compose.yml file you bring up the application, a MariaDB database and the data importer, which connects to more than 6,000 banks through GoCardless. You generate the 32-character APP_KEY and keep control of all your money on your own server.
Firefly III is an open-source personal finance manager you self-host with Docker to keep track of your money without handing your bank data to any external app. In this guide you bring up the application alongside a MariaDB database and the data importer with a single docker-compose.yml file, generate the mandatory 32-character APP_KEY, import transactions from your bank and schedule backups. The same explanation is available in Spanish.
Key takeaways
- Firefly III is a personal-finance web application written in PHP with Laravel, released under the AGPL-3.0 licence, that replaces commercial bank-aggregation services and keeps your data on your own server.
- The current stable release is 6.6.6, published in July 2026; pin the tag
fireflyiii/core:version-6.6.6rather than:latest. - You need an
APP_KEYof exactly 32 characters: if it is missing or the wrong length, the application will not start. - The container listens on internal port 8080 and requires an external database; MariaDB or PostgreSQL, never SQLite for serious use.
- The data importer (image
fireflyiii/data-importer) is a second container that connects to more than 6,000 banks through GoCardless (Nordigen) and also imports CSV files.
What is Firefly III?
Firefly III is an open-source tool for managing your personal finances: you record income and expenses, define budgets, create asset and liability accounts, schedule recurring bills and see where your money goes with reports and charts. All of it on a server you control, with no monthly fees and no data hosted in a third party’s cloud.
It is built with PHP on the Laravel framework and distributed under the AGPL-3.0 licence, which keeps the code free. Unlike apps such as Mint or your bank’s aggregators, Firefly III does not sell your data or show you ads, because the data never leaves your machine. It offers a full REST API, two-factor authentication and automatic rules that classify transactions by category as they come in, so daily maintenance drops to a minimum.
What do you need before you start?
You need a Linux machine with Docker and the Compose plugin already installed. If you do not have it yet, follow the guide to install Docker on Ubuntu 24.04 first. With 1 GB of RAM and one core you have plenty for personal use.
Firefly III does not bundle its own database: it stores everything in an external engine, so the minimum setup is two containers, the application and the database. In this guide we use MariaDB, although PostgreSQL works just as well. To avoid writing passwords directly into the file, it is worth reviewing first how environment variables and secrets in Docker work, which is exactly the pattern we apply here.
The docker-compose.yml with a database and the data importer
Create a folder for the project and save this docker-compose.yml inside it. Before starting, replace the database password, paste your APP_KEY (we generate it in the next section) and change the cron token to a random 32-character string:
services:
app:
image: fireflyiii/core:version-6.6.6
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "8085:8080"
volumes:
- firefly_upload:/var/www/html/storage/upload
environment:
APP_KEY: paste_a_key_of_exactly_32_characters_here
APP_URL: "http://localhost:8085"
TZ: "Europe/Madrid"
STATIC_CRON_TOKEN: change_this_token_of_exactly_32_chars_xx
DB_CONNECTION: mysql
DB_HOST: db
DB_PORT: "3306"
DB_DATABASE: firefly
DB_USERNAME: firefly
DB_PASSWORD: change_this_db_key
db:
image: mariadb:lts
restart: unless-stopped
environment:
MARIADB_DATABASE: firefly
MARIADB_USER: firefly
MARIADB_PASSWORD: change_this_db_key
MARIADB_RANDOM_ROOT_PASSWORD: "yes"
volumes:
- firefly_db:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 30s
timeout: 5s
retries: 5
importer:
image: fireflyiii/data-importer:version-2.3.4
restart: unless-stopped
depends_on:
- app
ports:
- "8086:8080"
environment:
FIREFLY_III_URL: "http://app:8080"
VANITY_URL: "http://localhost:8085"
cron:
image: alpine:3.21
restart: unless-stopped
command: >
sh -c "echo '0 3 * * * wget -qO- http://app:8080/api/v1/cron/change_this_token_of_exactly_32_chars_xx'
| crontab - && crond -f -L /dev/stdout"
volumes:
firefly_upload:
firefly_db:
Notice a few details in the file. The application does not start until MariaDB passes its healthcheck, thanks to depends_on with the service_healthy condition. The app service listens on internal port 8080 and we publish it on the host’s 8085 to avoid clashing with other services; the importer sits on 8086. The cron container is a minimal alpine image that every day, at three in the morning, calls Firefly III’s scheduled-tasks endpoint to process recurring bills and reminders; its token must be identical to the application’s STATIC_CRON_TOKEN.
APP_KEY and mandatory variables
The APP_KEY encrypts Firefly III’s sessions and sensitive data, and it is the requirement that causes the most headaches, because it must be exactly 32 characters long. If it is shorter or longer, the container falls into a restart loop. Generate a valid string with this command and paste it into the APP_KEY value in the Compose file:
head /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 32 && echo
Avoid the characters =, # and similar in the key, because they can break how the file is parsed. These are the variables you must not leave unchecked:
APP_KEY: the 32-character key you just generated. Do not share it or commit it to a repository.APP_URL: the public address you will use to reach Firefly III. Locally it ishttp://localhost:8085; in production, the full HTTPS URL.DB_CONNECTION,DB_HOST,DB_DATABASE,DB_USERNAMEandDB_PASSWORD: the database connection details, which must match those of thedbservice.STATIC_CRON_TOKEN: a 32-character token that protects the scheduled-tasks endpoint; thecroncontainer uses it to authenticate.
With the file and the key ready, start the stack in the background and check that the services are healthy:
docker compose up -d
docker compose ps
docker compose logs -f app
The first time, the application runs the database migrations, so the boot takes a little longer. When the log stops moving, open http://localhost:8085 in the browser, register the first account (it becomes the administrator) and set the currency you work with.
How do you import bank transactions?
The data importer is what turns Firefly III into a tool that is comfortable to use every day. It is important to understand that it does not connect to your bank directly: it relies on two intermediary services, GoCardless (formerly Nordigen) for more than 6,000 European banks and SaltEdge for the rest of the world, plus the classic import of CSV and camt.053 files.
To use the automatic bank connection, go to http://localhost:8086, the importer interface, and follow the wizard. The first step is to give it a Firefly III access token (you create it under Options, Profile, OAuth, Personal Access Tokens) so the importer can write into your instance. Then you choose GoCardless, enter the credentials you get for free from its portal, select your bank and authorise read-only access to your accounts. From there, the importer downloads the movements and turns them into Firefly III transactions, applying your categorisation rules.
If you would rather not depend on third parties, the CSV route is the most private: you export the statement from your bank’s website, upload it to the importer and define the column mapping once. That mapping is saved as a template, so later imports take seconds. To automate it fully, the importer exposes an endpoint protected by the AUTO_IMPORT_SECRET variable (at least 16 characters) that you can trigger from the cron itself.
Backups and security
Firefly III stores money, or rather the detailed reflection of your money, so backups are not optional. There are only two pieces to back up: the database dump and the upload volume, where the attachments (receipts, scanned invoices) you attach to each transaction live. With MariaDB, a full backup fits in two commands:
docker compose exec db mariadb-dump -u firefly -p firefly > firefly-db.sql
docker run --rm -v firefly_upload:/data -v "$PWD":/backup alpine \
tar czf /backup/firefly-upload.tar.gz -C /data .
As for security, never expose Firefly III to the Internet over plain HTTP: it carries financial data and needs encryption. Put it behind a reverse proxy that handles TLS, such as Traefik with Docker Compose, and enable two-factor authentication from your profile. Keep the APP_KEY and the passwords in a .env file with restricted permissions, the same approach we saw in environment variables and secrets in Docker, and never change the APP_KEY once the database is in use, because it would invalidate the encrypted data.
Frequently asked questions
Can I use Firefly III without connecting to my bank?
Yes, and it is a perfectly valid way to use it. You can enter transactions by hand or import the statements you download from your bank’s website in CSV format, without giving any third party access to your accounts. The automatic connection with GoCardless or SaltEdge is an optional convenience, not a requirement; many users prefer the CSV route precisely for privacy.
Why should I not use the image’s latest tag?
Because :latest changes without warning, and a major update could run database migrations during a simple restart, in a service that stores financial data you do not want to risk. By pinning fireflyiii/core:version-6.6.6 you decide when you update: you read the release notes first, take a backup and only then bump the tag.
Which database do I choose, MariaDB or PostgreSQL?
Both are officially supported and perform well. MariaDB is what Firefly III’s default configuration uses and what we put in this guide’s docker-compose.yml, so it is the simplest option if you start from scratch. If you already run a PostgreSQL for other services, you can reuse it by changing DB_CONNECTION to pgsql and the port to 5432. What Firefly III does not support for serious use is SQLite.
Conclusion
With a single docker-compose.yml you have a complete, private personal finance manager: application, database, importer and scheduled tasks, with all your data on your server. The logical next step is to publish it securely behind Traefik, connect your bank or import your first CSV, and schedule the backups. If you enjoyed organising your money this way, take a look at Vikunja to manage your tasks, another self-hosted piece in this series.