Installing Actual Budget on Your Debian 12 Server: A Comprehensive Guide from revWhiteShadow

At revWhiteShadow, we are committed to empowering individuals and small teams with the tools for robust financial management, prioritizing privacy and control. Today, we are thrilled to present an in-depth guide on deploying Actual Budget, a powerful, open-source finance management solution, onto your Debian 12 Server. This tutorial is meticulously crafted to ensure a seamless installation process, enabling you to harness the full potential of Actual Budget’s envelope-style budgeting principles directly on your own infrastructure. We understand the importance of having your sensitive financial data securely managed and readily accessible, and a self-hosted solution like Actual Budget on Debian 12 offers unparalleled peace of mind and customization.

Understanding Actual Budget: A Privacy-Focused Approach to Envelope Budgeting

Before we dive into the technical intricacies of installation, it’s crucial to understand what makes Actual Budget such a compelling choice. At its core, Actual Budget is an open-source application dedicated to providing a privacy-first approach to personal finance management. It meticulously follows the envelope budgeting methodology, a time-tested system designed to help you allocate funds for specific purposes, ensuring you stay on track with your financial goals. Unlike many commercial alternatives that often rely on cloud synchronization and may have less transparent data handling practices, Actual Budget allows you to maintain complete control over your financial information. By installing it on your own Debian 12 server, you are essentially creating a private sanctuary for your budget, accessible only to you. This self-hosted model is particularly attractive to users who value data sovereignty and wish to avoid potential vendor lock-ins or data breaches associated with third-party cloud services. The flexibility of Actual Budget also extends to its extensibility and the ability to integrate with other open-source tools, further enhancing its appeal for technically inclined users who seek a truly personalized financial management experience.

Prerequisites for Installing Actual Budget on Debian 12

To embark on this installation journey, ensuring you have the necessary prerequisites in place will streamline the process significantly. We recommend a stable Debian 12 (Bookworm) installation, whether it’s a fresh server or an existing one.

Essential System Components

  • Root or Sudo Privileges: You will need administrative access to your Debian 12 server to install packages and configure services. This typically means logging in as the root user or using a user account with sudo privileges.
  • Internet Connectivity: A stable internet connection is vital for downloading necessary packages and dependencies from the Debian repositories.
  • Basic Terminal Proficiency: Familiarity with using the command line interface (CLI) for executing commands and navigating your server’s file system is assumed.
  • Docker and Docker Compose (Recommended): While direct installation is possible, we strongly recommend using Docker and Docker Compose for a cleaner, more isolated, and easily manageable deployment of Actual Budget. This approach significantly simplifies dependency management and future updates.

Preparing Your Debian 12 Server

Before installing Actual Budget, it’s a good practice to ensure your system is up-to-date. This helps prevent potential conflicts and ensures you are running the latest stable versions of core system packages.

  1. Update Package Lists:

    sudo apt update
    

    This command fetches the latest information about available packages from the configured repositories.

  2. Upgrade Installed Packages:

    sudo apt upgrade -y
    

    The -y flag automatically answers “yes” to any prompts during the upgrade process. This step ensures all installed packages are brought up to their latest stable versions.

  3. Install Essential Build Tools (If not using Docker): If you plan to build Actual Budget from source or install it without Docker, you’ll need some development tools.

    sudo apt install -y build-essential git curl wget
    
    • build-essential: Provides essential tools for compiling software.
    • git: Used for cloning source code repositories.
    • curl and wget: For downloading files from the internet.

Installing Docker and Docker Compose on Debian 12

For the most robust and manageable deployment of Actual Budget, we highly recommend utilizing Docker. This section will guide you through the installation of Docker and Docker Compose on your Debian 12 server.

Installing Docker Engine

  1. Remove Old Versions (if any): If you have previously installed older versions of Docker, it’s a good idea to remove them to avoid conflicts.

    sudo apt remove docker docker-engine docker.io containerd runc
    
  2. Set up the Docker Repository: We’ll add the official Docker repository to ensure you get the latest versions.

    # Add Docker's official GPG key:
    sudo apt-get update
    sudo apt-get install ca-certificates curl gnupg
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    
    # Add the repository to Apt sources:
    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
  3. Install Docker Engine: Now, install Docker Engine, Containerd, and Docker Compose.

    sudo apt-get update
    sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
    
  4. Verify Docker Installation: Check if Docker is running correctly.

    sudo systemctl status docker
    

    You should see output indicating that the service is active and running.

  5. Add User to Docker Group: To run Docker commands without sudo every time, add your user to the docker group.

    sudo usermod -aG docker $USER
    

    Important: You will need to log out and log back in for this change to take effect. Alternatively, you can use newgrp docker in your current shell session.

