Business Management

How to Run Invoice Ninja in Docker: Setup Guide

J
James Eriksson
··11 min read
Deploy Invoice Ninja on Docker with Docker Compose. Configure HTTPS, reverse proxy, backups, and learn why managed hosting beats self-hosting for growing teams.
TL;DR
  • Invoice Ninja Docker deployments require Linux, Docker Compose, basic CLI knowledge, and 2 GB RAM minimum
  • Configure SSL with Let's Encrypt, set TRUSTED_PROXIES to trust your reverse proxy headers, and automate database backups daily
  • Self-hosting costs $155-205/month when factoring in infrastructure ($5) plus your time (3-4 hours/month at $50/hour)
  • Update the Docker image regularly with docker-compose pull, monitor logs for errors, and test database restoration quarterly
  • Managed hosting is ROI-positive for teams without existing DevOps staff

Docker makes Invoice Ninja deployment portable and reproducible, but self-hosting still requires infrastructure setup, security configuration, and ongoing maintenance. This guide walks through the exact steps, common pitfalls, and cost trade-offs so you know whether Docker self-hosting makes sense for your business.

Why Run Invoice Ninja on Docker?

Docker abstracts away the complexity of installing PHP, MySQL, and Nginx on your server. Instead of wrestling with system dependencies, you pull a container image and run it. All the moving parts are encapsulated.

This matters because Invoice Ninja is a Laravel application with specific version requirements for PHP and extensions. Without Docker, you'd need to manually configure these on a Ubuntu or CentOS server, test compatibility, and handle version conflicts across your other applications. Docker eliminates this friction.

The trade-off: you inherit DevOps responsibility. You must manage Docker updates, database backups, SSL certificates, reverse proxy configuration, and log monitoring. None of this is automatic. For a 10-person company with no ops staff, this overhead can quickly outweigh the deployment convenience.

Self-hosting Invoice Ninja in Docker makes sense if you already run other containerized services and have basic Docker knowledge. If Docker is new to your infrastructure, the learning curve and maintenance burden may justify using Opsily's managed Invoice Ninja hosting instead.

System Requirements and Prerequisites

Invoice Ninja Docker requires a Linux server with Docker and Docker Compose installed. Here's the minimum specification:

  • CPU: 1 vCPU (2 recommended for peak load)
  • RAM: 2 GB (minimum 512 MB, but slow and unreliable)
  • Disk: 50 GB (20 GB for app + database, 30 GB buffer for backups)
  • OS: Ubuntu 20.04 LTS or later, Debian 10+, or any Linux with Docker support

Costs on common providers (rough estimates for 2 vCPU, 2 GB RAM, 50 GB SSD):

  • Hetzner: $4-5/month (cheapest)
  • DigitalOcean: $12/month
  • Linode: $12/month
  • AWS EC2: $20-30/month (higher overhead)

Before starting, verify Docker and Docker Compose are installed:

docker --version
docker-compose --version

If not installed, follow the official Docker documentation for your Linux distribution. You'll also need SSH access to your server and basic comfort with the command line.

Installing Invoice Ninja with Docker Compose

The official Invoice Ninja Dockerfiles repository provides a production-ready Docker Compose example. This is your starting point.

Step 1: Clone the official repository.

git clone https://github.com/invoiceninja/dockerfiles.git invoice-ninja-docker
cd invoice-ninja-docker

The repository contains a docker-compose.yml file and example environment files. The most recent update was May 3, 2026, so you're getting current guidance.

Step 2: Configure environment variables.

Copy the example environment file and edit it:

cp.env.example.env

Open.env in your editor and set these critical variables:

  • APP_KEY: A random 32-character string used for encryption. Generate one with:

    openssl rand -base64 32
    

    Paste the output into APP_KEY= in your.env file.

  • APP_URL: Your domain name. This must match your reverse proxy setup and SSL certificate.

  • DB_PASSWORD: A random, strong password for the MySQL root user. Use:

    openssl rand -base64 20
    
  • MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD: SMTP credentials for sending invoices. Use your email provider's SMTP settings (Gmail, SendGrid, Mailgun, etc.).

  • IN_DOCKER: Set to true for Docker deployments.

