← All articles
a close up of a green motorcycle with the name ninja on it

Invoice Ninja: Self-Hosted Invoicing and Billing for Freelancers and Small Teams

Business 2026-02-28 · 7 min read invoice-ninja invoicing billing freelance self-hosted business
By Selfhosted Guides Editorial TeamSelf-hosting practitioners covering open source software, home lab infrastructure, and data sovereignty.

Most freelancers and small businesses reach for a SaaS invoicing tool and end up paying $15 to $30 a month for features they use maybe 20% of. Wave, FreshBooks, QuickBooks — they all work, but they all take a cut of your transaction fees or charge per user, and your billing data lives entirely on their platform. If they change pricing or shut down, you spend a weekend migrating.

Photo by Tim Rüßmann on Unsplash

Invoice Ninja is the open source alternative that takes invoicing seriously. It covers the full billing workflow: quotes that convert to invoices, expense tracking, time logging, recurring billing, client portals where clients can view and pay their invoices, and Stripe integration for accepting card payments. The hosted version is free for up to 10 clients. Self-host it and the client limit disappears entirely.

Invoice Ninja self-hosted invoicing logo

Invoice Ninja vs. the Field

There are a handful of serious open source invoicing platforms. Here is how they compare.

Feature Invoice Ninja Crater Akaunting Frappe/ERPNext
Self-hostable Yes Yes Yes Yes
License Elastic / v4 open source MIT GPL-3.0 GPL-3.0
Invoices & quotes Yes Yes Yes Yes
Expense tracking Yes Yes Yes Yes
Time tracking Yes No No Yes
Recurring invoices Yes Yes Limited Yes
Client portal Yes No No Yes
Payment gateways 40+ (Stripe, PayPal, etc.) Stripe, PayPal 10+ 10+
Multi-currency Yes Yes Yes Yes
Tax support Yes Yes Yes Yes
Projects / tasks Yes No No Yes
Mobile app iOS + Android No No No
Setup complexity Medium Low Low High
Target user Freelancers, small teams Solo freelancers SMBs Medium businesses

Crater is the simplest option — if you just need to send invoices and track payments, it takes 10 minutes to deploy and stays out of your way. Invoice Ninja is the right choice when you also need time tracking, client portals, and a payment gateway that clients can use to pay without emailing you a bank transfer. ERPNext/Frappe is overkill for anything short of a company with a real accounting department.

What Invoice Ninja Includes

Invoice Ninja is a complete billing platform, not just an invoice generator. The feature set breaks down into several areas:

Invoicing and quotes. Create professional invoices with your logo, custom fields, line items, discounts, and taxes. Quotes can be sent to clients, approved by clients through the portal, and converted to invoices in one click. Invoices can be emailed directly from the platform or downloaded as PDFs.

Recurring billing. Set up recurring invoice schedules (weekly, monthly, quarterly, custom) that automatically generate and send on the specified date. Essential for retainer clients or subscription services.

Expenses. Log business expenses with vendor, amount, category, and receipt attachments. Expenses can be marked billable to a client and added to an invoice with a few clicks.

Time tracking. Log time against projects and tasks, then add logged time as billable line items on an invoice. The time tracker is a stopwatch-style tool, not a full project management suite, but it covers the basic freelancer workflow of tracking hours per project.

Client portal. Each client gets a portal where they can view all their invoices, approve quotes, download PDFs, and pay outstanding invoices. This eliminates a lot of back-and-forth email — clients can self-serve without contacting you.

Payment processing. Invoice Ninja connects to over 40 payment gateways. Stripe is the most common. Clients click "Pay Now" in the portal and pay by card. You get notified, the invoice is marked paid automatically.

Installing with Docker Compose

Invoice Ninja v5 runs as a Laravel application. The Docker deployment uses an nginx container alongside the application container.

services:
  invoice-ninja:
    image: invoiceninja/invoiceninja:5
    container_name: invoice-ninja
    environment:
      APP_URL: "https://invoices.example.com"
      APP_KEY: "${IN_APP_KEY}"
      DB_HOST: invoice-ninja-db
      DB_DATABASE: ninja
      DB_USERNAME: ninja
      DB_PASSWORD: "${IN_DB_PASSWORD}"
      REQUIRE_HTTPS: "true"
      TRUSTED_PROXIES: "*"
      MAIL_HOST: "smtp.example.com"
      MAIL_PORT: "587"
      MAIL_USERNAME: "[email protected]"
      MAIL_PASSWORD: "${SMTP_PASSWORD}"
      MAIL_ENCRYPTION: "tls"
      MAIL_FROM_ADDRESS: "[email protected]"
      MAIL_FROM_NAME: "Your Business Name"
    volumes:
      - ninja_public:/var/www/app/public
      - ninja_storage:/var/www/app/storage
    depends_on:
      invoice-ninja-db:
        condition: service_healthy
    restart: unless-stopped

  invoice-ninja-nginx:
    image: nginx:alpine
    container_name: invoice-ninja-nginx
    ports:
      - "9000:80"
    volumes:
      - ninja_public:/var/www/app/public:ro
      - ./nginx/in-vhost.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - invoice-ninja
    restart: unless-stopped

  invoice-ninja-db:
    image: mariadb:10.11
    container_name: invoice-ninja-db
    environment:
      MYSQL_DATABASE: ninja
      MYSQL_USER: ninja
      MYSQL_PASSWORD: "${IN_DB_PASSWORD}"
      MYSQL_ROOT_PASSWORD: "${IN_DB_ROOT_PASSWORD}"
    volumes:
      - ninja_db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

