Applications Azure

ezBookkeeping on Ubuntu 24.04 on Azure User Guide

| Product: ezBookkeeping on Ubuntu 24.04 LTS on Azure

Overview

ezBookkeeping is a lightweight, open source, self hosted personal finance application for tracking accounts, income and expenses across multiple currencies. It pairs precise double entry style bookkeeping with a fast, mobile friendly web interface, so capturing a purchase takes seconds while the underlying ledger stays accurate. The cloudimg image delivers ezBookkeeping fully installed and configured on Ubuntu 24.04 as a single hardened Go service behind an nginx reverse proxy, so a complete private bookkeeping service is running within minutes of launch. Backed by 24/7 cloudimg support.

ezBookkeeping is licensed under the MIT License. All product and company names are trademarks or registered trademarks of their respective holders. This image repackages the upstream open source release with cloudimg's provisioning and support.

What is included:

  • ezBookkeeping 1.6.1 (the official upstream linux-amd64 release, MIT), a single self contained Go binary serving both the JSON API and the prebuilt web frontend
  • nginx as a reverse proxy on port 80, forwarding to the application on loopback 127.0.0.1:8080
  • All persistent data (the SQLite database, the object store for receipt images and avatars, and the application log) on a dedicated, independently resizable Azure data disk mounted at /var/lib/ezbookkeeping
  • Two secrets generated per VM on first boot: the key that signs every login session, and the password for the single administrator account, written to a root only file
  • Self registration switched off, so nobody can claim your instance before you sign in
  • ezbookkeeping.service and nginx.service as systemd units, enabled and active
  • 24/7 cloudimg support

ezBookkeeping sign-in page served on first boot, with self registration disabled

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point — ezBookkeeping is a single Go binary with an embedded database and idles at around 25 MiB of memory. NSG inbound: allow 22/tcp from your management network and 80/tcp (HTTP) from your users. Add 443/tcp if you enable HTTPS.

Step 1 — Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for ezBookkeeping by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create and Create.

Step 2 — Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name ezbookkeeping \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

Open HTTP to reach the web UI:

az vm open-port --resource-group <your-rg> --name ezbookkeeping --port 80 --priority 900

Step 3 — Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 — Confirm the services are running

Both services that back ezBookkeeping should report active, and the unauthenticated /healthz.json endpoint answers through nginx on port 80:

systemctl is-active ezbookkeeping nginx
curl -s http://127.0.0.1/healthz.json; echo

Expected: two lines of active, then a JSON body reporting "status":"ok" and "version":"1.6.1".

ezBookkeeping and nginx systemd units active, with the secret guard having passed

Step 5 — Retrieve your administrator credentials

On the first boot of every VM, a one-shot service (ezbookkeeping-firstboot.service) generates a session signing key and an administrator password that are both unique to that VM, creates the single administrator account directly in the database, and writes the credentials to a root only file. No shared or default login ships in the image.

sudo cat /root/ezbookkeeping-credentials.txt

The file (mode 0600, root only) contains the sign-in URL (EZBOOKKEEPING_URL), the username (EZBOOKKEEPING_USERNAME) and the password (EZBOOKKEEPING_PASSWORD).

You can prove the sign-in round-trip from the VM's own shell. This reads the per-VM credentials, posts a real sign-in, then uses the returned session token against an authenticated endpoint:

U=$(sudo grep '^EZBOOKKEEPING_USERNAME=' /root/ezbookkeeping-credentials.txt | cut -d= -f2-)
P=$(sudo grep '^EZBOOKKEEPING_PASSWORD=' /root/ezbookkeeping-credentials.txt | cut -d= -f2-)
TOKEN=$(curl -s -X POST http://127.0.0.1/api/authorize.json \
  -H 'Content-Type: application/json' \
  -d "$(jq -nc --arg u "$U" --arg p "$P" '{loginName:$u,password:$p}')" \
  | jq -r '.result.token // empty')
echo -n 'signed in as -> '
curl -s -H "Authorization: Bearer $TOKEN" \
  http://127.0.0.1/api/v1/users/profile/get.json | jq -r '.result.username'

Expected: signed in as -> admin, confirming the credentials in the file authenticate end to end.

Health endpoint, binary version and the cloudimg configuration applied to the image

Step 6 — Sign in and review the overview

Browse to http://<vm-public-ip>/ and sign in with the username and password from the credentials file. ezBookkeeping opens the Overview, which summarises the current month's income and expense, your asset and liability totals, net assets, and an income and expense trend chart.

ezBookkeeping overview with asset summary, net assets and the income and expense trend chart

Step 7 — Add accounts and record transactions

Open Accounts from the left navigation and add your accounts — cash, current and savings accounts, credit cards, investments or debts. Then open Transaction Categories and either create your own categories or accept the preset set.

With accounts and categories in place, record spending from Transaction Details. Each transaction carries a time, category, amount, account, optional tags, a description and, if you want, an attached receipt image. The list view totals income and expense for the selected date range.

Transaction list showing recorded income and expense against real accounts and categories

Use Import on the transaction list to bring in existing records from CSV, and Export from the settings menu to take your data out again at any time.

Step 8 — Read the statistics

Statistics & Analysis breaks your spending down by category, by account and over time, as pie, bar or trend charts. Insights Explorer goes further for ad hoc questions about your data.

Statistics and analysis with expense broken down by category as a pie chart

Step 9 — Confirm the version, the stack and the data disk

/opt/ezbookkeeping/ezbookkeeping --version
findmnt /var/lib/ezbookkeeping
sudo ls -l /var/lib/ezbookkeeping/data

Expected: ezBookkeeping version 1.6.1, /var/lib/ezbookkeeping mounted from the dedicated data disk (/dev/sdc), and the SQLite database owned by the ezbookkeeping service account at mode 0640. The database, the object store and the logs all live on that disk, which is independently resizable and survives instance replacement — resize it from the Azure portal if you need more room.

The dedicated data disk holding the database, object store and logs

First-boot service and security model

A one-shot ezbookkeeping-firstboot.service runs after the network is up. It generates the two per-VM secrets, writes them into the configuration, initialises the database schema, creates the single administrator account with the offline CLI, resolves the instance address from the Azure instance metadata service, writes the credentials file at mode 0600 (root only), and only then allows anything to serve.

That last point matters. Both ezbookkeeping.service and nginx.service are gated on a bootstrap-ready marker that first boot creates after the credentials are written, so on a brand new VM nothing answers port 80 until the lockdown is complete. There is no window in which a freshly launched instance is reachable without its own unique credentials.

systemctl is-active ezbookkeeping-firstboot.service
sudo stat -c '%a %U:%G %n' /root/ezbookkeeping-credentials.txt
test -f /var/lib/cloudimg/ezbookkeeping-bootstrap-ready && echo 'bootstrap marker present'

Expected: active, then 600 root:root /root/ezbookkeeping-credentials.txt, then bootstrap marker present.

The session signing key deserves a note of its own. ezBookkeeping signs every login session with [security] secret_key, and the upstream sample configuration ships that value empty — which the application resolves to a built-in default. Any instance left that way signs its sessions with a value anyone can look up. This image never ships a usable key: one is generated for your VM on first boot, and a guard that runs before the service starts refuses to launch the application if the key is missing, still the placeholder, or the upstream default.

sudo awk -F= '/^secret_key/ {gsub(/ /,"",$2); print "session signing key length: " length($2) " chars"}' \
  /etc/ezbookkeeping/ezbookkeeping.ini
sudo /usr/local/sbin/ezbookkeeping-secret-guard.sh

Expected: a key length of 48 characters, then the guard confirming the per-VM signing key is valid. The key itself is never printed.

The application is bound to the loopback address only, so nginx on port 80 is the single public entry point:

sudo ss -tlnp | grep -E ':80 |:8080 '

ezBookkeeping bound to loopback only, with nginx as the single public listener

Opening self registration for household members

Self registration is disabled by default, so a passer-by cannot create an account on your instance before you sign in for the first time. The registration route is not merely hidden — it is not served at all, and the sign-in page shows the "Create an account" link greyed out and inactive.

To invite household members, enable registration and restart the service:

sudo sed -i 's/^enable_register = false/enable_register = true/' /etc/ezbookkeeping/ezbookkeeping.ini
sudo systemctl restart ezbookkeeping

Once everyone has registered, set the value back to false and restart again so the instance is closed to new sign-ups. As an alternative that never opens registration at all, you can create each account yourself from the VM:

sudo -u ezbookkeeping /opt/ezbookkeeping/ezbookkeeping userdata user-add \
  --conf-path=/etc/ezbookkeeping/ezbookkeeping.ini \
  --username <new-username> --email <new-email> \
  --nickname <display-name> --password <new-password> --default-currency USD

Enabling HTTPS with your own domain

The image serves plain HTTP on port 80 so it works immediately on a bare IP address. For production use, terminate TLS in front of the VM with an Azure Application Gateway or Azure Front Door, or issue a certificate directly on the VM once a DNS record points at it:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>

Certbot rewrites the nginx site and installs a renewal timer. After enabling HTTPS, update the [server] section of /etc/ezbookkeeping/ezbookkeeping.ini so protocol is https and domain is your hostname, then restart the service so generated links use the right address. Remember to allow 443/tcp in the NSG.

Backup and maintenance

Everything worth backing up lives under /var/lib/ezbookkeeping on the dedicated data disk: the SQLite database, the object store and the logs. The simplest backup is a snapshot of that disk from the Azure portal or CLI. For a file level backup, stop the service briefly so the database is quiescent, archive the directory, then start it again:

sudo systemctl stop ezbookkeeping
sudo tar czf /var/tmp/ezbookkeeping-backup.tar.gz -C /var/lib ezbookkeeping
sudo systemctl start ezbookkeeping

Ubuntu security updates are applied automatically by unattended-upgrades, which is enabled in the image. To move to a newer ezBookkeeping release, download the upstream linux-amd64 tarball, replace the contents of /opt/ezbookkeeping, and restart the service — your configuration in /etc/ezbookkeeping/ezbookkeeping.ini and your data on the data disk are untouched, and the application updates its own database schema on start.

Support

cloudimg provides 24/7 technical support for this image by email at support@cloudimg.co.uk and via live chat, with a one hour average response for critical issues. We can help with deployment, retrieving the first-boot credentials, opening registration for household members, multi currency configuration, importing existing records, TLS termination, backups and scaling.