Self-Hosting Invoice Ninja with Docker

What Is Invoice Ninja?

Invoice Ninja is an open-source invoicing, quoting, and payment platform for freelancers and businesses. It handles invoices, quotes, expenses, time tracking, projects, recurring billing, and client payments — with a self-hosted option that gives you full control over your financial data. It replaces FreshBooks, QuickBooks Online, and Wave. Official site

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 1 GB of free RAM
  • A domain name (required for client portal and payment links)

Docker Compose Configuration

services:
  invoice-ninja-db:
    image: mariadb:11.4
    container_name: invoice-ninja-db
    environment:
      MYSQL_ROOT_PASSWORD: change-this-root-password
      MYSQL_DATABASE: invoiceninja
      MYSQL_USER: invoiceninja
      MYSQL_PASSWORD: change-this-db-password
    volumes:
      - invoice-ninja-db:/var/lib/mysql
    networks:
      - invoice-ninja
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5

  invoice-ninja:
    image: invoiceninja/invoiceninja:5.13.1
    container_name: invoice-ninja
    ports:
      - "8080:80"
    environment:
      # Application key (generate with: docker exec invoice-ninja php artisan key:generate --show)
      APP_KEY: base64:GENERATE_THIS_ON_FIRST_RUN
      APP_URL: https://invoice.example.com
      APP_ENV: production
      APP_DEBUG: "false"
      # Database
      DB_HOST: invoice-ninja-db
      DB_PORT: 3306
      DB_DATABASE: invoiceninja
      DB_USERNAME: invoiceninja
      DB_PASSWORD: change-this-db-password
      DB_TYPE: mysql
      # Mail
      MAIL_MAILER: smtp
      MAIL_HOST: smtp.example.com
      MAIL_PORT: 587
      MAIL_USERNAME: [email protected]
      MAIL_PASSWORD: change-this-mail-password
      MAIL_ENCRYPTION: tls
      MAIL_FROM_ADDRESS: [email protected]
      MAIL_FROM_NAME: "Your Business Name"
      # Queue and cache
      QUEUE_CONNECTION: database
      CACHE_DRIVER: database
      SESSION_DRIVER: database
    volumes:
      - invoice-ninja-public:/var/www/app/public
      - invoice-ninja-storage:/var/www/app/storage
    networks:
      - invoice-ninja
    depends_on:
      invoice-ninja-db:
        condition: service_healthy
    restart: unless-stopped

networks:
  invoice-ninja:

volumes:
  invoice-ninja-db:
  invoice-ninja-public:
  invoice-ninja-storage:

First-Run Setup

# Start the stack
docker compose up -d

# Generate the application key
docker exec invoice-ninja php artisan key:generate --show
# Copy the output (base64:xxxx...) and set it as APP_KEY in docker-compose.yml

# Restart with the key set
docker compose down && docker compose up -d

# Run migrations
docker exec invoice-ninja php artisan migrate --force

Access the setup wizard at http://your-server:8080 and create your admin account.

Core Features

ModuleWhat It Does
InvoicesCreate, send, and track invoices with line items, taxes, discounts
QuotesGenerate quotes that convert to invoices on acceptance
Recurring invoicesAuto-generate invoices on a schedule (weekly, monthly, yearly)
ExpensesTrack business expenses, attach receipts, link to invoices
ProjectsProject-based billing with time tracking integration
PaymentsRecord payments manually or accept online payments
Client portalClients view invoices, make payments, approve quotes
ReportsProfit & loss, invoice aging, expense reports, tax summary

Payment Gateway Integration

Invoice Ninja supports multiple payment gateways for online payments:

GatewaySetup
StripeAPI keys in Settings → Online Payments
PayPalClient ID and Secret
SquareApplication credentials
Authorize.netLogin ID and Transaction Key
BraintreeMerchant ID, public/private keys
GoCardlessFor direct debit (EU/UK)

Clients receive an invoice email → click “Pay Now” → complete payment through the gateway → invoice auto-marked as paid.

Configuration

Custom Invoice Templates

Invoice Ninja uses HTML/CSS templates for invoice PDFs. Customize them in Settings → Invoice Design. The template editor supports:

  • Custom HTML/CSS layouts
  • Company logo placement
  • Custom fields
  • Multiple templates (one per client or project type)

Multi-Currency and Tax

Configure in Settings → Tax Settings:

  • Multiple tax rates (VAT, sales tax, custom)
  • Per-line-item or per-invoice tax
  • Multi-currency support with exchange rate lookups
  • Tax report generation for filing

Email Configuration

Email is critical — clients receive invoices and payment links via email. Verify SMTP works:

docker exec invoice-ninja php artisan ninja:send-test-email [email protected]

If using Gmail SMTP, you’ll need an App Password (not your regular password).

Reverse Proxy

Behind Nginx Proxy Manager:

Proxy Host: invoice.example.com → http://invoice-ninja:80
Enable: WebSocket Support, Force SSL

Set APP_URL in your environment to match the public URL (including https://). Without this, invoice links and the client portal break.

Backup

VolumeContainsPriority
invoice-ninja-dbAll invoices, clients, payments, settingsCritical
invoice-ninja-storageUploaded files, logos, PDF cacheImportant
invoice-ninja-publicCustom assetsLow
# Database backup
docker exec invoice-ninja-db mariadb-dump -u invoiceninja -p'change-this-db-password' invoiceninja > invoiceninja-backup-$(date +%Y%m%d).sql

See Backup Strategy.

Troubleshooting

Blank page after setup

Symptom: Web UI shows a white page or 500 error. Fix: Check APP_KEY is set correctly. Run docker exec invoice-ninja php artisan config:cache and restart. Check logs: docker exec invoice-ninja cat /var/www/app/storage/logs/laravel.log.

Emails not sending

Symptom: Invoices created but clients never receive them. Fix: Verify SMTP settings. Test with php artisan ninja:send-test-email. Check that MAIL_ENCRYPTION matches your SMTP provider (tls for port 587, ssl for port 465).

PDF generation fails

Symptom: Clicking “Download PDF” shows an error or blank PDF. Fix: The container needs Chromium for PDF generation. The official Docker image includes it. If using a custom image, ensure PHANTOMJS_PDF_GENERATION or PDF_GENERATOR is configured correctly.

Recurring invoices not generating

Symptom: Recurring invoices don’t appear on schedule. Fix: The scheduler must run. Add this cron to your host or use a sidecar: docker exec invoice-ninja php artisan schedule:run. For production, set up a cron job that runs every minute.

Resource Requirements

  • RAM: ~250 MB idle (app + MariaDB), ~500 MB under load
  • CPU: Low to moderate — PDF generation is the heaviest operation
  • Disk: ~500 MB for application, database grows with invoice/client volume

Verdict

Invoice Ninja is the most complete self-hosted invoicing solution. The client portal with online payments is the killer feature — clients can view and pay invoices without you chasing them. For simpler invoicing without the overhead, Crater is a lighter Laravel-based alternative. If you need time tracking that feeds into invoicing, pair Invoice Ninja with Kimai or use its built-in time tracker.

Comments