Install Invoice Ninja v5 on Ubuntu 20.04

I’ve tested these instructions in a VM running Ubuntu 20.04 LTS so it should work for the most part, just the same in Ubuntu 20.04 server as well, I have used Ubuntu server in the past and I can’t imagine why it would be any different unless there are some repository issues.


First steps: Install dependencies

$ sudo apt update
$ sudo apt dist-upgrade -y

$ sudo apt install gcc g++ make php php-{fpm,bcmath,ctype,fileinfo,json,mbstring,pdo,tokenizer,xml,curl,zip,gmp,gd,mysqli} mariadb-server mariadb-client curl git nginx vim -y
$ curl -sS http-s:// -o composer-setup.php
$ sudo php composer-setup.php --install-dir=/usr/bin --filename=composer

$ sudo systemctl start mariadb
$ sudo systemctl enable mariadb
$ mysql_secure_installation

Done installing things. Let’s configure them.

Debian Users

You have different paths for php-fpm’s unix socket than Ubuntu users. This guide assumes you spawn /run/php/php-fpm.sock for a socket, but you do not. Other distros based on Debian or Ubuntu should pay attention to php-fpm.sock mentions in the nginx config example below, and change them to match the php-fpm path on your distro.

Check where php-fpm runs its socket with:

 systemctl status php-fpm

Next we configure Mariadb

$ mysql -u root -p
Enter Password:  ******
MariaDB .. > create database ninjadb;
MariaDB .. > create user 'ninja'@'localhost' identified by 'ninjapass';
MariaDB .. > grant all privileges on ninjadb.* to 'ninja'@'localhost';
MariaDB .. > flush privileges;
MariaDB .. > exit

Now we generate OpenSSL certification - unless you already have letsencrypt or other cert, if so, skip this step, and configure SSL cert path manually later when we configure NGINX .conf file for invoiceninja.

$ sudo mkdir -p /etc/nginx/cert
$ sudo openssl req -new -x509 -days 365 -nodes -out /etc/nginx/cert/ninja.crt -keyout /etc/nginx/cert/ninja.key

Optional, depends on config: the default NGINX install on Ubuntu has a pesky default website located at /etc/nginx/sites-enabled/default - and for our cases, we do not want this default website hosted by nginx. This is for a VM configured just for invoiceninja webhosting, and the “default_server” value will make it the first thing we see at or other direct IP. Unless it is overridden by this pesky file :wink: let’s delete it instead.

$ sudo rm /etc/nginx/sites-enabled/default

There. Now we can configure invoiceninja and test it properly without ‘default’ getting in our way.

$ sudo vim /etc/nginx/conf.d/invoiceninja.conf

