Business Management

How to Install Invoice Ninja Self-Hosted: Docker & Manual

J
James Eriksson
··12 min read
Install Invoice Ninja on your own server in 15-20 min via Docker or 1-2 hours manually. Includes prerequisites, SSL setup, queue config, troubleshooting, and cost breakdown.
TL;DR
  • Invoice Ninja is free, open-source software (Elastic License v2) used by 200,000+ businesses worldwide
  • Docker Compose setup takes 15-20 minutes; manual Ubuntu install takes 1-2 hours
  • Self-hosting cost is $1.2K-2.4K annually (infrastructure + your labor); managed hosting costs $600-2.4K/year but removes ops work
  • Queue workers, SSL setup, backups, and SMTP config are required post-install; common failures are database permissions, missing PHP extensions, and email misconfiguration
  • Choose managed hosting if your invoicing revenue exceeds $100K/year or you've had outages that cost money

Invoice Ninja is used by over 200,000 businesses worldwide and runs on any Linux server for free under the Elastic License v2. A Docker Compose install takes 15 minutes; manual setup on Ubuntu takes 1-2 hours. The real cost isn't the software—it's your labor, backups, security updates, and the inevitable 2am outage when something breaks. This guide walks you through both installation paths, shows you what goes wrong, and tells you when managed hosting wins.

What You Need Before Starting

Running Invoice Ninja yourself requires a small Linux VPS ($10-20/mo), PHP 8.1+ or Docker, MySQL 8.0, and discipline around backups. Most self-hosters spend 2-3 hours per month on updates, monitoring, and ops. Your true cost over a year is $1K-2.5K when you factor in your labor. Managed hosting removes that labor cost at a fixed price but eliminates your control.

Here are the actual prerequisites:

  • RAM: 2GB minimum, 4GB recommended for 50+ invoices monthly.
  • CPU: 1 vCPU to start; 2 vCPU if you hit 100+ invoices/month.
  • Disk: 20GB for the application, database, and file attachments.
  • OS: Ubuntu 22.04 LTS or 24.04 LTS (most common), Debian 12, or CentOS 8+.
  • Software: Docker + Docker Compose (easiest), OR PHP 8.1, MySQL 8.0, Redis, and Composer (manual path).
  • Domain: A domain name you control (cost: $12/year).
  • SSL: Let's Encrypt certificates (free, auto-renewable).

Cost breakdown for a 20-person company self-hosting Invoice Ninja:

  • VPS: $10-20/month (Linode, DigitalOcean, Hetzner all work).
  • Domain: $1/month.
  • Backups (external storage): $5/month.
  • Your time: 20-40 hours/year at your hourly rate.
  • Annual hard cost: $240-360. Annual labor cost (at $50/hour): $1,000-2,000.
  • Total: $1,240-2,360/year.

If your invoicing revenue is $100K+ annually, or you've lost money to an outage, that's worth it. If you're invoicing $20K/year and don't want ops work, Opsily's managed Invoice Ninja hosting removes the labor completely.

Installation Methods: Docker vs. Manual vs. Managed

Invoice Ninja runs three ways. Docker Compose is the fastest and most popular (confirmed by SERP analysis and YouTube tutorials). Manual installation gives you more control but requires Linux skill. Managed hosting gives you zero ops.

MethodSetup TimeSkill LevelMaintenance BurdenBest For
Docker Compose15-20 minBeginnerLow (docker pull, restart)80% of self-hosters
Manual (Ubuntu)1-2 hoursIntermediateMedium (PHP updates, cron jobs, monitoring)DevOps-comfortable teams
Managed (Opsily)5 min signupNoneNone (provider handles everything)You want to focus on billing, not servers

Unless you enjoy infrastructure work, Docker is the right choice. It bundles PHP, MySQL, Redis, and Nginx into containers that work identically on any Linux box. You upgrade by pulling a new image. You back up by copying one directory. You troubleshoot by reading one log file.

Fastest Path: Docker Compose Setup (15-20 Minutes)

Docker Compose is the preferred installation method across the Invoice Ninja community. It eliminates OS-level differences (no "PHP 8.1 isn't available on your Ubuntu version" errors) and makes backups, updates, and rollbacks trivial. Here's the step-by-step path.

Step 1: Rent a Linux VPS

Use Ubuntu 22.04 LTS or 24.04 LTS. Any provider works—DigitalOcean, Linode, Hetzner, or Vultr are popular. Choose 2GB RAM, 1 vCPU, 30GB disk. Cost: $10-15/month. SSH in as root or a sudo user.

Step 2: Install Docker

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
logout && login

Verify: docker --version and docker-compose --version.

Step 3: Set up the working directory and create docker-compose.yml

mkdir -p ~/invoice-ninja
cd ~/invoice-ninja

Create a docker-compose.yml file with:

version: '3'
services:
  app:
    image: invoiceninja/invoiceninja:latest
    container_name: invoice-ninja
    ports:
      - "80:80"
      - "443:443"
    environment:
      - APP_URL=https://invoices.yourcompany.com
      - APP_KEY=base64:${APP_KEY}
      - DB_HOST=db
      - DB_DATABASE=invoice_ninja
      - DB_USERNAME=invoice_user
      - DB_PASSWORD=${DB_PASSWORD}
      - MAIL_DRIVER=smtp
      - MAIL_HOST=smtp.gmail.com
      - MAIL_PORT=587
      - MAIL_USERNAME=${MAIL_USERNAME}
      - MAIL_PASSWORD=${MAIL_PASSWORD}
      - MAIL_ENCRYPTION=tls
    depends_on:
      - db
      - redis
    volumes:
      - ./storage:/var/www/app/storage
      - ./public:/var/www/app/public
  db:
    image: mysql:8.0
    container_name: invoice-ninja-db
    environment:
      - MYSQL_DATABASE=invoice_ninja
      - MYSQL_USER=invoice_user
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
    volumes:
      - db-data:/var/lib/mysql
  redis:
    image: redis:7-alpine
    container_name: invoice-ninja-redis
    volumes:
      - redis-data:/data

volumes:
  db-data:
  redis-data:

Step 4: Configure environment variables

cat > .env << EOF
APP_KEY=base64:generate-a-random-key-here
DB_PASSWORD=your-secure-database-password
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-specific-password
EOF

For mail, use Gmail initially. Generate an "App Password" in your Google Account settings (not your regular password).

Step 5: Spin up the containers

docker-compose up -d

This pulls the Invoice Ninja app, MySQL, Redis, and Nginx images. First run takes 2-3 minutes.

Step 6: Initialize the database

Wait 30 seconds for MySQL to be ready, then:

docker-compose exec app php artisan migrate:fresh --seed

This creates the database schema and seeds sample data. Then generate your app key:

docker-compose exec app php artisan key:generate

Step 7: Create your admin user

docker-compose exec app php artisan tinker

At the prompt:

PHP shell >> $user = new App\Models\User();
PHP shell >> $user->email = 'you@yourcompany.com';
PHP shell >> $user->password = Hash::make('your-secure-password-here');
PHP shell >> $user->save();
PHP shell >> exit

Step 8: Set up the queue worker

Invoice Ninja needs a background job processor to send emails and generate PDFs. The queue worker runs continuously:

docker-compose exec app php artisan queue:work --daemon &

Or, for a more robust setup, add to your system crontab:

* * * * * cd /home/youruser/invoice-ninja && docker-compose exec -T app php artisan schedule:run >> /dev/null 2>&1

Step 9: Set up SSL and point your domain

  • Add an A record in your DNS: yourcompany.com -> your-vps-ip
  • Use a reverse proxy for SSL. If using Nginx, add this config:
server {
    listen 80;
    server_name invoices.yourcompany.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name invoices.yourcompany.com;
    ssl_certificate /etc/letsencrypt/live/invoices.yourcompany.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/invoices.yourcompany.com/privkey.pem;
    
    location / {
        proxy_pass http://localhost:80;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Then use Certbot to obtain a free Let's Encrypt certificate:

sudo apt install certbot python3-certbot-nginx
sudo certbot certonly -a standalone -d invoices.yourcompany.com

Voila. You now have a running Invoice Ninja instance at https://invoices.yourcompany.com.

Manual Installation on Ubuntu 24.04 (Without Docker)

If Docker isn't available or you prefer direct control over your environment, here's the manual path. It's more work but gives you granular control.

Step 1: Install dependencies

sudo apt update
sudo apt install -y php8.1-fpm php8.1-mysql php8.1-gd php8.1-curl php8.1-xml php8.1-json php8.1-zip php8.1-redis php8.1-mbstring nginx mysql-server git curl

If php8.1 isn't available, check Ubuntu's PPA or use Debian 12 (which ships with PHP 8.2).

Step 2: Secure MySQL

sudo mysql_secure_installation

Create the Invoice Ninja database and user:

sudo mysql -u root -p

Then:

CREATE DATABASE invoice_ninja;
CREATE USER 'invoice_user'@'localhost' IDENTIFIED BY 'your-secure-password';
GRANT ALL ON invoice_ninja.* TO 'invoice_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Step 3: Install Composer

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version

Step 4: Clone Invoice Ninja

sudo git clone https://github.com/invoiceninja/invoiceninja.git /var/www/invoiceninja
cd /var/www/invoiceninja
sudo git checkout v5.13.17

Step 5: Install PHP dependencies

cd /var/www/invoiceninja
sudo composer install --no-dev

This can take 2-3 minutes.

Step 6: Set permissions

sudo chown -R www-data:www-data /var/www/invoiceninja
sudo chmod -R 755 /var/www/invoiceninja/storage
sudo chmod -R 755 /var/www/invoiceninja/bootstrap/cache

Step 7: Configure the environment

cd /var/www/invoiceninja
sudo cp .env.example .env
sudo nano .env

Set:

APP_URL=https://invoices.yourcompany.com
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=invoice_ninja
DB_USERNAME=invoice_user
DB_PASSWORD=your-secure-password

Step 8: Generate app key and run migrations

cd /var/www/invoiceninja
sudo php artisan key:generate
sudo php artisan migrate:fresh --seed

Step 9: Configure Nginx

Create /etc/nginx/sites-available/invoiceninja:

sudo nano /etc/nginx/sites-available/invoiceninja

Paste:

server {
    listen 80;
    server_name invoices.yourcompany.com;
    root /var/www/invoiceninja/public;
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
    
    location ~ /\.ht {
        deny all;
    }
}

Enable the site:

sudo ln -s /etc/nginx/sites-available/invoiceninja /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

Step 10: Set up SSL

sudo apt install certbot python3-certbot-nginx
sudo certbot certonly -a certonly -d invoices.yourcompany.com

Update your Nginx config to use HTTPS (modify the server block to include ssl_certificate directives).

Step 11: Configure the queue worker

Add to your crontab:

crontab -e

Add:

* * * * * cd /var/www/invoiceninja && php artisan schedule:run >> /dev/null 2>&1

Manual install is complete. It gives you full control but you own all the updates and troubleshooting. If you have DevOps in-house, this path works. If you don't, the Docker path is safer.

Post-Installation Configuration

After either installation method, you need to configure your instance to be production-ready.

Domain and SSL

Point your domain DNS to your VPS IP. Update APP_URL in .env to match. For Docker, mount an Nginx reverse proxy with auto-renewing Let's Encrypt certs. For manual installs, use Certbot as shown. Test: curl https://invoices.yourcompany.com should return HTML, not a certificate error.

Email and SMTP

Invoice Ninja sends invoice reminders, payment confirmations, and password resets via email. Configure SMTP in .env or via the web interface (Settings > Email).

Test with MAIL_DRIVER=log first (emails write to storage/logs/laravel.log). Once verified, switch to real SMTP. Gmail works but requires an App Password, not your regular login. SendGrid, Mailgun, and Postmark are better for production (higher deliverability).

Background Job Processing

Invoice Ninja uses Laravel queues for email, PDF generation, and recurring invoices. Without a queue worker, these tasks pile up and your app slows. Start the worker with php artisan queue:work --daemon, or run php artisan schedule:run via cron every minute.

Check that jobs are processing: Settings > System Settings > Queue. If the queue is backed up, restart the worker or increase QUEUE_WORKER_COUNT.

Backups

Back up your database weekly:

mysqldump -u invoice_user -p invoice_ninja > backup_$(date +%F).sql

Back up your file storage (attachments, PDFs):

tar -czf storage_backup_$(date +%F).tar.gz /var/www/invoiceninja/storage

Store backups off-site: AWS S3, Backblaze B2, a second VPS, or your NAS. If your VPS fails, local backups help you nothing.

Keeping Your Instance Running

Updates

Invoice Ninja releases bug fixes and security patches monthly. For Docker, update monthly:

docker-compose pull && docker-compose up -d

For manual installs:

cd /var/www/invoiceninja
git pull origin main
composer install --no-dev
php artisan migrate

Always back up your database before updating.

Monitoring

Set up free uptime monitoring (UptimeRobot) to alert you if your instance goes down. Check logs regularly: docker-compose logs app (Docker) or tail -f /var/www/invoiceninja/storage/logs/laravel.log (manual).

Monitor disk space: df -h. If your disk fills, backups fail and PDFs stop generating. Expand your VPS disk or delete old logs.

Redis Memory

If you see "Redis connection refused," Redis is out of memory or crashed. Restart: docker-compose restart redis (Docker) or sudo systemctl restart redis-server (manual). If this happens frequently, your instance is under-resourced—upgrade your VPS.

Troubleshooting Common Installation Failures

Database Connection Error: "SQLSTATE[HY000] [1045] Access denied"

Your MySQL credentials in .env are wrong. Verify DB_USERNAME, DB_PASSWORD, and that the user exists. For Docker:

docker-compose exec mysql mysql -u root -p -e "SHOW GRANTS FOR 'invoice_user'@'localhost';"

For manual:

mysql -u invoice_user -p invoice_ninja -e "SELECT 1;"

If login fails, recreate the user per the manual install steps above.

"Call to undefined function simplexml_load_file()"

Missing php-xml. Install: sudo apt install php8.1-xml && sudo systemctl restart php8.1-fpm. For Docker, this is pre-included.

"The ZIP extension is not installed"

PDF generation requires zip. Install: sudo apt install php8.1-zip.

Emails Not Sending

Check Laravel logs: tail -f storage/logs/laravel.log. Look for SMTP errors. Common issues:

  • MAIL_DRIVER=log: Emails write to logs, they don't send. Switch to smtp.
  • Wrong SMTP password: Gmail requires an App Password, not your login password.
  • Firewall blocking SMTP: Some providers block port 587. Try port 465 or switch providers (SendGrid, Postmark).

Queue Jobs Stuck

The queue worker crashed or isn't running. Restart: docker-compose restart app (Docker) or pkill -f 'php artisan queue:work'; nohup php artisan queue:work & (manual). If it crashes repeatedly, check logs for out-of-memory errors. Upgrade your VPS.

PDF Generation Slow (>5 seconds)

Your VPS is under-resourced. You're generating PDFs with insufficient RAM. Upgrade to 4GB RAM or delegate to Opsily's managed Invoice Ninja hosting where infrastructure scales automatically.

When to Stop Self-Hosting

Self-hosting works. Invoice Ninja has 10+ years of active development, 10.3K GitHub stars, and 26,974 commits. The open-source community is strong. But your effective cost is:

  • Hard costs: $240-360/year (VPS, domain, backups).
  • Soft costs: 20-40 hours/year at your rate (updates, monitoring, backups, the 2am outage).
    • At $50/hour: $1,000-2,000/year.
    • Total: $1,240-2,360/year.

Managed hosting costs $50-200/month ($600-2,400/year) but buys you:

  • Zero ops work (no 2am pages).
  • Daily backups and 30-day retention.
  • Automatic security updates.
  • DDoS mitigation and rate limiting.
  • Support team if something breaks.

If any apply to you, managed hosting wins:

  • You invoice >$100K/year (your time is worth more than the hosted cost).
  • You've lost money to a server outage.
  • You don't enjoy infrastructure work.
  • You need guaranteed uptime (SLA).
  • Your team is small and adding "keep the Invoice Ninja server up" isn't a good use of time.

Opsily's managed Invoice Ninja hosting handles this for you. Or stay with self-hosting if you have the bandwidth and want full control.

Frequently Asked Questions

Can I self-host Invoice Ninja?

Yes. It's open-source under the Elastic License v2. You run it on any Linux server you control.

Is self-hosted Invoice Ninja free?

The software is free. Your cost is infrastructure ($240-360/year) plus your labor (20-40 hours/year). Total: $1.2K-2.4K/year if you value your time.

How much does Invoice Ninja cost?

Self-hosted is free software. The SaaS version (invoiceninja.com) costs $9-99/month. Managed hosting (Opsily) is $50-200/month depending on scale.

Can I run Invoice Ninja on shared hosting?

No. Shared hosts don't allow long-running queue workers or persistent Redis. Manual installs usually fail due to missing PHP extensions. Rent a $10/mo VPS instead (DigitalOcean, Linode, Hetzner).

Does Invoice Ninja have an app?

Yes. Mobile apps (iOS, Android) sync with your Invoice Ninja instance. Available in the App Store and Google Play.

What is the most popular invoice software?

FreshBooks, Zoho Invoice, and Wave are mainstream. Invoice Ninja ranks highly among open-source and self-hosted options. It's used by 200,000+ businesses globally.

Is Invoice Ninja good?

Yes. It's been actively developed for 10+ years, has 10.3K GitHub stars, and a strong community. Downsides: it's self-hosted only (unlike FreshBooks) and has a steeper learning curve than Zoho Invoice.

The Bottom Line

Self-hosting Invoice Ninja works and saves money if you have the time. Docker Compose gets you running in 15 minutes. The open-source project is mature (10+ years, 26,974 commits, 200K+ users) and actively maintained. Your annual cost is $1.2K-2.4K including labor, plus the occasional 2am outage.

If you don't want ops work, or if your invoicing revenue justifies the fixed cost, managed hosting is the smarter play. Check out Opsily's Invoice Ninja hosting hub for your next step.

Skip the ops work?
Opsily hosts Invoice Ninja on EU infrastructure with daily backups, automatic updates, and zero DevOps required.
Get Started Free

Ready to self-host your own apps?

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

Get started →