Installing Docker Compose (Standalone)

While the docker-compose-plugin is installed above, sometimes having the standalone Docker Compose binary can be useful for specific scenarios or older setups. If you prefer the standalone version or if the plugin doesn’t suffice, you can install it as follows:

  1. Download the Latest Docker Compose Binary:

    sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    

    (Note: Replace v2.20.2 with the latest stable version of Docker Compose if a newer one is available. You can check releases on the Docker Compose GitHub page.)

  2. Apply Executable Permissions:

    sudo chmod +x /usr/local/bin/docker-compose
    
  3. Verify Docker Compose Installation:

    docker-compose --version
    

    This should display the installed Docker Compose version.

Deploying Actual Budget with Docker Compose

This is our recommended method for deploying Actual Budget. It utilizes a docker-compose.yml file to define and manage the Actual Budget service and its dependencies, such as a database.

Creating the Docker Compose Configuration File

  1. Create a Directory for Actual Budget: It’s good practice to keep your application configurations organized.

    mkdir ~/actual-budget
    cd ~/actual-budget
    
  2. Create the docker-compose.yml File: Use your preferred text editor (e.g., nano, vim) to create the configuration file.

    nano docker-compose.yml
    
  3. Paste the Following Configuration into the File: This configuration sets up Actual Budget with a PostgreSQL database. PostgreSQL is a robust and reliable open-source relational database system, well-suited for storing your financial data.

    version: '3.8'
    
    services:
      actual-postgres:
        image: postgres:15-alpine
        container_name: actual-postgres
        restart: unless-stopped
        volumes:
          - actual_postgres_data:/var/lib/postgresql/data
        environment:
          POSTGRES_USER: actual_user
          POSTGRES_PASSWORD: your_strong_password # CHANGE THIS TO A STRONG PASSWORD
          POSTGRES_DB: actual_db
        networks:
          - actual_network
    
      actual-server:
        image: actualbudget/actual-server:latest
        container_name: actual-server
        restart: unless-stopped
        ports:
          - "5006:5006" # Host:Container port mapping
        environment:
          DB_HOST: actual-postgres
          DB_PORT: 5432
          DB_USER: actual_user
          DB_PASSWORD: your_strong_password # USE THE SAME PASSWORD AS ABOVE
          DB_NAME: actual_db
          NODE_ENV: production
          # Optional: For HTTPS if you set up a reverse proxy like Nginx or Caddy
          # SSL_KEY_PATH: /etc/ssl/private/your_domain.key
          # SSL_CERT_PATH: /etc/ssl/certs/your_domain.crt
        depends_on:
          - actual-postgres
        networks:
          - actual_network
        volumes:
          - actual_server_data:/app/actual-server/data
    
    volumes:
      actual_postgres_data:
      actual_server_data:
    
    networks:
      actual_network:
        driver: bridge
    

    Explanation of the docker-compose.yml file:

    • version: '3.8': Specifies the version of the Docker Compose file format.
    • services:: Defines the different containers (services) that make up your application.
      • actual-postgres: This service defines the PostgreSQL database container.
        • image: postgres:15-alpine: Uses the official PostgreSQL image, specifically version 15, with the lightweight Alpine Linux base.
        • container_name: actual-postgres: Assigns a specific name to this container for easier management.
        • restart: unless-stopped: Ensures the container automatically restarts if it crashes or the server reboots, unless manually stopped.
        • volumes:: Mounts a named volume (actual_postgres_data) to persist your database data. This is crucial; without it, your data would be lost when the container is removed.
        • environment:: Sets environment variables within the container, configuring the PostgreSQL user, password, and database name. Remember to replace your_strong_password with a secure, unique password.
        • networks:: Connects this service to a custom bridge network named actual_network for inter-container communication.
      • actual-server: This service defines the Actual Budget server container.
        • image: actualbudget/actual-server:latest: Uses the official Actual Budget server image. latest will pull the most recent stable version.
        • container_name: actual-server: Assigns a specific name to the Actual Budget server container.
        • restart: unless-stopped: Ensures the Actual Budget server restarts automatically.
        • ports:: Maps port 5006 on your host machine to port 5006 inside the container. This is the default port Actual Budget uses. You can change the host port if 5006 is already in use (e.g., 8080:5006).
        • environment:: Configures the Actual Budget server to connect to the PostgreSQL database. It uses the service name actual-postgres as the DB_HOST because they are on the same Docker network. Ensure DB_PASSWORD matches the one set for PostgreSQL.
        • depends_on:: Specifies that the actual-server service depends on actual-postgres and will start only after the database container is running.
        • volumes:: Mounts a named volume (actual_server_data) to persist Actual Budget’s application data.
        • networks:: Connects this service to the actual_network.
    • volumes:: Declares the named volumes used for data persistence.
    • networks:: Defines the custom bridge network.
  4. Important Security Note: CRITICAL! Change your_strong_password in both actual-postgres and actual-server services to a unique and strong password. Never use default or weak passwords for database credentials.

