Applications AWS

Firefly III 6.7.9 on AWS User Guide

| Product: Firefly III 6.7.9 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the Firefly III 6.7.9 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg accounting and HR software listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

Firefly III is an open source, self-hosted personal finance manager. It uses double entry bookkeeping to keep an exact record of your money: asset, expense, revenue and liability accounts, budgets, categories and tags, bills and subscriptions, piggy banks for savings goals, rules that file transactions automatically, recurring transactions, multi-currency support, charts and reports, and a REST API for importers and apps. Your data stays on your own server.

The cloudimg image is a hardened, ready-to-use Firefly III server:

  • The upstream release. The official Firefly III 6.7.9 release archive, verified against its SHA-256, with its prebuilt web interface. No Firefly III source file is modified. Six bundled Symfony libraries are raised to their current security releases within the same versions; SOURCE.txt lists exactly what changed.
  • PHP 8.5 from the ondrej/php PPA. Firefly III 6.7.9 needs PHP 8.5, which Ubuntu 24.04 does not ship. PHP comes from the long-standing ondrej/php PPA, trusted through one pinned signing key and limited by an apt pin to PHP packages only. Unattended upgrades keep both Ubuntu and PHP patched.
  • No default login. First boot creates one owner account, admin@example.com, with a random password unique to your instance, and closes self-registration (single user mode). APP_KEY, the encryption key for Firefly III's stored secrets, and the cron token are also generated on your instance. Until first boot has finished, neither nginx nor PHP starts.
  • HTTPS from the first boot. nginx serves Firefly III on 443 with a certificate generated on your instance (an end-entity certificate, not a certificate authority). Port 80 redirects to HTTPS. The server's name is set from the instance's EC2 public DNS name at first boot and requests for any other name are dropped. You can change it to your own domain.
  • Hardened web tier. PHP runs as its own unprivileged user on a Unix socket that only nginx can reach. nginx passes Firefly III the real client address from the connection, never a header a client sends, limits sign-in attempts per address, refuses cross-site requests to state-changing pages, and refuses the web installer, the web cron URL, the configuration file, the data directory and the source tree.
  • SQLite. The database is one file in /var/lib/firefly-iii, so there is no database server, no database port and no database password to manage.
  • Metadata service blocked. nginx, PHP, the first-boot service and the cron cannot reach the EC2 instance metadata service. The AMI requires IMDSv2.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Firefly III 6.7.9 (AGPL-3.0-or-later), PHP 8.5 FPM and CLI (ondrej/php PPA), nginx, SQLite, cloud-init and the AWS Systems Manager agent, all from Ubuntu 24.04 except Firefly III and PHP.

Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large (2 vCPUs, 8 GiB). A t3.medium is enough for a household or a small business.

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
  • A security group that allows TCP 22 (SSH) from your own networks only, TCP 443 from wherever your users are, and TCP 80 (redirects to HTTPS). No other port is needed.
  • For production, a DNS name you control (for example finance.example.com) and, ideally, a certificate from a certificate authority. Until then the instance uses its EC2 public DNS name with its own self-signed certificate.

Connecting to your instance

Operating system SSH user
Ubuntu 24.04 ubuntu

Step 1: Launch the instance

Launch from the AWS Marketplace page (choose the Firefly III 6.7.9 on Ubuntu 24.04 version), or with the AWS CLI using the AMI ID shown on the listing's launch page:

aws ec2 run-instances --image-id ami-xxxxxxxxxxxxxxxxx --instance-type m5.large \
  --key-name my-key --security-group-ids sg-xxxxxxxx --subnet-id subnet-xxxxxxxx \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=firefly-iii}]'

First boot takes about a minute once the instance is up: it creates the database, the encryption keys, the owner account and the certificate. The web interface stays offline until that has finished.

Step 2: Connect to your instance

ssh -i my-key.pem ubuntu@<public-ip>

Step 3: Check the services

systemctl is-active nginx.service php8.5-fpm.service firefly-iii-cron.timer
sudo ss -ltnp | awk 'NR==1 || /:(22|80|443) /'
sudo ss -lxp | grep firefly-fpm
active
active
active
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      4096         0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=903,fd=3),("systemd",pid=1,fd=227))
LISTEN 0      511          0.0.0.0:80        0.0.0.0:*    users:(("nginx",pid=55399,fd=5),("nginx",pid=55398,fd=5),("nginx",pid=45804,fd=5))
LISTEN 0      511          0.0.0.0:443       0.0.0.0:*    users:(("nginx",pid=55399,fd=7),("nginx",pid=55398,fd=7),("nginx",pid=45804,fd=7))
LISTEN 0      4096            [::]:22           [::]:*    users:(("sshd",pid=903,fd=4),("systemd",pid=1,fd=228))
LISTEN 0      511             [::]:80           [::]:*    users:(("nginx",pid=55399,fd=6),("nginx",pid=55398,fd=6),("nginx",pid=45804,fd=6))
LISTEN 0      511             [::]:443          [::]:*    users:(("nginx",pid=55399,fd=8),("nginx",pid=55398,fd=8),("nginx",pid=45804,fd=8))
u_str LISTEN 0      4096                         /run/php/firefly-fpm.sock 106981            * 0    users:(("php-fpm8.5",pid=45809,fd=10),("php-fpm8.5",pid=45808,fd=10),("php-fpm8.5",pid=45799,fd=8))

Only SSH, HTTP and HTTPS listen on the network. PHP listens only on its Unix socket.

Step 4: Get your address and the owner password

First boot writes everything you need to sign in to a file only root can read:

sudo cat /root/firefly-iii-credentials.txt
# Firefly III 6.7.9 - generated on first boot by firefly-iii-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret.

FIREFLY_URL=https://ec2-44-201-132-253.compute-1.amazonaws.com/
FIREFLY_ADMIN_EMAIL=admin@example.com
FIREFLY_ADMIN_PASSWORD=<24 random letters and digits>
FIREFLY_TLS_SHA256=B5:D7:CC:DC:6B:0D:DE:85:54:BC:D1:94:32:B3:0E:ED:01:1F:57:D0:8F:34:EF:03:14:9F:39:64:CD:BF:D1:78
...
  • FIREFLY_URL is your Firefly III address.
  • FIREFLY_TLS_SHA256 is the fingerprint of the instance's own certificate. Your browser will warn that the certificate is not trusted; compare the fingerprint it shows with this one before you continue. Replace it with a certificate from a certificate authority for your own name when you can (Step 10).
  • FIREFLY_ADMIN_EMAIL / FIREFLY_ADMIN_PASSWORD sign in to Firefly III as its owner.

Step 5: Run the self-test

The image includes an end-to-end test. Over HTTPS on the instance it checks that port 80 redirects, that the installer, the front controller path, the cron URL, the configuration file, the data directory and the sources are refused, that registration is closed, that the owner signs in through Firefly III's own login form, and that a wrong password and common default passwords are refused:

