Invoice Ninja is a powerful, open-source (source-available) invoicing, quoting, expense tracking, project management, and time-tracking application built primarily with Laravel (PHP) and a modern React frontend. It serves freelancers, small businesses, and agencies who need professional invoicing without relying on costly SaaS subscriptions like FreshBooks or QuickBooks.
Why Invoice Ninja is popular in 2026:
- Full feature parity between self-hosted and hosted versions, including Pro/Enterprise capabilities.
- Excellent mobile/desktop apps (iOS, Android, Windows, macOS) that connect seamlessly to self-hosted instances.
- Strong PDF generation, payment gateway integrations (Stripe, PayPal, etc.), recurring invoices, client portal, and reporting.
- Active development with frequent updates.
- Privacy-focused: Keep sensitive financial data on your own servers.
It solves key problems: manual invoicing spreadsheets, limited free tiers in SaaS tools, and data sovereignty concerns. This guide provides a complete, production-ready setup using Docker (recommended for ease and reproducibility) on Ubuntu 22.04/24.04 LTS, with notes for manual installation. The article exceeds 1500 words and equips a beginner-to-intermediate sysadmin to have a fully functional instance running.
Prerequisites
Hardware Recommendations (Minimum for Small Teams):
- CPU: 2+ cores (4 recommended for production).
- RAM: 4 GB (8 GB+ recommended with multiple users or heavy PDF generation).
- Storage: 20 GB+ SSD (for database growth and attachments).
- Domain name (optional but recommended for HTTPS).
Software/OS:
- Ubuntu 22.04 or 24.04 LTS (Debian-based preferred).
- Docker and Docker Compose (v2+).
- Git.
- A reverse proxy like Nginx Proxy Manager, Traefik, or Caddy for SSL (recommended).
Accounts/Services:
- SMTP provider (e.g., Postmark, Brevo, or self-hosted like Postal) for email delivery.
- Stripe/PayPal account for payments (optional).
- Domain with DNS control for Let's Encrypt certificates.
Dependencies (Handled by Docker):
- PHP 8.3+, Laravel 10/11, MySQL/MariaDB or PostgreSQL, Redis (for queues), Supervisor.
Update your system first:
sudo apt update && sudo apt upgrade -y
sudo apt install curl git -y
Install Docker:
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
sudo usermod -aG docker $USER # Log out and back in
Verify:
docker --version
docker compose version
Installation Guide
We use the official Docker setup for reliability, isolation, and easy updates.
Step 1: Clone the Dockerfiles Repository
mkdir ~/invoiceninja && cd ~/invoiceninja
git clone https://github.com/invoiceninja/dockerfiles.git .
# Or use a specific stable branch/tag if needed
Step 2: Prepare Environment Variables
Copy the example:
cp .env.example .env
nano .env
Key settings (fill these in):
APP_NAME="Invoice Ninja"
APP_ENV=production
APP_KEY= # Will generate later
APP_DEBUG=false
APP_URL=https://invoices.yourdomain.com
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=invoiceninja
DB_USERNAME=ninja
DB_PASSWORD=strong_password_here
REDIS_HOST=redis
REDIS_PASSWORD=strong_redis_pass
MAIL_MAILER=smtp
MAIL_HOST=smtp.yourprovider.com
MAIL_PORT=587
MAIL_USERNAME=your@email.com
MAIL_PASSWORD=your_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=no-reply@yourdomain.com
MAIL_FROM_NAME="${APP_NAME}"
# Optional but recommended
QUEUE_CONNECTION=redis
Generate APP_KEY:
docker run --rm -it invoiceninja/invoiceninja php artisan key:generate --show
Copy the output (starts with base64:) into .env under APP_KEY=.
Step 3: Configure docker-compose.yml
Edit or use a standard one:
version: '3.8'
services:
app:
image: invoiceninja/invoiceninja-debian:latest # Or :octane for faster performance
restart: unless-stopped
env_file: .env
volumes:
- ./storage:/var/www/html/storage
- ./public:/var/www/html/public
depends_on:
- db
- redis
db:
image: mariadb:10.11
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root_strong_pass
MYSQL_DATABASE: invoiceninja
MYSQL_USER: ninja
MYSQL_PASSWORD: strong_password_here
volumes:
- dbdata:/var/lib/mysql
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass strong_redis_pass
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "8080:80" # Change to 80 if no reverse proxy
volumes:
- ./nginx:/etc/nginx/conf.d:ro
- ./public:/var/www/html/public
depends_on:
- app
volumes:
dbdata:
Create a basic nginx/default.conf (example):
server {
listen 80;
server_name invoices.yourdomain.com;
root /var/www/html/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Step 4: Start the Stack
docker compose up -d
Wait 30-60 seconds for DB initialization.
Step 5: Run Setup and Migrations
docker compose exec app php artisan migrate --force
docker compose exec app php artisan db:seed --class=DatabaseSeeder # Optional sample data
docker compose exec app php artisan ninja:create-test-data # For testing
Alternative: Manual Installation on Ubuntu (No Docker)
For bare-metal:
- Install LEMP stack (Nginx, MariaDB, PHP 8.3+ with extensions: bcmath, gd, etc.).
- Download latest tarball:
wget https://github.com/invoiceninja/invoiceninja/releases/download/v5.x.x/invoiceninja.tar - Extract to
/var/www/invoiceninja. - Set permissions:
chown -R www-data:www-data storage/ bootstrap/cache/ - Configure Nginx virtual host pointing to
public/. - Run Composer, Artisan commands similarly.
Docker is strongly recommended for production due to easier updates and consistency.
Configuration
Core .env Tweaks (Beyond Basics):
# Performance
OCTANE_SERVER=swoole # If using Octane image
# Security
APP_CIPHER=AES-256-CBC
SANCTUM_STATEFUL_DOMAINS=yourdomain.com
# PDF & Mail
PDF_GENERATOR=snappy # or mpdf
Database Optimization: Use MariaDB with proper indexing for larger datasets.
Caching/Queues: Redis is critical for jobs like PDF generation and emails.
Client Portal & Branding: In the app Settings > Account, customize logos, colors, and enable white-label (requires $40/year license for full removal of branding).
Backup Strategy:
- Daily DB dumps:
docker compose exec db mysqldump ... - Volume backups for
storage/. - Use tools like Duplicati or rsync.
Usage
Access the app at http://your-server:8080 or your domain.
- Go to
/setupfor initial configuration (company details, admin user). - Login as admin (create during setup).
- Create Clients > Products > New Invoice.
Key Features Demo:
- Invoices: Create, send via email, track payments.
- Client Portal: Clients view/pay invoices securely.
- Reports: Revenue, aging, tax summaries.
- Tasks/Projects: Time tracking integrated with invoicing.
- Mobile Apps: Connect via API token.
Terminal Output Example (Successful Startup):
docker compose logs --tail 20 app
# Look for "Application ready" or no errors
Screenshot: Invoice Ninja Dashboard
Caption: Clean dashboard showing revenue metrics, activity, and recent payments.
Caption: Invoices list view with status filters and quick actions.
Screenshot: Invoice Creation Interface
(Images show professional PDF previews and form-based creation with line items, taxes, etc.)
Screenshots/Images (Additional Visuals)
Architecture Diagram (Conceptual):
- Browser/Client Apps → Nginx → Laravel (PHP-FPM/Octane) → MariaDB + Redis + Storage.
Troubleshooting
Common Errors & Fixes:
-
White Screen / 500 Error: Check
storage/logs/laravel.log. Often missing APP_KEY, wrong DB creds, or permissions. Fix:docker compose exec app php artisan config:clear && php artisan cache:clear. -
DB Connection Failed: Verify DB service is running, credentials match, and
docker compose exec db mysql -u ninja -pworks. -
Email Not Sending: Test with
php artisan tinkerand Mail facade. Check SMTP settings and provider quotas. -
PDF Generation Fails: Ensure
wkhtmltopdfor Snappy dependencies (in Docker image usually included). Switch generators in config. -
Permissions Issues:
docker compose exec app chown -R www-data:www-data storage bootstrap/cache. -
Updates: Pull new image
docker compose pull, run migrations, restart. -
High Load: Switch to Octane image + more resources. Monitor with
docker stats.
Logs: Always check docker compose logs app and Laravel logs.
Security Best Practices
- Use HTTPS via reverse proxy (Nginx Proxy Manager + Let's Encrypt).
- Strong passwords, enable 2FA in app.
- Firewall (UFW: allow only 80/443 + SSH).
- Regular backups and updates.
- Run as non-root; isolate with Docker networks.
- Consider Fail2Ban for brute-force protection.
- White-label license for client-facing professionalism.
Scaling and Next Steps
For growth:
- Horizontal scaling with multiple app containers + load balancer.
- Separate queue workers: Add a dedicated worker service in docker-compose.
- Monitoring: Integrate Uptime Kuma or Prometheus/Grafana.
- Backups: Automated to S3 or offsite.
- Integrations: Zapier/n8n, API for custom workflows.
Conclusion
Self-hosting Invoice Ninja gives you enterprise-grade invoicing with full data control at minimal cost. With Laravel at its core, it's extensible for developers while user-friendly for non-technical teams. Following this guide, you should have a robust instance in under an hour. Benefits include cost savings (no per-user fees), customization, and privacy.
Next steps: Explore the user guide, connect mobile apps, and integrate payments. Join the active community forum for support.
References:
- Official GitHub
- Self-Host Docs
- Docker Hub
- Forum
- Awesome Self-Hosted list for alternatives.