Other variables like IN_USER_EMAIL_PASSWORD and REQUIRE_HTTPS can stay at defaults for now; you'll tune them after deployment.

Step 3: Start the containers.

docker-compose up -d

This pulls the Invoice Ninja image, MySQL image, and Nginx image, then starts them in the background. The first run takes 2-5 minutes depending on your connection speed.

Step 4: Initialize the database.

Once containers are running, generate the database schema:

docker-compose exec invoiceninja php artisan migrate

If this fails with a database connection error, wait 30 seconds and retry. MySQL takes time to start up.

Step 5: Create your first user account.

docker-compose exec invoiceninja php artisan tinker

Inside the Tinker shell:

user = new App\Models\User();
user.email = 'you@yourcompany.com';
user.password = Hash::make('a-strong-password-here');
user.save();
exit;

Your Invoice Ninja instance is now running. Access it at your server's IP address on port 8080. Log in with the email and password you just created.

Configuring Network Security and HTTPS

Running on a raw server port is not production-ready. You need a reverse proxy, HTTPS, and proper domain configuration.

Set up a reverse proxy (Nginx example).

The Docker Compose includes an Nginx container, but you likely need an external reverse proxy on your host to handle SSL and domain routing. Create an Nginx config file on your server with your domain details. The config should listen on port 80 to redirect HTTP traffic to HTTPS, then listen on port 443 for HTTPS traffic. Configure the SSL certificate paths to point to your Let's Encrypt certificates. Set the proxy_pass to forward traffic to localhost on port 8080. Be sure to pass through headers including Host, X-Real-IP, X-Forwarded-For, and X-Forwarded-Proto so Invoice Ninja receives the original request information. Enable the config file and test your Nginx syntax before reloading.

Obtain an SSL certificate with Let's Encrypt.

Use Certbot to automate this:

sudo apt update && sudo apt install certbot python3-certbot-nginx -y
sudo certbot certonly --nginx -d yourdomain.com

Replace yourdomain.com with your actual domain. Certbot will ask for your email and request to share your IP. Accept both. Your certificate is installed at /etc/letsencrypt/live/ under your domain directory.

Configure Invoice Ninja for HTTPS.

Edit your.env file and set APP_URL to your domain using HTTPS protocol. Set REQUIRE_HTTPS to true. Set TRUSTED_PROXIES to an asterisk or to your Nginx server's IP address. This setting tells Invoice Ninja to trust the X-Forwarded-Proto header from your reverse proxy, so it knows requests are HTTPS even though the container receives them over HTTP.

Restart the container:

docker-compose restart invoiceninja

Visit your domain using HTTPS and verify the lock icon appears in your browser.

Post-Deployment Configuration

Your Invoice Ninja is online, but not yet complete. Configure these before going live.

Set up email (SMTP).

Invoice Ninja sends invoices, payment reminders, and notifications via email. Your.env file should already have MAIL_* variables set. Test the configuration:

  1. Log in to Invoice Ninja.
  2. Go to Settings > Email Settings.
  3. Send a test email.

If it fails, check your.env SMTP credentials and consult your email provider's documentation.

Enable PDF generation.

Invoice Ninja generates PDFs server-side using Chrome/Chromium. This requires additional memory and system resources.

Edit your.env and set PHANTOMJS_SKIP_DOWNLOAD to false and PDFA_BUILD_LOCALLY to false. In your docker-compose.yml services.invoiceninja.environment section, add PUPPETEER_SKIP_CHROMIUM_DOWNLOAD set to false.

Rebuild the container:

docker-compose down
docker-compose up -d

