Deployment guide

Actual Budget

Overview

Actual Budget is a free, open source, local-first personal finance application built around the envelope budgeting method. You give every unit of money a job across category groups, reconcile your accounts and get a precise picture of your finances. It runs as a self-hosted sync server with a bundled web app, and the same server keeps the Actual desktop and mobile clients in sync, so your financial data stays on infrastructure you control.

This SecureAnyCloud image delivers Actual Budget fully installed and configured on Ubuntu 24.04, as a Node.js sync server behind an nginx reverse proxy. A complete budgeting service is running within minutes of launch.

What you get:

  • Actual Budget 26.6 (the @actual-app/sync-server 26.6.0 release, MIT), installed globally with npm on Node.js 22 LTS
  • nginx as a reverse proxy on port 80, forwarding to the sync server on loopback 127.0.0.1:5006
  • All persistent data on a dedicated, independently resizable Azure data disk mounted at /var/lib/actual: the account.sqlite server database, plus the server-files and user-files budget blobs
  • A per-VM server password generated on first boot and written to a root-only file, so no default or shared login ships in the image
  • actual-budget.service and nginx.service as enabled, active systemd units
  • 24/7 SecureAnyCloud support

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

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting size. Scale up for larger households or heavy sync activity.

Configure the network security group (NSG) to allow inbound 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 Actual Budget by SecureAnyCloud, and select Create.

On the Basics tab, 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).

Select Review + create, then Create.

Step 2 - Deploy from the Azure CLI

Accept the Marketplace terms once, then create the VM:

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:actual-budget-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name actual-budget \
  --image sac1647283583153:actual-budget-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

Open HTTP to reach the web interface:

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

Step 3 - Connect to your VM

Connect to the VM over SSH as the administrator user you created:

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

Both services that back Actual Budget should report active. The unauthenticated /account/needs-bootstrap health endpoint answers through nginx on port 80.

systemctl is-active actual-budget nginx curl -s http://127.0.0.1/account/needs-bootstrap; echo

Expect two lines of active, then a JSON body reporting "bootstrapped":true. The Actual sync server listens only on the loopback address 127.0.0.1:5006. nginx on port 80 is the only exposed application port, so the server is never reachable directly.

Step 5 - Retrieve your server password

On the first boot of every VM, a one-shot service (actual-budget-firstboot.service) starts the sync server and generates a server password that is unique to that VM. It applies the password through Actual's own bootstrap mechanism, which bcrypt-hashes it into the server database. No shared or default password ships in the image.

Read the credentials file as root:

sudo cat /root/actual-budget-credentials.txt

The file (mode 0600, root only) contains the sign-in URL (ACTUAL_URL) and the server password (ACTUAL_SERVER_PASSWORD).

You can verify the sign-in round trip from the VM's own shell. The command below reads the per-VM password and posts a real sign-in. A correct password answers HTTP 200, and the server returns a session token:

PASS=$(sudo grep '^ACTUAL_SERVER_PASSWORD=' /root/actual-budget-credentials.txt | cut -d= -f2-)
echo -n 'sign-in HTTP status -> ' curl -s -o /dev/null -w '%{http_code}\n' -X POST http://127.0.0.1/account/login \
  -H 'Content-Type: application/json' \
  -d "$(jq -nc --arg p "$PASS" '{loginMethod:"password",password:$p}')"

The expected output is sign-in HTTP status -> 200, which confirms that the password in the file signs in.

Step 6 - Sign in and create your budget

Browse to http://<vm-public-ip>/ and enter the server password from the credentials file.

Actual offers three options: Start fresh with a new empty budget, Import my budget from an Actual, YNAB or nYNAB export, or View demo data. Choose Start fresh to begin.

Actual opens the monthly envelope budget. Assign every unit of available money to a category group, so you always know what is left to spend.

Step 7 - Add accounts and review reports

Open Accounts and add your asset accounts, such as checking, savings and credit cards. You can create a local account and enter transactions manually, import QIF/OFX/QFX files, or configure bank sync so transactions download automatically.

The Reports dashboard summarizes your finances with configurable widgets for net worth, cash flow, and income and expenses over time.

To keep budgeting on the move, install the Actual desktop or mobile app and point it at http://<vm-public-ip>/. Enter the same server password, and your budget stays in sync across every device.

Step 8 - Confirm the version, the stack and the data disk

Check the sync server version, the Node.js version and the data disk mount:

node -e "console.log('@actual-app/sync-server ' + require('/opt/actual/lib/node_modules/@actual-app/sync-server/package.json').version)"
node --version findmnt /var/lib/actual

Expect @actual-app/sync-server 26.6.0, Node.js v22, and /var/lib/actual mounted from the dedicated data disk (/dev/sdc). The server database and all budget files live on that disk. It is independently resizable and survives instance replacement. Resize it from the Azure portal if you need more room.

First-boot service and security model

A one-shot actual-budget-firstboot.service runs after the network is up. It does the following, in order:

  • Starts the sync server.
  • Generates a fresh server password unique to the VM.
  • Applies the password through the server's own POST /account/bootstrap endpoint.
  • Resolves the instance address from the Azure instance metadata service.
  • Writes the credentials file at mode 0600 (root only).
  • Drops a sentinel so the service runs exactly once.

The image ships with an empty database and no usable login. The per-VM password is created on first boot. Verify the service state and the file permissions:

systemctl is-active actual-budget-firstboot.service
sudo stat -c '%a %U:%G %n' /root/actual-budget-credentials.txt

Expect active, then 600 root:root /root/actual-budget-credentials.txt.

Enabling HTTPS with your own domain

The image serves the web interface over plain HTTP on port 80. For a browser-trusted certificate, point a DNS record at the VM and open port 443 in the NSG. Then install a certificate from your CA, for example Let's Encrypt:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com

Certbot updates the nginx site to serve your domain certificate. Actual runs behind the proxy on loopback, so no application configuration change is needed. Your budget is then reachable over HTTPS at your domain.

Backup and maintenance

Actual stores everything under /var/lib/actual on the dedicated data disk, including the account.sqlite server database and all budget files. A backup is therefore a single directory. Snapshot the data disk and OS disk from the Azure portal for a full point-in-time copy, or archive the tree:

sudo tar -C /var/lib -czf /var/backups/actual-$(date +%F).tar.gz actual

Keep the OS current with sudo apt-get update && sudo apt-get upgrade. The image ships with unattended security updates enabled.

Review the Actual Budget documentation before moving between releases, and always back up before an upgrade.

Actual also supports optional per-file end-to-end encryption, configured inside the app. Use it if you want budget data encrypted at rest with a key only you hold.

Support

This image is backed by 24/7 SecureAnyCloud support for deployment and initial configuration, retrieving the first-boot server password, multi-device sync setup, importing existing budgets from YNAB, nYNAB or Actual exports, end-to-end encryption, HTTPS and custom domain setup, performance tuning and storage administration.

Email sales@secureanycloud.com or use the live chat in the support portal. Critical issues receive a one-hour average response.

Deploy on Azure

Launch Actual Budget on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure