Running a business means tracking money, and tracking money usually means handing your books over to a subscription service that charges per user, per month, forever. Akaunting offers a different deal. It’s free, open-source accounting software that handles invoicing, expenses, bills, and reporting, and you can run the whole thing on your own server. No seat limits. No locked features behind a premium tier you didn’t ask for.
This guide takes you from a fresh Ubuntu VPS to a working Akaunting install using Docker Compose. You’ll get a clean container setup, a reverse proxy with HTTPS, and a backup routine that keeps your financial data safe. Let’s dig in.
What Is Akaunting?
Akaunting is a full-featured accounting application built on the Laravel PHP framework. Small businesses, freelancers, and accountants use it to send invoices, record expenses, manage customers and vendors, and pull financial reports. It supports multiple companies, multiple currencies, and multiple users, all from a clean web dashboard.
The hosted version exists, but self-hosting is where it gets interesting. Your client data, your invoices, and your transaction history all stay on hardware you control. There’s an app store for extra modules too, though the core covers what most businesses need on day one.
Why Docker? Akaunting needs PHP, a stack of extensions, Composer, and a database wired together just so. Docker bundles all of that into containers, which means you skip the dependency juggling and get a setup that behaves the same way every time. Updates get easier too.
Prerequisites
Before touching the terminal, make sure you’ve got the following ready:
| Requirement | Minimum | Recommended |
|---|---|---|
| OS | Ubuntu 20.04 | Ubuntu 22.04 LTS |
| RAM | 1 GB | 2 GB or more |
| CPU | 1 vCPU | 2 vCPUs |
| Storage | 10 GB | 20 GB SSD |
| Software | Docker + Compose | Latest stable Docker |
| Access | Root or sudo user | |
| Domain | Optional | Strongly recommended for HTTPS |
A domain name pointed at your server makes the HTTPS step much smoother. If you don’t have one yet, you can still reach Akaunting by IP address, but you’ll want a domain before going live with real data.
Step 1: Connect to Your VPS
Open your terminal and SSH into the server. Swap in your real username and IP address:
ssh your_user@your_server_ip
Run a full system update first. It’s a thirty-second habit that heads off a surprising number of installation headaches.
sudo apt update && sudo apt upgrade -y
Step 2: Install Docker and Docker Compose
Akaunting runs inside Docker containers, so Docker comes first. Grab the official convenience script, which installs the latest stable Docker Engine along with the Compose plugin:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
Add your user to the docker group so you can run commands without typing sudo every time:
sudo usermod -aG docker $USER
Log out and back in for that group change to take effect. Then confirm both Docker and Compose are working:
docker --version
docker compose version
Two version numbers means you’re good to keep moving.
Step 3: Set Up the Project Directory
Keeping everything in one folder makes the install tidy and the backups simple later. Create a directory and move into it:
mkdir -p /opt/akaunting
cd /opt/akaunting
Now create an environment file to hold your passwords and settings. Storing secrets here keeps them out of the main Compose file, which is good hygiene:
nano .env
Paste in the following, then change every password and the domain to match your own setup:
# Database settings
DB_ROOT_PASSWORD=change_this_root_password
DB_NAME=akaunting
DB_USER=akaunting
DB_PASSWORD=change_this_db_password
# Akaunting admin account
[email protected]
ADMIN_PASSWORD=change_this_admin_password
# Company and app
COMPANY_NAME=Your Company Name
APP_URL=https://accounting.yourdomain.com
LOCALE=en-GB
Save and exit with Ctrl + X, then Y, then Enter.
Important: Use long, unique passwords for all three values. This system holds your financial records and customer details, so treat these credentials with the same care you’d give a bank login.
Step 4: Create the Docker Compose File
This file defines two containers: Akaunting itself and a MariaDB database for it to talk to. Create it now:
nano docker-compose.yml
Paste in the configuration below. The ${VAR} references automatically pull values from the .env file you just created:
services:
akaunting:
image: akaunting/akaunting:latest
container_name: akaunting
restart: unless-stopped
depends_on:
- mariadb
ports:
- "8080:80"
environment:
AKAUNTING_SETUP: "true"
DB_HOST: mariadb
DB_PORT: 3306
DB_NAME: ${DB_NAME}
DB_USERNAME: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
DB_PREFIX: aka_
APP_URL: ${APP_URL}
LOCALE: ${LOCALE}
COMPANY_NAME: ${COMPANY_NAME}
COMPANY_EMAIL: ${ADMIN_EMAIL}
ADMIN_EMAIL: ${ADMIN_EMAIL}
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
volumes:
- akaunting_data:/var/www/html
mariadb:
image: mariadb:11
container_name: akaunting_db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- akaunting_db:/var/lib/mysql
volumes:
akaunting_data:
akaunting_db:
A few things worth knowing about this file. The akaunting_data and akaunting_db volumes persist your files and database outside the containers, so your data survives restarts and updates. The 8080:80 mapping exposes the app on port 8080 of your server, which the reverse proxy will sit in front of shortly. The AKAUNTING_SETUP: "true" line tells the container to run its first-time installer automatically.
Heads up: Akaunting’s Docker image occasionally renames environment variables between major releases. If a value here doesn’t take, cross-check the current names against the official Akaunting Docker repository.
Step 5: Launch the Containers
With both files in place, bring the stack to life:
docker compose up -d
The -d flag runs everything in the background. Docker downloads the images, starts MariaDB, then starts Akaunting, which runs its installer and connects to the database. The first launch takes a couple of minutes since the installer has to build the database tables.
Watch the logs to follow along:
docker compose logs -f akaunting
Once the logs settle and the installer reports success, press Ctrl + C to stop watching. The containers keep running in the background.
Step 6: Disable the Installer
The setup flag did its job, and leaving it on could re-trigger the installer on a future restart. Open your Compose file again:
nano docker-compose.yml
Change the setup line from "true" to "false":
AKAUNTING_SETUP: "false"
Save, then apply the change by recreating the container:
docker compose up -d
Your data stays untouched because it lives in the named volumes, not the container.
Step 7: Set Up a Reverse Proxy
Right now Akaunting answers on port 8080. You want it on standard web ports with a proper domain and, soon, HTTPS. A reverse proxy handles that. Pick whichever web server you already know or prefer. Both work equally well here.
Option A: Nginx
Install Nginx:
sudo apt install -y nginx
sudo systemctl enable nginx
Create a server block. Replace accounting.yourdomain.com with your real domain throughout:
sudo nano /etc/nginx/sites-available/akaunting
server {
listen 80;
server_name accounting.yourdomain.com;
# Allow large invoice and document uploads
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
Enable the site, test the config, and reload:
sudo ln -s /etc/nginx/sites-available/akaunting /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Option B: Apache
Install Apache and enable the proxy modules it needs:
sudo apt install -y apache2
sudo a2enmod proxy proxy_http headers
sudo systemctl enable apache2
Create a virtual host file:
sudo nano /etc/apache2/sites-available/akaunting.conf
<VirtualHost *:80>
ServerName accounting.yourdomain.com
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
RequestHeader set X-Forwarded-Proto "http"
LimitRequestBody 52428800
</VirtualHost>
Enable the site and reload Apache:
sudo a2ensite akaunting.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
Run Nginx or Apache, never both at once. They’ll fight over ports 80 and 443 if you do.
Step 8: Enable HTTPS with Let’s Encrypt
An accounting app passing logins and financial data over plain HTTP is asking for trouble. Certbot issues a free, trusted certificate and wires it into your web server automatically.
Make sure your domain’s DNS A record points to your VPS IP first, since Certbot verifies ownership by reaching your server. Then install the matching Certbot plugin.
For Nginx:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d accounting.yourdomain.com
For Apache:
sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache -d accounting.yourdomain.com
Certbot asks for an email, confirms the terms, and offers to redirect all HTTP traffic to HTTPS. Accept the redirect. Within a minute your site serves over a secure connection.
Because you’re now serving over HTTPS, update the APP_URL in your .env file to use https:// if it doesn’t already, then recreate the container with docker compose up -d. This keeps Akaunting’s generated links pointing at the secure address.
Certbot renews certificates automatically. Confirm the renewal timer is active:
sudo systemctl status certbot.timer
Step 9: Configure Your Firewall
Close everything except what you actually need. This allows SSH plus web traffic and blocks the rest, including direct access to port 8080:
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
If you chose Apache instead of Nginx, swap that middle line for sudo ufw allow 'Apache Full'. Check the result:
sudo ufw status
Step 10: Log In and Verify
Open https://accounting.yourdomain.com in your browser. You’ll see the Akaunting login screen. Sign in with the admin email and password you set in your .env file.
Once you’re in, you’ll land on the dashboard. Set your company details, currency, and fiscal year, then send a test invoice to confirm everything works end to end.
To check the containers from the server side, run:
docker compose ps
Both services should show a status of running or healthy.
Backing Up Your Data
This step isn’t optional for an accounting system. A corrupted database or a fat-fingered command shouldn’t be able to erase your financial history. Two things need backing up: the database and the application files.
Dump the database to a file with this command. It runs mysqldump inside the database container and saves the output to your project folder:
docker exec akaunting_db sh -c \
'exec mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" akaunting' \
> /opt/akaunting/backup-$(date +%F).sql
Back up the uploaded files (logos, invoice attachments, and the like) by archiving the data volume:
docker run --rm \
-v akaunting_akaunting_data:/data \
-v /opt/akaunting:/backup \
alpine tar czf /backup/files-$(date +%F).tar.gz -C /data .
For real peace of mind, drop both commands into a shell script and schedule it with cron to run nightly. Then copy those backups off the server to remote storage, because a backup that lives only on the same machine isn’t really a backup.
Updating Akaunting
Docker makes updates clean. Pull the newest image and recreate the containers:
cd /opt/akaunting
docker compose pull
docker compose up -d
Your named volumes carry the data forward, so nothing gets lost. Run a database backup before any major version jump, just in case the update includes schema changes you’d want to roll back from.
Troubleshooting Common Issues
The page won’t load at all
Check that both containers are actually up:
docker compose ps
docker compose logs akaunting
502 Bad Gateway from the proxy
Your web server can’t reach the container. Confirm Akaunting is listening on port 8080 and that the proxy_pass address matches. A container that’s still starting up can also cause this, so give it a minute after launch.
Database connection errors in the logs
The database password in your .env file doesn’t match what MariaDB initialized with. If you changed it after the first launch, MariaDB kept the original. Either match the old password or wipe the database volume and start fresh with docker compose down -v, which deletes all data.
Styles and links point to the wrong address
Your APP_URL doesn’t match the address you’re actually visiting. Update it in .env to the exact domain and protocol you use, then run docker compose up -d to apply it.
Certbot can’t issue a certificate
DNS probably hasn’t propagated, or the A record points to the wrong IP. Run dig accounting.yourdomain.com to see where it resolves, wait a few minutes, then try again.
What to Do Next
Your books now live on a server you control. A few worthwhile next moves:
- Add your team: Create user accounts with role-based permissions so staff see only what they should.
- Explore the app store: Akaunting offers modules for payroll, inventory, custom reports, and payment gateways.
- Set up recurring invoices: Automate billing for retainer clients and subscriptions.
- Connect a payment gateway: Let clients pay invoices online and watch transactions reconcile themselves.
Wrapping Up
There’s the whole picture. Docker and Compose running the app and its database, a reverse proxy fronting it, Let’s Encrypt securing the connection, and a backup routine guarding your records. It’s a stable, self-contained stack that updates with two commands and survives reboots without a fuss.
The payoff goes beyond saving on subscription fees. Your financial data sits on your own server, under your own rules, with no third party deciding how long they’ll keep it or what it costs to access. For a system that holds something as sensitive as your books, that kind of control is hard to put a price on.
Now go send that first invoice.