press ‘i’ to enter insert mode, and paste this server configuration. Review it line by line, and edit the server name, root path, ssl path, php-fpm socket path, etc, as necessary.

  server {
   listen       443 ssl http2 default_server;
   listen       [::]:443 ssl http2 default_server;
   # Here, enter the path to your invoiceninja directory, in the public dir.
   root         /usr/share/nginx/invoiceninja/public;
   client_max_body_size 20M;

   gzip on;
   gzip_types application/javascript application/x-javascript text/javascript text/plain application/xml application/json;
   gzip_proxied    no-cache no-store private expired auth;
   gzip_min_length 1000;

   index index.php index.html index.htm;

   # Enter the path to your existing ssl certificate file, and certificate private key file
   # If you don’t have one yet, you can configure one with openssl in the next step.
   ssl_certificate "/etc/nginx/cert/ninja.crt";
   ssl_certificate_key "/etc/nginx/cert/ninja.key";
   ssl_session_cache shared:SSL:1m;
   ssl_session_timeout  10m;
   ssl_ciphers 'AES128+EECDH:AES128+EDH:!aNULL';
   ssl_prefer_server_ciphers on;
   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

   charset utf-8;

   # Load configuration files for the default server block.
   include /etc/nginx/default.d/*.conf;

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

   if (!-e $request_filename) {
           rewrite ^(.+)$ /index.php?q= last;

   location ~ \.php$ {
           fastcgi_split_path_info ^(.+\.php)(/.+)$;
           # Here we pass to php-fpm listen socket.  For configuration see /etc/php-fpm.d/*.conf.
           fastcgi_pass unix:/run/php/php-fpm.sock;
           fastcgi_index index.php;
           include fastcgi_params;
           fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
           fastcgi_intercept_errors off;
           fastcgi_buffer_size 16k;
           fastcgi_buffers 4 16k;

   location ~ /\.ht {
       deny all;

   location = /favicon.ico { access_log off; log_not_found off; }
   location = /robots.txt { access_log off; log_not_found off; }

   access_log /var/log/nginx/ininja.access.log;
   error_log /var/log/nginx/ininja.error.log;

   sendfile off;


  server {
      listen      80;
      add_header Strict-Transport-Security max-age=2592000;
      rewrite ^ https://$server_name$request_uri? permanent;

That’s great! Hope you remembered to check root, server_name, and SSL certificate paths. Next Steps.

For Ubuntu 20.04, I had to disable apache2 in order to enable nginx to run on ports 80 and 443 without conflict. You might prefer to use apache2, but I am only supporting one web server conf file, and am already using nginx.

  $ sudo systemctl stop apache2
  $ sudo systemctl disable apache2
  $ sudo systemctl start nginx
  $ sudo systemctl enable nginx

Installing Invoice Ninja

Please visit to get the latest github release of InvoiceNinja from the team. Look closely at what you are downloading, the list also includes recent updates to v4.

  $ cd /usr/share/nginx
  $ sudo mkdir invoiceninja && cd invoiceninja
  $ sudo wget <latest zip url>
  $ sudo unzip

Installing and configuring Invoice Ninja server software and dependencies

  $ sudo php /usr/bin/composer install --no-dev

OR, if you get a memory error you can run:

  $ sudo php -d memory_limit=-1 `which composer` install --no-dev

When running for the first time only - Follow the link provided to generate github token, then pass to the prompt on the terminal.
Wait while it runs.

You have an automatically generated .env file with preset encryption key and ready to initialize the setup page.

Optionally, populate the .env file with a new genuine encryption key.

  $ sudo php artisan key:generate

Run auto configure process, something you must do again if you ever change the values of .env or other files within the invoiceninja directory.

  $ sudo php artisan optimize

Finally, set permissions for the directory.

  $ sudo chown -R www-data:www-data /usr/share/nginx/invoiceninja
  $ sudo chmod -R g+s /usr/share/nginx/invoiceninja

Now, there is need to enable cron job that will run some sort of regular maintenance, or you get a nasty red exclamation mark error in InvoiceNinja after logging in. See here for more:

  $ sudo -u www-data crontab -e

Then copy paste the following into the bottom of your cron file, which will be run for something to do with laravel which InvoiceNinja depends on.

  * * * * * php /usr/share/nginx/invoiceninja/artisan schedule:run >> /dev/null 2>&1

Some users may encounter issues generating PDF, some may not. I do not know why or so on, but you can try to fix the chromium headless dependencies by installing:

  sudo apt-get install gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

For me this was not an issue in a KVM Ubuntu managed by Virt-manager, but for others with remote VM or container it was.

I strongly suggest if you are struggling, to review both this link to original Invoice Ninja install documentation, then there is a readme document included in invoiceninja data files that is also useful.

Done. Enjoy.

If you cannot get it to login or have other errors, fastest support will come from making a NEW thread, or joining InvoiceNinja on Slack, in order to communicate quickly with devs.

This guide is written in my free time, and I do not offer real support for it, but I will try to update it if there are errors in my post that misguide you.



Great Job, thanks. In my case, the only change I did was:
$ php `which composer` install
instead of
$ php `which composer` update

1 Like

Thanks for the positive feedback.

Thanks a lot, you have a small typo error “inatll” :wink:

1 Like

I followed the steps and when submitting the setup form I get a 500 response. Do you have any idea where I should look?

1 Like

Please check the web server error logs and the app error logs in storage/logs/laravel-error.log for details about the error.

i’ve seen this howto. But i have a litte error in nginx. I gat a 403 Forbidden. The log says only
*2 directory index of "/var/www/invoiceninja/" is forbidden
Any hints for me?

@CKMartens does the webuser have read/write access to that directory?

Update as of 5.0.35:

Follow all OP’s instructions as written for setting up webserver and unziping
Then do as follows:

cd /path/to/invoiceninja
sudo php /usr/bin/composer install --no-dev
sudo npm install --no-optional
sudo chown -R www-data:www-data ../invoiceninja
sudo chmod -R g+s ../invoiceninja
sudo chmod -R 775 ../invoiceninja/storage

Do not need to optimize at this point and you do not need to create storage links.

Run crontab as www-data (I had some issues with root owning files causing errors):

sudo crontab -u www-data -e

Past this into www-data’s crontab:

* * * * * php /usr/share/nginx/invoiceninja/artisan schedule:run >> /dev/null 2>&1

Hit the web interface and run setup.

If you are getting “Validation token was expired. Please try again.” on the client interface: edit .env, set SESSION_DRIVER=file, then run:

sudo php artisan optimize

1 Like

I know about storage:link already, those steps are guarunteeing permissions in the user directory are correct, and that the group permission will not change later if you do something in there. Group permission might be irrelevant, and an ACL edit might be more effective, but I would test that a bit more first before I change it.

Unless you are extra verbose, and type ‘sudo -u www-data’ for every command you run in that directory ever, you will need to reassign those permissions. Seeing as it’s a very common issue for users to miss it, or break the permissions, I’m inclined to leave it.

I’ve added the ‘sudo -u www-data crontab -e’ command though. Alternatively you can run it as root anyways, and add ‘www-data’ right before the ‘php’ command in the cron entry, and it ought to run that command as www-data user.


thank you for the guide.
i tried and it worked

1 Like

Hey there. Thanks for the guide. I would like to reach out for help. I’m using ubuntu 20.04 LTS with nginx. I have followed the instructions provided by invoiceninja and here. I can’t pass the check_pdf. It shows “Oops, looks like something isn’t correct!” which is not descriptive to me. I tried to look for the controller in the repository but I can’t find any. My laravel log seems good. Can someone help me?

Here is my logs
[2020-12-28 02:00:01] staging.INFO: Sending recurring invoices 2020-12-28 02:00:01
[2020-12-28 02:00:01] staging.INFO: 2020-12-28 Sending Recurring Invoices. Count = 0
[2020-12-28 02:06:02] staging.INFO: GET - xxx/setup: 2 queries - 0.15784692764282
[2020-12-28 02:06:09] staging.INFO: POST - xxx/setup/check_pdf: 0 queries - 5.3190200328827
[2020-12-28 02:07:11] staging.INFO: POST - xxx/setup/check_pdf: 0 queries - 5.8493161201477
[2020-12-28 02:09:39] staging.INFO: GET - xxx/setup: 0 queries - 0.052273988723755
[2020-12-28 02:09:53] staging.INFO: POST - xxx/setup/check_pdf: 0 queries - 3.8224358558655

Thanks for the guide!
I would ask you to remove vim from the install list and replace occurences of sudo vim with sudoedit or alternatively use $EDITOR to respect the user preferences and not install unrelated packages :slight_smile:

Further, you could replace this:

with sudo systemctl enable --now mariadb

That’s a new function to me so I will look into it when I have time sure.

Just an update, NPM/Node is no longer required for installation. It also appears that on some systems, the MariaDB client isn’t installed, this is required to perform the initial migration it can be installed by running

sudo apt install MariaDB-client



On Ubuntu 20.04, I also had to install the packages ‘libgbm-dev’ and ‘libxshmfence-dev’. Otherwise, no PDF invoice could be generated.

1 Like

Hey there, installation for missing dependencies is noted in our docs:

Yes, but ‘libgbm-dev’ and ‘libxshmfence-dev’ are not listed there.

Thanks for clarifying. I’ve updated the snappdf documentation :+1: