What Is This
Firefly III is an open-source bookkeeping system written in PHP and running in Docker. My instance is called Firefly, and it is mainly used to record the family's daily transactions: who spent it, where it was spent, and which account it came from.
Why Self-Host
When it comes to bookkeeping, two things worry me most: first, the data is not in my own hands; second, switching tools loses a batch of history. After self-hosting, the entire ledger is "a database + an upload directory"; backing it up means everything, and migration does not require asking anyone for help. Along the way, I also went through three things: how to deploy a PHP application, how to connect to the database, and how to retain backups. The pitfalls I hit are all left in the configuration.
What Problems It Solves
Too many accounts are the biggest obstacle to bookkeeping: cash, bank cards, Alipay, and WeChat each recorded in a separate book, and at the end of the month they simply do not reconcile. Firefly III splits them into multiple accounts but aggregates them in one view; reports are generated by month, category, and account, making it clear where the money actually goes, rather than just a pile of transactions; then set monthly budgets for a few major categories, and you can see at a glance whether you are over budget.
Current Status
Running, and it has continuously recorded two years of family transactions; daily bookkeeping is done through the web UI. The deployment configuration is under opt-configs/ledger and managed with docker-compose. Rebuilding containers does not lose data, which is also why I insist on writing a compose file rather than manually running docker run.
Features
- 多账户记账:现金、银行卡、第三方支付分开记,汇总在一处
- 报表与图表:按月、按分类、按账户出流水统计
- 预算管理:给主要开销类别设月度预算并跟踪
- Docker Compose 部署:配置集中在一个 compose 文件里,随时重建
- 数据自持:数据库与上传目录可整体备份、可迁移
Stack: Firefly III · PHP · Docker Compose · MariaDB · Nginx Proxy Manager
1. Prepare the directory
On the host with Docker installed, create a working directory; put the configuration and data here:
mkdir -p /opt/ledger && cd /opt/ledger
2. Write docker-compose.yml
One application container + one database container, with the upload directory mounted separately:
services:
firefly:
image: fireflyiii/core:latest
restart: unless-stopped
volumes:
- ./upload:/var/www/html/storage/upload
env_file: .env
ports:
- "8082:8080"
depends_on:
- db
db:
image: mariadb:lts
restart: unless-stopped
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: firefly
MYSQL_USER: firefly
MYSQL_PASSWORD: 换成你自己的密码
volumes:
- ./db:/var/lib/mysql
3. Write .env
The key items are APP_KEY (a 32-character random string) and the database connection; set DB_HOST to the service name db in the compose file:
APP_KEY=填32位随机字符串
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=firefly
DB_USERNAME=firefly
DB_PASSWORD=与compose里一致
4. Start and initialize
docker compose up -d
docker compose logs -f firefly
After the logs show that migrations are complete, open http://192.168.50.164:8082 in your browser. The first registered account is the administrator. After registering, remember to turn off open registration.
5. Set up a reverse proxy and HTTPS
Create a new proxy in Nginx Proxy Manager pointing to 192.168.50.164:8082, request a certificate, and enable forced HTTPS. For home LAN use, you can restrict access to the internal network only; for external access, use an intranet traversal solution such as Tailscale, which is less hassle than exposing ports directly to the public internet.
6. Backup
Two things must be backed up: the database and the upload directory. A dump is the most reliable way to back up the database:
docker compose exec db mysqldump -u firefly -p firefly > backup-$(date +%F).sql
tar czf upload-$(date +%F).tar.gz upload/
Put it in a scheduled task, and regularly verify that it can be restored—don't just back up without testing.