Self-hosting your financial data instead of entrusting it to third-party services offers significant advantages in terms of data privacy and control. Actual Budget, an open-source budgeting tool, is an ideal solution for this need and can be easily set up with Docker Compose. In this guide, we will cover how to set up Actual Budget on your own server step-by-step, including Nginx reverse proxy and SSL configuration.
Actual Budget primarily focuses on manual or CSV import for data entry, but it can also offer bank connectivity through third-party integrations (as experimental features) like SimpleFIN or GoCardless. This approach allows you to keep your financial information more isolated and under control, making it a preferred choice for many users, especially given the sensitivity of personal financial data. Hosting it on your own infrastructure enables you to have full control over the application's behavior and ensure your data security.
ℹ️ Why Should I Self-Host My Financial Data?
Your financial data is among the most targeted information in identity theft and fraud cases. While third-party financial applications offer convenience, you surrender control and security of your data to the provider. Self-hosting gives you full authority over where and how this data is stored, thus maximizing your privacy protection.
What is Actual Budget and Why Self-Host It?
Actual Budget is a web-based personal finance and budgeting application that embraces the philosophy of "zero-based budgeting" or "envelope budgeting." It encourages users to assign a job to every dollar, making it easier to control spending and achieve financial goals. The application offers essential financial management features such as categorized expenses, income tracking, budget creation, reporting, and account management.
Self-hosting becomes particularly appealing for applications like Actual Budget because financial data is extremely sensitive. While cloud-based solutions store your data on a third party's servers, when you self-host, the physical location and access control of this data are entirely in your hands. This provides an additional layer of security against potential data breaches and is an indispensable approach for those who value digital privacy. Furthermore, you can optimize the application's performance and resource usage according to your own needs.
Prerequisites and Infrastructure Preparation
To run Actual Budget on your own server, there are some basic prerequisites. Completing these steps thoroughly will ensure a smooth installation process.
First, you will need a server. This can be a Virtual Private Server (VPS) or a physical (bare-metal) server. It is recommended that your server has at least 512MB of RAM (it might use 80-120MB RAM when idle) and a Linux distribution (e.g., Ubuntu, Debian) capable of running Docker and Docker Compose. Second, to access the application over the internet, you need to have a domain or subdomain and point it to your server's IP address. Finally, to ensure secure access via HTTPS, we will need to configure a reverse proxy like Nginx and an SSL certificate via Let's Encrypt.
We can start by installing Docker and Docker Compose on your server. If they are not already installed, you can use the following commands:
# Update system packages
sudo apt update
sudo apt install ca-certificates curl gnupg -y
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the Docker APT repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Update the package list again and install Docker Engine and Docker Compose plugin
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y
# Add the user to the docker group to run Docker without sudo
sudo usermod -aG docker $USER
newgrp docker # To activate the group immediately, restarting the session also works
After these steps, your server will be ready to run the Docker environment. Make sure you have also completed the domain redirection through your DNS provider. For example, you can use a subdomain like finances.yourdomain.com.
Setup Steps with Docker Compose
Setting up Actual Budget with Docker Compose is quite straightforward. With a single YAML file, we can easily bring up the application, which hosts both the server and the web interface. This approach greatly simplifies managing dependencies and updating the application.
First, create a directory for Actual Budget on your server and navigate into it:
mkdir actualbudget
cd actualbudget
Now, create a file named docker-compose.yml in this directory and paste the following content:
version: '3.8'
services:
actual-server:
image: actualbudget/actual-server:latest
container_name: actual_server
restart: unless-stopped
environment:
# ACTUAL_DATA_DIR: /data # /data is used by default, no need to change
# ACTUAL_PORT: 5000 # 5000 is used by default, valid within the container.
ACTUAL_PASSWORD: "yourpasswordhere" # Set the admin password during initial setup
ACTUAL_TRUSTED_PROXIES: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" # Recommended if using a reverse proxy like Nginx.
volumes:
- ./data:/data # Mounts to host directory for persistent data
ports:
- "127.0.0.1:5000:5000" # Only accessible via localhost, Nginx will forward to this port.
In this docker-compose.yml file, we define a single service named actual-server. It hosts both the backend API and the web interface of Actual Budget and manages the data. The ./data:/data specified in the volumes section ensures that data is persistently stored in the actualbudget/data directory on your server. Setting the initial administrator password via the ACTUAL_PASSWORD environment variable is crucial. The ACTUAL_TRUSTED_PROXIES variable helps in correctly detecting the client's IP address when a reverse proxy like Nginx is used. With ports: - "127.0.0.1:5000:5000", we bind the container's 5000 port only to the host's 5000 port on the localhost interface. This will allow Nginx to access Actual Budget and prevent direct external access.
After saving the file, you can start Actual Budget by running the following command in the same directory:
docker compose up -d
This command will download the Docker image, create the service, and run it in the background. You can check the service status with docker compose ps. The initial setup might take some time, but it's usually ready within a few minutes.
Nginx Reverse Proxy and SSL Configuration
After running the Actual Budget service with Docker Compose, we need to access the application securely and externally. This is where Nginx comes in as a reverse proxy. Nginx will receive incoming HTTPS requests, perform SSL termination, and forward these requests to the internal Docker service. This setup provides security, performance, and the flexibility to host multiple web applications on a single server.
To install Nginx, you can use the following command:
sudo apt install nginx -y
After Nginx installation, let's create a virtual host configuration for Actual Budget. To do this, create a new file in the /etc/nginx/sites-available/ directory, for example, actualbudget.conf:
sudo nano /etc/nginx/sites-available/actualbudget.conf
Paste the following configuration into the file. Don't forget to replace finances.yourdomain.com with your own domain or subdomain.
server {
listen 80;
server_name finances.yourdomain.com; # Enter your domain name here
location / {
proxy_pass http://localhost:5000; # Host port of the Actual Budget server container
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
This configuration specifies that Nginx will forward requests coming from port 80 to finances.yourdomain.com and pass these requests to the Actual Budget server at localhost:5000. Save and close the file.
Now, let's enable this configuration by creating a symbolic link and restarting Nginx:
sudo ln -s /etc/nginx/sites-available/actualbudget.conf /etc/nginx/sites-enabled/
sudo nginx -t # Check for errors in the configuration file
sudo systemctl restart nginx
With this step, you can now access Actual Budget via HTTP using your domain address. However, for financial data, using HTTPS is mandatory. Let's obtain a free SSL certificate with Let's Encrypt and Certbot:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d finances.yourdomain.com
Certbot will automatically update your Nginx configuration and install the SSL certificate. During the process, it will ask for your email address and to accept the terms of service. If successful, you can now securely access Actual Budget at https://finances.yourdomain.com.
Data Management and Backup Strategies
One of the most critical aspects when self-hosting your financial data is data security and backup. Actual Budget stores its data by default in SQLite database files, and these files are written to the ./data directory on the host server via a Docker volume. This situation presents some advantages and points to consider for data management and backup.
For data persistence, we defined a volume in the docker-compose.yml file as ./data:/data. This means that the /data directory inside the Actual Budget container is mapped to the actualbudget/data directory on your host server. Thus, all your financial data is kept in files like db.sqlite located in this host directory. This configuration ensures that your data is not lost even if containers are deleted or updated.
As a backup strategy, periodically taking a copy of this ./data directory is the simplest and most effective method. For example, you can compress this directory every night with a cron job and copy it to a secure location (another server, cloud storage, external drive):
#!/bin/bash
# Path to the backup source directory
BACKUP_SOURCE_DIR="/path/to/your/actualbudget/data"
# Directory where backup files will be saved
BACKUP_DEST_DIR="/path/to/your/backups"
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
BACKUP_FILE="$BACKUP_DEST_DIR/actualbudget_backup_$TIMESTAMP.tar.gz"
# Create backup directory if it doesn't exist
mkdir -p "$BACKUP_DEST_DIR"
# Stop the Actual Budget server container to ensure a consistent database backup.
# CAUTION: This operation will make the Actual Budget application unavailable during the backup process.
# This is the safest approach for data consistency.
echo "Stopping Actual Budget server container..."
cd /path/to/your/actualbudget # Navigate to the directory containing your docker-compose.yml file
docker compose stop actual-server
# Backup the data directory
echo "Backing up data directory: $BACKUP_FILE"
tar -czf "$BACKUP_FILE" -C "$BACKUP_SOURCE_DIR" .
# Restart the container
echo "Starting Actual Budget server container..."
docker compose start actual-server
echo "Actual Budget data backed up: $BACKUP_FILE"
# Clean up old backups (e.g., keep the last 7 days)
echo "Cleaning up old backups (older than 7 days)..."
find "$BACKUP_DEST_DIR"/actualbudget_backup_*.tar.gz -mtime +7 -delete
# IMPORTANT: Regularly test your backup files to ensure they can be restored.
# The risk of data loss without backups is very high.
This script stops the container at the time of backup, compresses the data directory, takes a backup, and then restarts the container. This is the safest approach for database consistency. You might also consider encrypting your backup files to add an extra layer of security. For example, you can use the gpg command to encrypt the backup file and then move it to a secure location.
Update and Maintenance Processes
Regular maintenance and updating of self-hosted applications are critical for both security and benefiting from new features. Actual Budget, like other software, releases new versions from time to time. Managing these updates is quite easy thanks to Docker Compose.
To update Actual Budget, all you need to do is pull the new Docker images and recreate the containers. During this process, your data is preserved thanks to the volume configuration. You can perform the update using the following commands:
cd /path/to/your/actualbudget # Navigate to the directory containing your docker-compose.yml file
# Pull the latest images from Docker Hub
docker compose pull
# Stop and remove old containers, then recreate them with new images
docker compose up -d --remove-orphans
The docker compose pull command fetches the latest images with the latest tag specified in your docker-compose.yml file. The docker compose up -d --remove-orphans command stops and removes old containers, then starts new containers with the new images. The --remove-orphans parameter also cleans up services that have been removed from the docker-compose.yml file but still exist.
Maintenance processes are not limited to updates. Regularly receiving operating system updates for your server, monitoring disk space, and checking Docker logs are also important. You can collect Docker logs centrally with journald and limit container memory or CPU consumption using cgroup limits. For example, setting soft limits like cgroup memory.high to prevent a container from consuming more memory than expected and causing an OOM (Out Of Memory) error is beneficial for system stability.
# View logs of the Actual Budget container
docker compose logs -f
# Check Docker system disk usage
docker system df
These simple commands will help you monitor the health of your system. Additionally, you can use tools like fail2ban to monitor Nginx access logs and take precautions against potential brute-force attacks.
Conclusion
Self-hosting Actual Budget on your own server provides full control and high-level privacy over your financial data. Thanks to the easy setup with Docker Compose, secure access with Nginx and SSL configuration, data backup strategies, and regular maintenance processes covered in this guide, you can manage your personal finances entirely on your own infrastructure. This way, you can be sure that your sensitive financial information is stored in a secure environment managed by you, not on third-party servers.
While self-hosting brings responsibility, the peace of mind and control it provides are invaluable. Especially in a critical area like finance, such an approach increases your digital independence. In the future, we may also cover topics such as integrating Actual Budget with a more robust database backend like PostgreSQL or developing secure middleware for automatic bank integration. I will continue to prepare comprehensive guides for those who want to delve deeper into these topics.
Top comments (2)
Awesome write-up! I've been considering migrating to Actual Budget for a while. How has your experience been with third-party bank syncing like SimpleFIN or GoCardless in this self-hosted environment? Any caveats or sync delay issues to watch out for?
Thanks! 😊
I’ve self-hosted several finance-related applications over the years, and my overall experience with self-hosting in this space has been excellent. Having full control over the infrastructure, backups, updates, and data is the biggest advantage.
That said, I haven’t used SimpleFIN or GoCardless extensively enough in production to give a fair long-term assessment of their reliability. From what I’ve seen, they work well as optional integrations, but I’d still treat them as a convenience layer rather than something I’d depend on exclusively.
For anything finance-related, I always recommend keeping manual import or CSV import available as a fallback. It gives you resilience if a bank API changes or a third-party integration has temporary issues.
For me, the real value of Actual Budget is that your financial data remains under your control while you decide how much external connectivity you actually want.