zenodotus280

Actual Budget - Actually Easy

Self-hosting Actual Budget on Proxmox using a Debian LXC;


I use Proxmox and I like LXC containers because there are fewer abstractions compared to Docker and it keeps me closer to what actually happening. Where possible, I will try to install in a Debian LXC unless it's unreliable or tedious (especially updates) and then use Docker Compose in the LXC instead.

Only a few weeks after I set up Actual back in January there was a substantial change to how the program is organized which meant any future updates wouldn't make it my way. The 25.3.0 release comes with the following warning:

Starting this release, the actual-server repository will no longer be updated. If you use a local install, please review these docs for how to migrate.

I chose not to follow the migration steps and preferred to just export, backup the LXC, re-create the LXC using the same MAC address, and then re-import the budget. There aren't any notable direct benefits from the upgrade which is why I delayed for nearly 6 months (and my server isn't exposed to the internet - I access via VPN) but web apps can't go on forever without some updates so it seemed time to update my script and set things up again.

I experimented and found that I needed very few changes overall.

  1. yarn is no longer required which lowers the RAM requirement to 512 MB.
  2. NPM handles updates rather than systemd hooks to pull changes via git.
  3. The cat > /path/to/file <<EOF structure is preferred over cat << EOF > /path/to/file to account for edge cases like using sudo tee where the redirection would happen before being executed by sudo.
#!/bin/sh

## Prepare OS
apt-get update
apt-get upgrade -y

## Install Actual
apt-get install -y npm
npm install --location=global @actual-app/sync-server
mkdir -p /opt/actual-server
chown -R root:root /opt/actual-server
chmod -R 755 /opt/actual-server

## SystemD Service File
cat > /etc/systemd/system/actual-server.service <<EOF
[Unit]
Description=Actual-Server (https://actualbudget.org)
After=network.target

[Service]
WorkingDirectory=/opt/actual-server
ExecStartPre=/usr/bin/npm update -g @actual-app/sync-server
ExecStart=actual-server

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload

## Configuration including HTTPS
openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /opt/actual-server/selfhost.key -out /opt/actual-server/selfhost.crt
cat > /opt/actual-server/config.json <<EOF
{
  "https": {
    "key": "selfhost.key",
    "cert": "selfhost.crt"
  }
}
EOF

## Enable and Start
systemctl enable --now actual-server.service
apt-get autoremove -y
apt-get autoclean -y
Thoughts? Leave a comment

Comments
  1. Elias Sousdes — Mar 21, 2025:

    hi and thank you for the instructions, is it possible to do the same in Alpine LXC?

  2. zenodotus280Jun 15, 2025:

    Yes - I think so. I recently updated my instructions to account for some changes that happened in February. I could try it again.