How to Install Invoice Ninja Self-Hosted: Docker & Manual
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.
- 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.
| Method | Setup Time | Skill Level | Maintenance Burden | Best For |
|---|---|---|---|---|
| Docker Compose | 15-20 min | Beginner | Low (docker pull, restart) | 80% of self-hosters |
| Manual (Ubuntu) | 1-2 hours | Intermediate | Medium (PHP updates, cron jobs, monitoring) | DevOps-comfortable teams |
| Managed (Opsily) | 5 min signup | None | None (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.