Starting Actual Budget

Now that you have your docker-compose.yml file ready, you can start Actual Budget.

  1. Navigate to the Directory: Ensure you are in the ~/actual-budget directory where you saved the docker-compose.yml file.

    cd ~/actual-budget
    
  2. Start the Services: Run the following command to create and start the containers defined in your docker-compose.yml file.

    docker-compose up -d
    
    • up: Creates and starts the containers.
    • -d: Runs the containers in detached mode (in the background).
  3. Verify the Services are Running: You can check the status of your containers:

    docker-compose ps
    

    You should see both actual-postgres and actual-server listed with their status as Up.

  4. Check Actual Budget Logs (Optional but Recommended): To ensure everything is functioning correctly, you can view the logs of the Actual Budget server:

    docker-compose logs actual-server
    

    Look for any error messages. If you see output indicating the server is listening on port 5006, it’s a good sign.

Accessing Actual Budget

Once the containers are running, you can access Actual Budget through your web browser.

  • Open your web browser and navigate to: http://your_server_ip:5006 Replace your_server_ip with the public IP address of your Debian 12 server. If you mapped the port differently in docker-compose.yml (e.g., 8080:5006), use that host port instead.

You should now see the Actual Budget interface, ready for you to set up your budget!

Securing Actual Budget: Essential Steps

Running Actual Budget on your server opens up the possibility of remote access, which necessitates proper security measures.

Exposing your Actual Budget application directly via its port (5006) is generally not recommended for production environments. A reverse proxy, such as Nginx or Caddy, offers several advantages:

  • SSL/TLS Encryption: Enables secure HTTPS access.
  • Load Balancing: If you ever scale to multiple Actual Budget instances.
  • Improved Security: Acts as an additional layer of defense.
  • Easier Domain Name Association: Allows access via a friendly domain name (e.g., budget.yourdomain.com).

We will outline the steps for setting up Nginx as a reverse proxy.

