Self Host Installation
Invoice Ninja adapts to however you want to host it. You can use whatever fits your access level. Start with the option that is easiest today and switch later when your needs change.
Secure & fast maintenance
CLI
Install, configure, update, back up, monitor, and receive notifications for your self-hosted Invoice Ninja, from a single CLI. Requires SSH access.
Focus on saving time,
less stress, certainty, and convenience.
Docker or Podman
Docker images
Official containers for Octane and Debian builds. Perfect for reproducible environments and quick pilots.
Running web stack
Server manual install
Install from the tarball or git, tweak nginx/Apache yourself, and own every line. Works great on bare metal or cloud VMs. You can still adopt the CLI later to automate updates and backups.
Cloudron server
Cloudron marketplace
Deploy Invoice Ninja as an app and let Cloudron handle SSL, backups, and log rotation.
Softaculous access
Softaculous one-click
Hosting panels that include Softaculous (cPanel, DirectAdmin, etc.) can install Invoice Ninja with a few clicks.
Elestio server
Elestio managed VM
Elestio provisions a VM, installs Invoice Ninja, and keeps monitoring and backups running for you.
YunoHost server
YunoHost package
If you already run YunoHost, add Invoice Ninja as an app and inherit its user and domain management features.
Server requirements
- PHP 8.2 with: bcmath, ctype, imagick, soap, gd, mbstring, openssl, tokenizer, xml, curl, zip, gmp, iconv, mysqli, intl, FPM (for nginx), and saxon (for e-invoice validation).
- MySQL 5.7+ or MariaDB 10.3+, or a compatible managed MySQL tier.
- nginx or Apache with HTTPS enabled.
sudo apt install php8.2-bcmath php8.2-gmp php8.2-gd php8.2-mbstring \
php8.2-xml php8.2-curl php8.2-zip php8.2-mysql php8.2-fpm \
php8.2-imagick php8.2-soap php8.2-common php8.2-intl
Invoice Ninja v5 is not an in-place upgrade from v4.x—start with a clean install before migrating data.
Install into the document root (domain or subdomain). Subdirectories such as https://example.com/ninja are not supported.
Shared hosting providers can still run Invoice Ninja, but make sure cron access is available. Softaculous or the manual tarball method is usually the quickest way to deploy on shared environments, and you can always migrate out later with the INmanage CLI once you have full server access.
Linux server configs
Prefer to see the entire build spelled out? These community guides take you from bare metal to a running Invoice Ninja instance. Every path below can later be handed over to the INmanage CLI card for automated updates and backups once the web server and database are running.
Ubuntu 22.04
TechnicallyComputers’ step-by-step guide for Invoice Ninja v5.5 on the latest LTS release.
Debian 12 (Bookworm)
Dros’ tutorial plus a management script for updates, backups, and general deployments.
Debian 12 via WSL
Install Invoice Ninja on Windows using WSL with the same automation scripts.
Enterprise Linux 8
Companion guide for Alma, Rocky, and other Enterprise Linux distributions.
Arch Linux
Community-maintained walkthrough covering pacman packages and Arch-specific tweaks.
Manual install checklist
This path gives you full control over every package. Once the base install is up, you can still point the INmanage CLI at the same server—it will adopt the instance and handle future updates and backups for you.
-
Download the latest
invoiceninja.tarfrom the GitHub releases. -
Unpack it into your vhost root (for example
/var/www/invoiceninja). -
Set permissions so the web user owns the files:
sudo chown -R www-data:www-data /var/www/invoiceninjasudo find /var/www/invoiceninja -type d -exec chmod 755 {} \; -
Configure nginx (sample below) or Apache. Enable gzip for quicker page loads.
server {listen 80;server_name ninja.example.com;root /var/www/invoiceninja/public;index index.php index.html;client_max_body_size 20M;location = /index.php {include snippets/fastcgi-php.conf;fastcgi_pass unix:/run/php/php8.2-fpm.sock;}location ~ \.php$ { return 403; }location / {try_files $uri $uri/ /index.php?$query_string;}location ~ /\.ht { deny all; }} -
Create the database and grant a user full access (MySQL’s official guide can help).
-
Configure cron so the Laravel scheduler fires every minute:
* * * * * cd /var/www/invoiceninja && php artisan schedule:run >> /dev/null 2>&1Shared hosting often requires:
* * * * * cd /path/to/root && /usr/bin/php -d register_argc_argv=On artisan schedule:run >> /dev/null 2>&1 -
Run the web installer at
https://ninja.example.com/setup, enter your database credentials, and you’re done.
After installation
- Git installs:
git clone --depth 1 https://github.com/invoiceninja/invoiceninja.gitthen follow the manual checklist before pointing the browser to/setup. Note: The React UI is not included and needs to be wired manually. So, really not the way to go for production. For production and full CLI control consider the INmanage CLI card. - Docker tips: restart containers after editing
.envand keep your volumes mapped so invoices survive rebuilds. - Queues: enable the Laravel queue worker (Supervisor) once you have root access. Laravel’s guide shows the unit file.
Whatever route you picked, the INmanage CLI and Docker stacks make it easy to move between servers later, so start simple and iterate.
$ sudo supervisorctl start invoiceninja-worker:*
Running the following will show worker processes as RUNNING (on my installation, I see 8 worker processes, numbered 00 through 07)
$ sudo supervisorctl status
Now that the Supervisor is configured, we need to tell Invoice Ninja to actually use it.
Edit the .env file for Invoice Ninja
$ sudo vi /path/to/invoiceninja/.env
Edit the following line to change it from sync to database, and save the file
QUEUE_CONNECTION=database
Finally, now that everything is set up, reload the config for Invoice Ninja and restart the queue. I’m using www-data for this example as the web server user.
$ cd /path/to/invoiceninja/
$ sudo -u www-data php artisan optimize
$ sudo -u www-data php artisan queue:restart
That’s it! You should now have a functioning Supervisor setup for Invoice Ninja.
Alternative for queues on shared hosting
If you are on shared hosting, it is possible to get the queues working by defining a new cron with the following configuration:
*/5 * * * * cd /path/to/root/folder && /usr/bin/php -d register_argc_argv=On artisan queue:work --stop-when-empty
Some people have different web hosting setups, so this might also work:
*/5 * * * * php /home/admin/domains/site.com/private_html/invoices_site/artisan queue:work --stop-when-empty
This cron will start a queue worker every 5 minutes and run any jobs that are in the queue and then gracefully terminate itself. This means any emails / notification may be queued for a small period of time prior to executing. If this amount of delay is acceptable, it is a great way to get queue's working on shared hosting.
If you prefer to manage the queues with Supervisor, then you will want to disable the internal Invoice Ninja commands which start the queue, to do this simly set the following .env var
INTERNAL_QUEUE_ENABLED=false
You will then have full control over the queue.
Shared Hosting
Keep this section short and pragmatic: many tasks are easier with the CLI card above, but if your provider only offers shared hosting, follow the list below.
Server requirements
Invoice Ninja needs the following PHP functions on shared hosting. If any of them are disabled, open a ticket with your provider or consider switching to a Softaculous-capable host (see the Softaculous card above).
- proc_open
- exec
- open_basedir
- fpassthru
Without these modules, the installer will fail. The setup wizard performs checks, but it is faster to confirm with your host before you start.
Quick path (Softaculous)
If your control panel includes Softaculous (cPanel, DirectAdmin, Plesk, etc.):
- Open the Softaculous marketplace and search for “Invoice Ninja”.
- Follow the one-click installer (same metadata as the Softaculous card).
- After the app is live, add the cron entry Softaculous proposes or use the snippet below.
Manual path (tarball)
- Create a MySQL-compatible database + user with full privileges.
- Download the latest
invoiceninja.tarfrom GitHub releases and upload it topublic_html(or the document root your panel exposes). - Extract the archive and rename
.env.exampleto.env. - Point your subdomain to the
/publicdirectory. Example:/domains/domain.com/public_html/invoices/public/. - Visit
https://yourdomain.com/setup, fill in the wizard, review any errors instorage/logs/laravel.logif needed.
Cron on shared hosting
Add the scheduler cron job in your panel (adjust paths as needed):
* * * * * cd /path/to/root/folder && /usr/bin/php -d register_argc_argv=On artisan schedule:run >> /dev/null 2>&1
Queues can be run with a 5‑minute worker if Supervisor isn’t available:
*/5 * * * * cd /path/to/root && /usr/bin/php -d register_argc_argv=On artisan queue:work --stop-when-empty
When you outgrow shared hosting, clone the site to a VPS and hand it over to the INmanage CLI installer for automated updates and backups.
Mail Configuration
Mail is now configured inside the application under Settings / Email Settings, not exclusively in your .env file. Each company selects its own Email Provider, so two companies on the same install can send through completely different services. Changes take effect immediately — no server restart or deployment is required.
Configure in the application
Navigate to Settings / Email Settings and choose an Email Provider. The provider you pick determines which credential fields appear:
| Provider | What you enter in-app |
|---|---|
| Default | Nothing — falls back to the server .env MAIL_* settings (see Default mailer below). |
| SMTP | Host, Port, Encryption (STARTTLS / SSL), Username, Password, Local Domain, Verify Peer. |
| Postmark | Your Postmark server API token (the Secret field). |
| Mailgun | Secret, Domain, and Endpoint (api.mailgun.net for US, api.eu.mailgun.net for EU). |
| Brevo | Your Brevo API key (the Secret field). |
| Amazon SES | Access Key, Secret Key, Region, From Address, and Topic ARN. |
You also set the From Name, From Email, Reply-To, and BCC on the same screen.
When using the SMTP provider, use the Send Test Email button to validate the configuration before you rely on it. In particular ensure a valid From Email / From Name are set to avoid errors such as Address in mailbox given [ ] does not comply with RFC 2822, 3.6.2.
Default mailer (.env)
When the Email Provider is set to Default, Invoice Ninja uses the global mailer defined in your server .env. This is the right place for a single SMTP relay shared by every company on the install. Here is a full example using Gmail:
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME="your_email_address@gmail.com"
MAIL_PASSWORD="your_password_dont_forget_the_quotes!"
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="your_email_address@gmail.com"
MAIL_FROM_NAME="Full Name With Double Quotes"
You must include MAIL_FROM_ADDRESS and MAIL_FROM_NAME to prevent the RFC 2822 error noted above.
If you are using SSL encryption the MAIL_PORT is 465. TLS encryption is on port 587.
Individual mail configurations per company (.env)
In addition to the in-app per-company providers above, the older .env override (from v5.5.38) is still supported. Prefix the mail variables with the company's primary key — open the companies table in your database, and if the primary id column is 1 for Acme co, the configuration is:
1_MAIL_HOST=
1_MAIL_PORT=
1_MAIL_USERNAME=null
1_MAIL_PASSWORD=null
1_MAIL_ENCRYPTION=null
1_MAIL_FROM_ADDRESS=
1_MAIL_FROM_NAME=
If Ninja Co is company id 5:
5_MAIL_HOST=
5_MAIL_PORT=
5_MAIL_USERNAME=null
5_MAIL_PASSWORD=null
5_MAIL_ENCRYPTION=null
This .env override only applies when that company's Email Provider is left as Default. Configuring a provider in Settings / Email Settings is the recommended approach.
Mail Webhooks (delivery, bounce & complaint tracking)
When you send through Postmark, Mailgun or Amazon SES, those services can call back to your install to report delivery status, bounces and spam complaints. Invoice Ninja uses these to update the email status of each invitation and to flag problem recipients (a bounce or complaint marks the client contact so you stop emailing a dead or hostile address).
Configuration is optional — outbound mail works without it — but recommended so the email activity in your dashboard stays accurate.
Invoice Ninja tags every outbound message with the company key, so incoming webhook events are routed to the correct company automatically. You only need to point the provider at the endpoint and enable the events below.
Postmark
-
Add
POSTMARK_SECRET=your_postmark_server_tokento your.env. This is the value Invoice Ninja checks against theX-API-SECURITYheader on incoming webhooks. -
In the Postmark server, add a webhook pointing at:
https://your-domain.com/api/v1/postmark_webhook -
Add a custom HTTP header to the webhook so requests authenticate:
X-API-SECURITY: your_postmark_server_token -
Enable the Delivery, Bounce, Spam Complaint and (optionally) Open events.
Mailgun
-
In the Mailgun dashboard, copy your HTTP webhook signing key and add it to your
.env:MAILGUN_WEBHOOK_SIGNING_KEY=your_mailgun_signing_keyInvoice Ninja verifies the HMAC-SHA256 signature on every request against this key, so no custom header is required.
-
Add webhooks pointing at:
https://your-domain.com/api/v1/mailgun_webhook -
Enable the Delivered Messages, Permanent Failure, Spam Complaints and (optionally) Opened events.
Amazon SES
SES reports events through Amazon SNS.
-
Set the SNS topic ARN in your
.env(it must match the Topic ARN entered inSettings / Email Settings):SES_TOPIC_ARN=arn:aws:sns:us-east-1:123456789012:your-topic -
In SES, create a configuration set with an event destination publishing Bounce, Complaint and Delivery events to that SNS topic.
-
Subscribe the SNS topic to an HTTPS endpoint:
https://your-domain.com/api/v1/sns_webhookSNS will send a subscription-confirmation request; Invoice Ninja confirms it automatically for the matching topic ARN.
Currency Conversion
Invoice Ninja supports Open Exchange for currency conversion. Open Exchange currently provides a free tier which is suitable for daily updates of the exchange rates. Simply insert a Open Exchange API key into your .env file to enable exchange rate updates:
OPENEXCHANGE_APP_ID=your_open_exchange_api_key_here
Currencies are updated automatically by using the scheduler. In case the currencies are not available within the UI please double check the database table currencies and ensure that exchange_rate fields contains realistic values.
Lib Saxon
If using e invoicing, you may want to install the saxon extension. The saxon extension provides XSLT2 validation of e invoice schema's and provides additional confidence that your einvoice will be accepted by third party systems.
- On shared hosting, enable the Saxon extension in cPanel if available.
- On the official Debian Docker image, Saxon is installed via
mlocati/php-extension-installer(saxonin the install list). - On bare‑metal Linux or VM's, you typically install the shared library first, then compile/enable the PHP extension.
- For SaxonC, download the HE build from https://www.saxonica.com/download/c.xml.
We have a short video showing the installation steps here: