Hands-off script for setting up Firefly III for Docker

Firefly III is an open source financial management system. I’m trying it out in renewing my search for an accounting system I can use from a browser. Am I ultimately going to keep using it? I’m still kind of playing around with it, but it’s likely I’ll look for something else. I guess when it comes to ease of use, nothing really compares to GnuCash’s simplicity. And that’s largely what I’m looking for.

Firefly III, sorry to say, doesn’t even come close. I might write a review for it later, contrasting it with GnuCash and comparing it against the rules (or, largely, lack thereof) with double-entry accounting.

Anyway, copy the installation script to a .sh file on your Docker machine and give it the requisite permissions, then run it. Make sure to copy off everything from output at the end and store it off somewhere, preferably in a password manager like KeePass, since you’ll need it for running the update script.

Like with the install script for Guacamole, pay attention to the subnet and IPs this will be using and change those if necessary. If you don’t select a port number at the first prompt, it’ll randomly select a port between 40,000 and 60,000. And unless you have a need for this to be on a specific port, I suggest just letting the script pick one at random.

Having a separate script that is run periodically – e.g. as a cron job – to back up the volumes for the MySQL and Firefly containers would also be a good idea.

Installation script

#!/bin/bash

read -p "Port number for Firefly web interface [Enter to pick random port]: " firefly_port_number
echo

if [ -z $firefly_port_number ]; then
    firefly_port_number=$(curl -s "https://www.random.org/integers/?num=1&min=40000&max=60000&col=1&base=10&format=plain&rnd=new")
fi

# Random passwords and app key generated using Random.org so you don't have to supply them

root_secure_password=$(curl -s "https://www.random.org/strings/?num=1&len=16&digits=on&upperalpha=on&loweralpha=on&unique=on&format=plain&rnd=new")
firefly_mysql_password=$(curl -s "https://www.random.org/strings/?num=1&len=16&digits=on&upperalpha=on&loweralpha=on&unique=on&format=plain&rnd=new")
firefly_app_key=$(curl -s "https://www.random.org/strings/?num=1&len=32&digits=on&upperalpha=on&loweralpha=on&unique=on&format=plain&rnd=new")

sudo docker pull mysql
sudo docker pull fireflyiii/core

# Creating the volumes for persistent storage

sudo docker volume create firefly_iii_upload
sudo docker volume create firefly_mysql_data

# Creating the network. This allows the containers to "see" each other
# without having to do some odd port forwarding.
#
# Change the subnet and gateway if you need to.

firefly_network_subnet=192.168.11.0/24
firefly_network_gateway=192.168.11.1
mysql_host_ip=192.168.11.2
firefly_host_ip=192.168.11.3

# Remove the ".local" if necessary. Override entirely if needed.

full_hostname=$(hostname).local

sudo docker network create \
--subnet=$firefly_network_subnet \
--gateway=$firefly_network_gateway \
firefly-net

# Setting up the MySQL container

sql_create="\
CREATE DATABASE firefly; \
\
CREATE USER 'firefly_user'@'%' \
IDENTIFIED BY '$firefly_mysql_password'; \
\
GRANT ALL PRIVILEGES \
ON firefly.* \
TO 'firefly_user'@'%'; \
\
FLUSH PRIVILEGES;"

echo Creating MySQL container

sudo docker run -d \
--name firefly-mysql \
-e MYSQL_ROOT_PASSWORD=$root_secure_password \
-v firefly_mysql_data:/var/lib/mysql \
--network firefly-net \
--ip $mysql_host_ip \
--restart unless-stopped \
mysql

# Sleep for 30 seconds to allow the new MySQL container to fully start up before continuing.

echo Let\'s wait about 30 seconds for MySQL to completely start up before continuing.
sleep 30

echo Setting up MySQL database

sudo docker exec firefly-mysql \
mysql --user=root --password=$root_secure_password -e "$sql_create"

echo Creating Firefly-III container

sudo docker run -d \
--name firefly \
-v firefly_iii_upload:/var/www/html/storage/upload \
-e DB_HOST=$mysql_host_ip \
-e DB_DATABASE=firefly \
-e DB_USERNAME=firefly_user \
-e DB_PORT=3306 \
-e DB_CONNECTION=mysql \
-e DB_PASSWORD=$firefly_mysql_password \
-e APP_KEY=$firefly_app_key \
-e APP_URL=http://$full_hostname:$firefly_port_number \
-e TRUSTED_PROXIES=** \
--network firefly-net \
--ip $firefly_host_ip \
--restart unless-stopped \
-p $firefly_port_number:8080 \
fireflyiii/core

echo Done.
echo
echo MySQL root password: $root_secure_password
echo MySQL firefly password: $firefly_mysql_password
echo Firefly App Key: $firefly_app_key
echo Firefly web interface port: $firefly_port_number
echo
echo Store off these passwords as they will be needed for later container updates.
echo To access the Firefly III web interface, go to http://$full_hostname:$firefly_port_number

Update script

#!/bin/bash

read -s -p "MySQL Firefly user password: " firefly_mysql_password
echo
read -s -p "Firefly app key: " firefly_app_key
echo
read -p "Port number for Firefly web interface: " firefly_port_number
echo

# Make sure these match the IPs in the installation script

mysql_host_ip=192.168.11.2
firefly_host_ip=192.168.11.3

# Remove the ".local" if necessary

full_hostname=$(hostname).local

echo Stopping the containers.

sudo docker stop firefly-mysql
sudo docker stop firefly

echo Deleting the containers.

sudo docker rm firefly-mysql
sudo docker rm firefly

sudo docker pull mysql
sudo docker pull fireflyiii/core

echo Creating MySQL container

sudo docker run -d \
--name firefly-mysql \
-v firefly_mysql_data:/var/lib/mysql \
--network firefly-net \
--ip $mysql_host_ip \
--restart unless-stopped \
mysql

echo Creating Firefly-III container

sudo docker run -d \
--name firefly \
-v firefly_iii_upload:/var/www/html/storage/upload \
-e DB_HOST=$mysql_host_ip \
-e DB_DATABASE=firefly \
-e DB_USERNAME=firefly_user \
-e DB_PORT=3306 \
-e DB_CONNECTION=mysql \
-e DB_PASSWORD=$firefly_mysql_password \
-e APP_KEY=$firefly_app_key \
-e APP_URL=http://$(hostname).local:$firefly_port_number \
-e TRUSTED_PROXIES=** \
--network firefly-net \
--ip $firefly_host_ip \
--restart unless-stopped \
-p $firefly_port_number:8080 \
fireflyiii/core

echo Done.