Installing Nginx

  1. Install Nginx:

    sudo apt install nginx -y
    
  2. Configure Nginx for Actual Budget: Create a new Nginx configuration file for Actual Budget.

    sudo nano /etc/nginx/sites-available/actual-budget
    

    Paste the following configuration, replacing budget.yourdomain.com with your actual domain name or server IP address if you’re not using a domain name for direct access. If using an IP, you might skip SSL for now unless you set up a dynamic DNS and obtained a certificate.

    server {
        listen 80;
        server_name budget.yourdomain.com; # Replace with your domain or IP
    
        location / {
            proxy_pass http://localhost:5006; # Points to the Actual Budget 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;
    
            # WebSocket support (required for Actual Budget's real-time features)
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
    
  3. Enable the Nginx Site: Create a symbolic link to enable the configuration.

    sudo ln -s /etc/nginx/sites-available/actual-budget /etc/nginx/sites-enabled/
    
  4. Test Nginx Configuration and Restart:

    sudo nginx -t
    sudo systemctl restart nginx
    
  5. Access Actual Budget: Now, you should be able to access Actual Budget via http://budget.yourdomain.com (or your server IP if you didn’t use a domain).

Implementing SSL/TLS with Certbot (Let’s Encrypt)

For secure HTTPS access, we’ll use Certbot with Let’s Encrypt.

  1. Install Certbot and the Nginx Plugin:

    sudo apt install certbot python3-certbot-nginx -y
    
  2. Obtain and Install SSL Certificate: Ensure your domain name points to your server’s IP address. Then, run Certbot.

    sudo certbot --nginx -d budget.yourdomain.com # Replace with your domain
    

    Follow the prompts. Certbot will automatically modify your Nginx configuration to use HTTPS and set up automatic certificate renewal.

  3. Verify Auto-Renewal: You can test the renewal process with:

    sudo certbot renew --dry-run
    

After these steps, you should be able to access Actual Budget securely via https://budget.yourdomain.com.

2. Regular Updates

Keeping your system and Actual Budget updated is paramount for security and stability.

  • Update Docker Images: Periodically, you’ll want to update the Actual Budget Docker image to the latest version.

    1. Navigate to your Actual Budget directory:
      cd ~/actual-budget
      
    2. Pull the latest image:
      docker-compose pull actual-server
      
    3. Recreate the container with the new image:
      docker-compose up -d --force-recreate
      
      The --force-recreate flag ensures the container is rebuilt using the new image.
  • Update Debian System: Continue to run sudo apt update && sudo apt upgrade -y regularly.

3. Firewall Configuration

Ensure your server’s firewall is configured to allow only necessary traffic. If you are using ufw (Uncomplicated Firewall), which is common on Debian:

  1. Allow SSH:

    sudo ufw allow OpenSSH
    
  2. Allow HTTP and HTTPS (if using reverse proxy):

    sudo ufw allow http
    sudo ufw allow https
    
  3. Allow Actual Budget Port (if not using reverse proxy): If you are accessing Actual Budget directly on port 5006 without Nginx, allow that port.

    sudo ufw allow 5006/tcp
    
  4. Enable the Firewall:

    sudo ufw enable
    
  5. Check Firewall Status:

    sudo ufw status
    

Advanced Configurations and Troubleshooting

While the default setup is straightforward, you might encounter specific needs or issues.

1. Backing Up Your Data

Data loss can be catastrophic, especially for financial data. Regularly backing up your Actual Budget data is essential. Since we are using Docker volumes, the data is stored in host directories managed by Docker.

  1. Locate Docker Volume Data: You can find the location of your Docker volumes using docker volume inspect <volume_name>. For example:

    docker volume inspect actual_postgres_data
    docker volume inspect actual_server_data
    

    Look for the "Mountpoint" field in the output. It will point to a directory on your host machine (e.g., /var/lib/docker/volumes/actual_postgres_data/_data).

  2. Backup Strategy:

    • Stop Actual Budget: Before backing up, it’s safest to stop the Actual Budget containers to ensure data consistency.
      cd ~/actual-budget
      docker-compose down
      
    • Copy Volume Data: Copy the contents of the identified mount points to a secure backup location.
      # Example using rsync
      rsync -avz /var/lib/docker/volumes/actual_postgres_data/_data /path/to/your/backups/actual_postgres_data_backup
      rsync -avz /var/lib/docker/volumes/actual_server_data/_data /path/to/your/backups/actual_server_data_backup
      
    • Restart Actual Budget:
      cd ~/actual-budget
      docker-compose up -d
      
    • Automate Backups: Consider setting up a cron job to automate this backup process.

2. Increasing PostgreSQL Memory Limits

For very large budgets or heavy usage, you might consider tweaking PostgreSQL’s memory settings. This typically involves modifying the PostgreSQL configuration file (postgresql.conf) within the volume. However, directly editing files inside Docker volumes can be complex. A more Docker-native approach might involve building a custom PostgreSQL image with adjusted postgresql.conf settings. For most users, the default settings should suffice.

3. Troubleshooting Common Issues

  • Cannot Access Actual Budget:
    • Check Docker Status: docker-compose ps to ensure containers are running.
    • Check Server IP/Port: Verify you are using the correct IP address and port (5006 or your mapped port).
    • Check Firewall: Ensure port 5006 (or your mapped port) and ports 80/443 (if using Nginx) are open. sudo ufw status.
    • Check Nginx Logs: If using Nginx, check /var/log/nginx/error.log and /var/log/nginx/access.log.
    • Check Actual Budget Logs: docker-compose logs actual-server.
  • Database Connection Errors:
    • Check Passwords: Ensure DB_PASSWORD in docker-compose.yml exactly matches the PostgreSQL password.
    • Check DB Host/Port: Ensure DB_HOST is actual-postgres and DB_PORT is 5432.
    • Check PostgreSQL Logs: docker-compose logs actual-postgres.
  • Actual Budget Not Starting:
    • Insufficient Resources: Ensure your server has enough RAM and CPU for Docker and the applications.
    • Conflicting Ports: Ensure no other service is using port 5006 on the host if you mapped directly, or the port you chose for the reverse proxy.

Conclusion

By following this comprehensive guide, you have successfully installed and configured Actual Budget on your Debian 12 Server. You now possess a powerful, privacy-focused financial management tool that gives you complete control over your sensitive data. The adoption of Docker and Docker Compose ensures a robust, isolated, and easily manageable deployment, while the recommendations for a reverse proxy and regular updates provide essential layers of security.

At revWhiteShadow, we believe in the power of self-hosting and open-source software to provide users with greater autonomy and control. Actual Budget perfectly embodies these principles, offering a sophisticated yet accessible solution for envelope budgeting. We encourage you to explore its features, customize it to your needs, and enjoy the peace of mind that comes with managing your finances on your own secure infrastructure. Should you have any further questions or require assistance with advanced configurations, the revWhiteShadow personal blog site remains a resource for insightful technical guidance. Happy budgeting!