Every budgeting app you sign up for asks for the same thing eventually: read access to your bank accounts. In exchange you get a subscription fee, a company that can change its pricing or shut down, and your full transaction history sitting on someone else's server. Firefly III is a free, open-source, double-entry finance manager that runs entirely on hardware you control, and it never contacts an external server unless you explicitly tell it to. This guide covers installing it with Docker, setting it up correctly behind a reverse proxy, and reaching it securely from your phone with Localtonet.
Why Hand Your Financial Data to Another Company
A cloud budgeting app is convenient right up until it changes its pricing tier, gets acquired, or has a data breach involving the exact category of data you were trying to get organized in the first place. None of that is a hypothetical risk category, it has happened to more than one popular app already.
Firefly III sidesteps the entire question. Your transactions, your accounts, your budgets, all of it stays on infrastructure you run, and the software itself is built around the same double-entry principle accountants have used for centuries, not a simplified envelope system that falls apart once your finances get slightly complicated.
You get the same rigor as a real ledger, without a company sitting between you and your own money.
What Is Firefly III?
Firefly III is a free, open-source personal finance manager built by James Cole under the AGPLv3 license. Every transaction has both a source and a destination account, the same double-entry approach real bookkeeping uses, which is what makes its reports trustworthy instead of approximate.
Firefly III is light enough to run comfortably on a Raspberry Pi. The one catch: reliable MariaDB and MySQL container images are not available on arm/v7, so switch DB_CONNECTION to PostgreSQL in your .env file if you are deploying to a Pi.
Install Firefly III With Docker Compose
Generate an APP_KEY
Firefly III needs a 32-character Laravel encryption key. Generate one and save it, you will paste it into your .env file next.
head /dev/urandom | LC_ALL=C tr -dc A-Za-z0-9 | head -c 32; echo
Create docker-compose.yml
services:
app:
image: fireflyiii/core:latest
restart: always
depends_on:
- db
environment:
- APP_KEY=your_generated_32_char_key
- DB_CONNECTION=pgsql
- DB_HOST=db
- DB_DATABASE=firefly
- DB_USERNAME=firefly
- DB_PASSWORD=your_db_password
- APP_URL=https://budget.example.com
- TRUSTED_PROXIES=**
volumes:
- firefly_upload:/var/www/html/storage/upload
ports:
- "8080:8080"
db:
image: postgres:16
restart: always
environment:
- POSTGRES_DB=firefly
- POSTGRES_USER=firefly
- POSTGRES_PASSWORD=your_db_password
volumes:
- firefly_db:/var/lib/postgresql/data
volumes:
firefly_upload:
firefly_db:
Start the stack
docker compose up -d
Open it locally and create your account
Visit http://localhost:8080, register the first account, and set up your first bank and cash accounts.
Remote Access With Localtonet
Create an HTTP tunnel
Go to localtonet.com/tunnel/http, point it at 127.0.0.1:8080, and map a custom domain such as budget.example.com.
Turn on Basic Auth
In the tunnel's settings, enable Basic Auth with its own username and password, separate from your Firefly III login.
Confirm APP_URL matches the custom domain exactly
This is the value from your docker-compose.yml, it must be the real public HTTPS address, not localhost.
Firefly III is a Laravel application, and Laravel generates links and validates requests based on APP_URL. If it is left at a default or a local address while you access it through a custom domain, forms, redirects, and CSRF checks can fail in confusing ways. Set APP_URL to your exact public HTTPS domain, and set TRUSTED_PROXIES so Firefly III trusts the forwarded headers from the tunnel instead of rejecting them.
๐ Securing Your Financial Data
๐ Layer Basic Auth in front of the login screen
Firefly III already requires its own login. Basic Auth on the tunnel adds an independent check before a visitor ever reaches that login page, so a leaked link alone cannot get anyone to your data.
๐ Turn on two-factor authentication inside Firefly III
Firefly III has built-in 2FA. Enable it on your account from the profile settings, it is a five-minute step that matters far more here than on most self-hosted apps.
๐ Consider Enterprise Auth for a full SSO login
Firefly III supports authenticating through a trusted reverse proxy instead of its own login form. If you want a proper single sign-on screen in front of your finances rather than a Basic Auth prompt, Localtonet's Enterprise Auth add-on, Google, GitHub, or SAML 2.0, sits in exactly that position.
๐พ Back up the database, not just the app
Your actual financial history lives in Postgres, not in the Firefly III container. Schedule regular database dumps and store them somewhere other than the same disk.
Importing Your Bank Data
Firefly III does not connect to your bank directly, and by design it never contacts an external server unless you explicitly configure it to. Getting your transaction history in is handled by a separate, official Data Importer tool, which either reads CSV or CAMT.053 files you export from your bank yourself, or connects through opt-in third-party providers like Salt Edge, GoCardless, or SimpleFIN if you want ongoing automatic imports instead of manual exports.
Keep It Running Permanently
Both containers already use restart: always, so Docker brings them back after a crash or a host reboot on its own. For the tunnel itself to survive a full reboot, install the Localtonet client as a background service once: localtonet --install-service --start-service. Your custom domain comes back automatically without any manual step.
Firefly III vs. Cloud Budgeting Apps
| Feature | YNAB / Mint-style apps | Self-hosted Firefly III |
|---|---|---|
| Cost | Monthly or annual subscription | Free, forever, AGPLv3 |
| Where your data lives | The provider's servers | Your own server, never leaves unless you configure an import |
| Accounting model | Usually envelope-style budgeting | True double-entry bookkeeping |
| Bank connections | Built in, automatic | Via the separate Data Importer, files or opt-in providers |
| Setup effort | None, sign up and connect accounts | An evening of Docker and configuration |
The honest trade-off: a polished cloud app genuinely wins on convenience, automatic bank syncing with no setup is hard to beat if that is all you want. Firefly III's advantage is everything downstream of that: no subscription, a stricter accounting model, and a guarantee that your transaction history is not the product being monetized somewhere else.
๐ Tips for Getting the Most Out of Firefly III
Troubleshooting Common Issues
| Symptom | Likely cause | Fix |
|---|---|---|
| "No application encryption key has been specified" | APP_KEY was never set or is the wrong length | Generate a proper 32-character key and restart the containers |
| Forms or redirects behave strangely through the tunnel | APP_URL does not match the public domain, or TRUSTED_PROXIES is unset | Set APP_URL to the exact custom domain and TRUSTED_PROXIES as shown in the compose file above |
| Database connection failed on startup | DB_USERNAME or DB_PASSWORD do not match between the app and db services | Confirm both services reference the same credentials, then recreate the containers |
| MariaDB container won't start on a Raspberry Pi | No reliable arm/v7 MariaDB images | Switch DB_CONNECTION to pgsql and use the postgres image instead |
Frequently Asked Questions
Does Firefly III connect to my bank automatically?
Not by itself. Firefly III never contacts external servers unless you configure it to. Getting transactions in is handled by the separate Data Importer tool, either from files you export or through opt-in third-party providers.
Is Firefly III really free?
Yes. It is open source under the AGPLv3 license, with no paid tiers or premium features. The developer accepts donations, but the software is fully functional without paying anything.
Can I access it from my phone?
Yes, its web interface works on mobile browsers once it is reachable through a Localtonet tunnel, and the REST API is available for anyone building or using a dedicated client.
Why does Firefly III need TRUSTED_PROXIES?
Traffic through a tunnel arrives with forwarded headers rather than a direct connection. TRUSTED_PROXIES tells Laravel, the framework Firefly III is built on, to trust those headers so links, redirects, and security checks resolve correctly.
Is Basic Auth enough to protect financial data?
It is a strong first layer, but combine it with Firefly III's own 2FA for a real second factor. If you want a full SSO experience instead of a Basic Auth prompt, Localtonet's Enterprise Auth add-on supports that too.
Can multiple people use one Firefly III instance?
Firefly III supports multiple user accounts and multiple financial "administrations" within one instance, useful for tracking personal and household finances separately under the same install.
What happens to my data if I stop self-hosting?
It is entirely yours. Export it from the built-in export tools, or take your Postgres backup with you, there is no vendor lock-in since nothing was stored on someone else's platform to begin with.
Ready to Own Your Financial Data?
Deploy Firefly III with Docker, secure it with Basic Auth and 2FA, then reach it from anywhere with a Localtonet custom domain. Free to start, no credit card required.
Get Started Free โ