sudo firefly-iii-cred-roundtrip
FIREFLY_ROUNDTRIP_OK https 301 + no installer/index.php/cron URL/env/data/sources + health + registration closed + owner sign-in (Firefly III's own login form, CSRF token) + wrong and default passwords refused

Step 6: Sign in to the web interface

Open FIREFLY_URL in your browser, check the certificate fingerprint, and sign in with FIREFLY_ADMIN_EMAIL and FIREFLY_ADMIN_PASSWORD.

The Firefly III sign-in page with the e-mail address admin@example.com entered, an empty password field, a Remember me checkbox, a Sign in button and an I forgot my password link

On the first sign-in Firefly III asks for the name of your bank, the balance of your main account and its currency, an optional savings balance and your language:

The Firefly III Getting started page with the bank name Example Bank, a balance of 2500 in euro, a savings balance of 1000, the language English (US) and a Submit button

Submit, and the dashboard opens with your accounts, a balance chart and your net worth:

The Firefly III dashboard with summary boxes for in and out this period, subscriptions to pay, budgets and a net worth of 3,500 euro, a Your accounts balance chart for November 2026, and panels for the Example Bank, Example Bank savings account and Cash wallet accounts

Change the e-mail address on your profile page (/profile, the person icon at the top right). To change the password, run one of these on the instance. The first generates a new random password; the second reads yours (20 to 72 letters and digits) from the terminal, never from the command line. Either way every session is signed out and the new password is written to /root/firefly-iii-credentials.txt:

sudo firefly-iii-set-password
# Type <new-password> at the prompt; nothing is echoed.
read -rs -p 'New Firefly III password: ' P; echo
printf '%s\n' "$P" | sudo firefly-iii-set-password --stdin; unset P

Once you have stored the password somewhere safe, you can delete the FIREFLY_ADMIN_PASSWORD line from /root/firefly-iii-credentials.txt.

Step 7: Record your money

  • Accounts. Add your bank, savings and credit card accounts under Accounts > Asset accounts and Liabilities. Expense and revenue accounts (shops, employers) are created as you record transactions.
  • Transactions. Use Create new > Withdrawal / Deposit / Transfer. Every transaction moves money between two accounts, so balances always add up.
  • Budgets, categories and tags organise spending; Bills track recurring payments and warn when one is missed; Piggy banks set money aside for a goal.
  • Rules (under Automation) file new transactions automatically, for example by description.
  • Reports show income, spending and net worth over any period.

The Firefly III Asset accounts page listing Example Bank (default asset account, 2,500 euro), Example Bank savings account (savings account, 1,000 euro) and Cash wallet (0 euro), with their current balances, last activity and Actions menus, and a total of 3,500 euro

The owner account also has System settings (/settings): Firefly III's configuration, notification settings, update checks (off on this image until you turn them on) and All users, where you invite more users. Self-registration stays closed.

The Firefly III System settings page with a Configuration panel (Firefly III configuration, Transaction links configuration, Check for updates, Settings for notifications), a User administration panel with All users, and a Maintenance panel with a Clear cache button

Step 8: The daily cron

Recurring transactions, bill reminders, auto-budgets and exchange rates are processed by Firefly III's cron. On this image it is a systemd timer that runs it once a day at 03:00 UTC as the unprivileged firefly user; the web cron URL is not exposed. To see the schedule or run it now:

systemctl list-timers firefly-iii-cron.timer --no-pager
sudo systemctl start firefly-iii-cron.service
systemctl show -p Result -p ExecMainStatus firefly-iii-cron.service
NEXT                            LEFT LAST                        PASSED UNIT                   ACTIVATES
Sun 2026-11-08 03:03:14 UTC 5h 15min Sat 2026-11-07 21:18:53 UTC      - firefly-iii-cron.timer firefly-iii-cron.service

1 timers listed.
Pass --all to see loaded but inactive timers, too.
Result=success
ExecMainStatus=0

Step 9: Firefly III's command line

firefly-iii-artisan runs Firefly III's own artisan commands as the firefly user with the same metadata block as the web tier:

sudo firefly-iii-artisan firefly-iii:output-version
6.7.9

Step 10: Use your own domain and certificate

Point a DNS name at the instance (an Elastic IP is a good idea), then:

sudo firefly-iii-set-hostname <your-domain>

This creates a new self-signed certificate for the name, pins nginx to it (other names are dropped), sets Firefly III's APP_URL (used in links in its e-mails) and updates the URL and fingerprint in /root/firefly-iii-credentials.txt. To use a certificate from a certificate authority, replace /etc/nginx/ssl/firefly-iii.crt and firefly-iii.key (keep the key 0600 root) and run sudo systemctl reload nginx.

To send e-mail (password resets, bill reminders), set the MAIL_* values in /etc/firefly-iii/env (see Firefly III's documentation) and run sudo systemctl restart php8.5-fpm.

Step 11: Restrict access to your networks

Limit who can reach the web interface in the instance's security group. For example, to allow HTTPS only from your office network:

aws ec2 authorize-security-group-ingress --group-id sg-xxxxxxxx --protocol tcp --port 443 --cidr <your-mgmt-cidr>
aws ec2 revoke-security-group-ingress --group-id sg-xxxxxxxx --protocol tcp --port 443 --cidr 0.0.0.0/0

Firefly III locks a client address out of sign-in for a minute after five attempts, and nginx separately rate limits sign-in and registration requests per client address.

Step 12: Check the security posture

U=$(sudo sed -n 's/^FIREFLY_URL=//p' /root/firefly-iii-credentials.txt)
C=/etc/nginx/ssl/firefly-iii.crt
for p in login register health; do
  curl -s --cacert "$C" -o /dev/null -w "GET /$p: %{http_code}\n" "${U}$p"
done
for p in install index.php/login api/v1/cron/x .env storage/logs/laravel.log composer.json; do
  curl -s --cacert "$C" -o /dev/null -w "GET /$p: %{http_code}\n" "${U}$p"
done
curl -s --cacert "$C" -o /dev/null -w 'GET /flush from another site: %{http_code}\n' -H 'Sec-Fetch-Site: cross-site' "${U}flush"
curl -s -o /dev/null -w 'GET http://: %{http_code}\n' "${U/https:/http:}"
curl -sk -o /dev/null -w 'GET with an unknown Host: %{http_code}\n' -H 'Host: not-this-server.example' https://127.0.0.1/ || true
systemctl show -p IPAddressDeny nginx.service php8.5-fpm.service
curl -s http://127.0.0.1/healthz
GET /login: 200
GET /register: 200
GET /health: 200
GET /install: 404
GET /index.php/login: 404
GET /api/v1/cron/x: 404
GET /.env: 404
GET /storage/logs/laravel.log: 404
GET /composer.json: 404
GET /flush from another site: 403
GET http://: 301
GET with an unknown Host: 000
IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128

IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128
ok
  • /register answers with "Registration is currently not available": the owner is the only account until you invite others.
  • The installer, the front controller path, the web cron URL, the configuration file, logs and sources are refused. Requests for any name other than the configured one are dropped (000: nginx closes the connection).
  • IPAddressDeny is the metadata-service block on nginx and PHP; the first-boot service and the cron have the same one.
  • http://127.0.0.1/healthz returns ok for a monitoring agent on the instance.

Step 13: Back up your data

Your data is the SQLite database plus any attachments in /var/lib/firefly-iii/storage/upload. Keep /etc/firefly-iii/env too: its APP_KEY decrypts the attachments and stored secrets, and a backup restored without it cannot read them. Copy them to files only root can read, and keep copies off the instance (for example in an encrypted S3 bucket):

sudo -u firefly sqlite3 -readonly /var/lib/firefly-iii/storage/database/database.sqlite .dump \
  | sudo sh -c 'umask 077; gzip > /var/backups/firefly-iii-$(date +%F).sql.gz'
sudo sh -c 'umask 077; tar -C /var/lib/firefly-iii/storage -czf /var/backups/firefly-iii-uploads-$(date +%F).tar.gz upload'
sudo sh -c 'umask 077; cp /etc/firefly-iii/env /var/backups/firefly-iii-env-$(date +%F)'
sudo ls /var/backups/ | grep firefly-iii
firefly-iii-2026-11-07.sql.gz
firefly-iii-env-2026-11-07
firefly-iii-uploads-2026-11-07.tar.gz

Firefly III also exports transactions as CSV under Options > Export data. EBS snapshots of the instance are a simple way to keep point-in-time copies of the whole server.

Step 14: Updates

Ubuntu and PHP security updates install automatically (unattended upgrades). New Firefly III releases are published as new versions of this listing: launch the new version, stop its services, copy your database, uploads and /etc/firefly-iii/env across (keeping the new instance's APP_URL), then run sudo firefly-iii-artisan migrate --force and start the services again.

Step 15: Licences and source

ls /usr/share/doc/firefly-iii/
sed -n '1,4p' /usr/share/doc/firefly-iii/SOURCE.txt
LICENSE
SOURCE.txt
Firefly III 6.7.9 on Ubuntu 24.04 by cloudimg - source and changes

Upstream: the official Firefly III 6.7.9 release archive, https://github.com/firefly-iii/firefly-iii/releases/download/v6.7.9/FireflyIII-v6.7.9.zip
(sha256 f806ac9c8d34f570d954172a6ea4718ee387350d6c9b9b8ef7ba02902dc63752; GitHub tag v6.7.9).

Firefly III is licensed under the GNU Affero General Public License version 3 or later. SOURCE.txt names the exact upstream archive, the files that are not shipped (tests, sample configuration, Apache and IIS files) and the six Symfony libraries raised for security, so the corresponding source of the running version is the upstream release plus those six releases.

Security notes

  • Secrets. The owner password is in /root/firefly-iii-credentials.txt until you remove it; Firefly III stores only its bcrypt hash. APP_KEY and the cron token are in /etc/firefly-iii/env, readable by root and the firefly group only (not by the web server). The TLS key is in /etc/nginx/ssl/firefly-iii.key (root only). No secret is on any command line, in a systemd unit or in a log.
  • Client addresses. nginx gives Firefly III the address of the connection; forwarding headers sent by clients are replaced or removed. Behind a load balancer every request therefore comes from the load balancer's address.
  • PHP. The PHP pool runs as firefly, cannot start other programs, and is confined to Firefly III's code, data and configuration directories.

Support

cloudimg provides support for this image by email at support@cloudimg.co.uk. Firefly III documentation is at docs.firefly-iii.org.