PDF generation may take 10-20 seconds per invoice. Monitor RAM usage; if you see OOM (out-of-memory) errors, upgrade your server to 4 GB RAM.

Configure cron jobs.

Invoice Ninja sends scheduled reminders, generates reports, and processes recurring invoices via a Laravel scheduler. The Docker image includes a cron container that handles this. Verify it's running:

docker-compose ps

You should see an invoiceninja-cron service with status Up. If it's not there, you can add it to your docker-compose.yml using the official Invoice Ninja Dockerfiles repository as a reference.

Ongoing Maintenance and Backups

Self-hosting means you own the backup and update process. Neglect this and you will lose data.

Automate database backups.

Your MySQL data lives inside a Docker volume. Back it up daily:

#!/bin/bash

# /home/user/backup-invoice-ninja.sh

DATABASE_NAME="invoiceninja"
BACKUP_DIR="/home/user/backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)

mkdir -p $BACKUP_DIR
docker-compose exec -T db mysqldump -u root -p$DB_PASSWORD $DATABASE_NAME | gzip > $BACKUP_DIR/invoice-ninja-$DATE.sql.gz

# Keep only the last 14 days of backups
find $BACKUP_DIR -name "invoice-ninja-*.sql.gz" -mtime +14 -delete

Make it executable and schedule it in crontab:

0 2 * * * /home/user/backup-invoice-ninja.sh

This backs up your database at 2 AM daily and deletes backups older than 14 days.

Monitor disk space.

Use df -h to check available space. Docker images and volumes consume storage. If you hit 90% capacity, expand your disk or clean up old backups immediately.

Update Invoice Ninja.

The official image receives updates for security patches and features. Update by pulling the latest image:

docker-compose pull invoiceninja
docker-compose down
docker-compose up -d

Always backup your database before updating. If an update breaks compatibility, you can roll back by reverting to the previous image tag (for example, invoiceninja:5.8.47 instead of invoiceninja:latest).

Watch for errors.

Check Docker logs regularly:

docker-compose logs -f invoiceninja

Look for "error" or "exception" messages. Common issues:

  • Database connection failed: MySQL may have crashed. Restart it with docker-compose restart db.
  • Out of memory: Your server is undersized. Upgrade to 4 GB RAM or reduce PDF generation concurrency.
  • CSRF token mismatch: Usually a TRUSTED_PROXIES configuration error. Double-check that setting.
  • Emails not sending: Verify SMTP credentials in your.env and check that your email provider allows SMTP from your server IP.

Cost and Effort Analysis: Self-Hosted vs. Managed Hosting

You can now run Invoice Ninja on Docker. But should you?

Let's calculate the true cost of self-hosting:

Infrastructure cost (monthly):

  • Hetzner VPS (2 vCPU, 2 GB RAM): $5
  • Let's Encrypt certificate (free, but renewal time): ~$0
  • Backups (assuming 14-day retention on your server): included in $5
  • Subtotal: $5/month

Your time (monthly):

  • Initial setup: 2-3 hours (one-time)
  • Monthly monitoring and backup verification: 30 minutes
  • Security updates (OS, Docker images): 1 hour per quarter
  • Troubleshooting (SSL cert renewal failures, database corruption, etc.): 1-2 hours per quarter
  • Recurring estimate: 3-4 hours/month

At a $50/hour labor rate, your time cost is $150-200/month.

Total cost of self-hosting: ~$155-205/month (including your time).

Opsily's managed Invoice Ninja hosting:

  • Fully managed infrastructure, SSL, and backups
  • Automatic updates and security patches
  • EU-hosted (GDPR compliant)
  • Email support
  • No DevOps overhead
  • Pricing: Check Opsily pricing for Invoice Ninja

If Opsily's managed option costs less than $155-205/month, you save money by not self-hosting. Even if it costs the same, you reclaim 3-4 hours/month to focus on your business instead of server maintenance.