volumes:
  ninja_public:
  ninja_storage:
  ninja_db_data:

You also need an nginx config file at ./nginx/in-vhost.conf:

server {
    listen 80;
    server_name _;
    root /var/www/app/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass invoice-ninja:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Generate the APP_KEY before first launch:

# Generate a Laravel app key
docker run --rm invoiceninja/invoiceninja:5 php artisan key:generate --show
# Copy the output into your .env as IN_APP_KEY

Then start the stack:

docker compose up -d

Navigate to https://invoices.example.com to complete the setup wizard. The first account created is the admin.

Like what you're reading? Subscribe to Self-Hosted Weekly — free weekly guides in your inbox.

Creating Your First Invoice

Once setup is complete, the workflow for sending an invoice is:

  1. Create a client. Go to Clients > New Client. Enter the company name, contact name, email, billing address. The email address is where invoices will be sent.

  2. Create a product (optional). Under Products, create line item templates for services you bill regularly. This saves you from re-typing "Consulting — hourly" on every invoice.

  3. Create an invoice. Invoices > New Invoice. Select the client, add line items (services, products, or ad-hoc descriptions with quantities and rates), apply taxes if needed, and add a due date.

  4. Send it. Click Email Invoice. Invoice Ninja sends the PDF to the client and creates a portal link they can use to view and pay.

The invoice editor is clean and functional. You can drag line items to reorder them, add custom fields, attach files, and include internal notes visible only to you. The PDF output looks professional with minimal effort.

Client Portal and Payment Processing

The client portal is one of Invoice Ninja's strongest features relative to simpler tools. Each client gets a unique URL where they can:

For payment processing, connect Stripe under Settings > Payment Gateways > Add Gateway. You will need your Stripe publishable key and secret key. Once configured, clients see a "Pay Now" button on outstanding invoices and can pay by card without any friction. Payment confirmation happens automatically — Invoice Ninja receives the webhook from Stripe and marks the invoice as paid.

Stripe is the most common choice, but Invoice Ninja also supports PayPal, Square, Authorize.Net, GoCardless for ACH/BACS, and several dozen regional gateways.

Multi-Currency and Tax Support

Invoice Ninja handles both international billing scenarios well.

Multi-currency. Set a default currency for your company and override it per client. Invoice Ninja stores exchange rates and can display amounts in both the invoice currency and your base currency on reports. Useful for freelancers billing clients in USD, EUR, and GBP simultaneously.

Taxes. Create named tax rates under Settings > Tax Rates. Tax rates can be applied at the invoice level, the line item level, or both. You can configure inclusive taxes (GST in Australia, VAT in Europe) or exclusive taxes. For US freelancers, you can create state-specific tax rates and apply them to the appropriate clients.

Invoices display the tax breakdown clearly, which matters for clients that need to account for input tax credits.

Backup and Maintenance

All state lives in the MariaDB database and the ninja_storage volume (which holds uploaded files and PDFs). Back up both:

# Database backup
docker exec invoice-ninja-db mysqldump -u ninja -p${IN_DB_PASSWORD} ninja > ninja_backup.sql

# Storage volume
docker run --rm -v ninja_storage:/source -v $(pwd):/backup alpine \
  tar czf /backup/ninja-storage-$(date +%Y%m%d).tar.gz -C /source .

Upgrading is straightforward — pull the new image and restart. Laravel handles migrations on startup:

docker compose pull invoice-ninja
docker compose up -d invoice-ninja

Check the release notes before major version upgrades. Invoice Ninja v5 is the current generation — do not mix v4 and v5 images.

Honest Trade-offs

Invoice Ninja is a good fit if:

Consider alternatives if:

Practical limitations to be aware of:

The setup is more involved than simpler invoicing tools. The nginx + application container split, the need for a working SMTP configuration before you can invite users, and the queue worker requirements for scheduled tasks mean that getting Invoice Ninja fully operational requires more than a docker compose up. Plan for an hour of initial configuration.

The UI is good but not exceptional. Some areas of the settings feel dated, and finding specific configuration options can involve clicking through several menus. Once configured, day-to-day use is smooth, but initial setup has a learning curve.

Should You Use Invoice Ninja?

For freelancers and small teams who have outgrown manually generating PDFs or simple cloud invoicing tools, Invoice Ninja is the most complete self-hosted option available. The combination of professional invoicing, client portals, time tracking, and Stripe payment processing in a single self-hosted package is genuinely hard to match at any price. You own your data, you control your branding, and you are not paying per-seat fees as your client list grows.

If your needs are simple, start with Crater. If you need everything Invoice Ninja offers, the setup investment pays for itself quickly in time saved chasing payments and managing client billing manually.

Get free weekly tips in your inbox. Subscribe to Self-Hosted Weekly