For most 10-50 person companies, managed hosting is the rational choice. Self-hosting makes sense only if you already have a DevOps person, run multiple containerized apps, or have unique compliance requirements (such as on-premises infrastructure).

Frequently Asked Questions

How do I run Invoice Ninja with Docker Compose?

Clone the official repository, edit your.env file with database and SMTP credentials, then run docker-compose up -d. The containers start automatically. Access the web interface at your server IP on port 8080 and initialize your database with docker-compose exec invoiceninja php artisan migrate.

What are the system requirements for self-hosting Invoice Ninja in Docker?

Minimum: 1 vCPU, 512 MB RAM, 20 GB disk. Recommended: 2 vCPU, 2 GB RAM, 50 GB disk. Costs range from $5/month (Hetzner) to $30/month (AWS) depending on your provider and instance type.

How do I configure Invoice Ninja Docker with HTTPS/SSL?

Use Certbot to obtain a Let's Encrypt certificate, then configure a reverse proxy (Nginx) to terminate SSL and forward traffic to your Docker container. Set APP_URL to use HTTPS and REQUIRE_HTTPS to true in your.env, and configure TRUSTED_PROXIES to trust your proxy's headers.

How do I set up a reverse proxy (Nginx) for Invoice Ninja Docker?

Create an Nginx config block that listens on port 443 for HTTPS, specifies your SSL certificate paths, and proxies requests to the Docker container on port 8080. Pass the X-Forwarded-Proto, X-Real-IP, and X-Forwarded-For headers so Invoice Ninja knows the original request was HTTPS.

How do I backup Invoice Ninja data in Docker?

Create a bash script that runs docker-compose exec -T db mysqldump to dump your database to a gzipped file, then schedule it in crontab to run daily at off-peak hours. Keep at least 14 days of backups and test restoration monthly.

What is the TRUSTED_PROXIES setting in Invoice Ninja Docker?

This setting tells Invoice Ninja to trust the X-Forwarded-Proto and X-Forwarded-For headers sent by your reverse proxy. Set it to an asterisk in development or restrict it to your proxy's IP in production. Without this, Invoice Ninja may redirect HTTPS requests back to HTTP.

How do I generate a random APP_KEY for Invoice Ninja?

Run openssl rand -base64 32 in your terminal, then paste the output into the APP_KEY variable in your.env file. This 32-character string is used to encrypt sensitive data in your database.

How do I update Invoice Ninja running in Docker?

Back up your database first, then run docker-compose pull invoiceninja to fetch the latest image, followed by docker-compose down and docker-compose up -d to restart the container with the new image. Rolling back is possible by specifying a previous image tag.

How do I set up SMTP/email for Invoice Ninja Docker?

Set the MAIL_HOST, MAIL_PORT, MAIL_USERNAME, and MAIL_PASSWORD variables in your.env file using your email provider's SMTP credentials. Test the configuration in Invoice Ninja's Settings > Email Settings panel.

Can I run Invoice Ninja Docker on a low-resource VPS?

Yes, but responsiveness suffers. On a 512 MB server, Invoice Ninja runs but feels slow. Add at least 1 GB RAM for comfortable performance. PDF generation and cron jobs are especially resource-intensive; consider disabling them or moving them to a separate worker container if you hit memory limits.

The Bottom Line

Docker makes Invoice Ninja deployable in minutes, but the real work is security hardening, backup automation, and ongoing maintenance. Self-hosting costs $5-30/month in infrastructure but demands 3-4 hours/month of your attention. For most growing companies, that time is better spent on revenue-generating work.

Ready to skip the DevOps overhead? Check out Opsily's managed Invoice Ninja hosting at /hosting/invoice-ninja for a fully maintained alternative.

Skip the DevOps work
Opsily manages your Invoice Ninja infrastructure, backups, and updates so you don't have to.
Get Started Free

Ready to self-host your own apps?

One server. Multiple apps. No per-app fees.

Get started →