Install Invoice Ninja v5 on Ubuntu 20.04
If you are self-hosting, installing on Ubuntu is the best possible method, and highly suggested. Running Ubuntu as a host allows you to install with the least amount of effort, fewer dependencies, and auto-update the application through the admin portal user interface. The ‘invoiceninja.zip’ package that is compiled by the Invoice NInja team every release has many dependency packages bundled into it, but it is only compatible with Ubuntu, and maybe other distros more similar to Ubuntu. Because this package is used for the auto updates as well, auto updates only work on Ubuntu.
- Most if not all of the commands below must be executed as sudo user, so you can enter a root user shell to make it easier, with
sudo bash
or you can just preface every command withsudo
. This guide and the commands below assume you are running a root user shell withsudo bash
.
First steps: Install dependencies
Invoice Ninja on Ubuntu production servers depends on PHP 8.1 and multiple PHP 8.1 extensions.
# apt update
# apt dist-upgrade -y
# apt install php8.1-bcmath php8.1-gmp php8.1-fileinfo php8.1-gd php8.1-mbstring php8.1-pdo php8.1-xml php8.1-cli php8.1-curl php8.1-zip php8.1-gmp php8.1-mysql php8.1-fpm
# apt install mariadb-server mariadb-client curl git nginx vim -y
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 php8.1-fpm
Second: Configure Mariadb
Start, and enable services for mariadb, the program/service that manages your SQL database and the incoming and outgoing communication it has with other applications like Invoice Ninja.
# systemctl enable --now mariadb
This command will take you through a guided wizard to initialize the SQL database.
# mysql_secure_installation
Enter current password for root (enter for none):
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y
These commands will directly access the SQL database through the services provided by mariadb. We will create a database with any arbitrary name ‘ninjadb’ in this example, and create arbitrary username and password combination ‘ninja’ and ‘ninjapass’. The database name will be used by InvoiceNinja during the server setup after installation is complete, as well as the username and password you specify here, in order for InvoiceNinja to login to the SQL database with read/write permission.
# 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
Third: Configure NGINX
FOR TESTING - NOT for Production use - OpenSSL certification
You should not need to do this. I am about to show you NGINX configuration file that points to an example based openssl cert. Most of you would be using letsencrypt, or some other CA. I am not going to provide a guide to setup letsencrypt. So for the purposes of this guide, the NGINX configuration will use an instant OpenSSL certificate that is not particularly trusted on the Internet.
# mkdir -p /etc/nginx/cert
# openssl req -new -x509 -days 365 -nodes -out /etc/nginx/cert/ninja.crt -keyout /etc/nginx/cert/ninja.key
Secure NGINX
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. When left unconfigured, this page presents some security loopholes. It can also cause conflicts sometimes. Lets remove it.
# rm /etc/nginx/sites-enabled/default
NGINX configuration page for website
Create the text configuration file for a new vhost in the sites-available
folder, best practice if you host multiple websites or webapps from a single server.
# vim /etc/nginx/sites-available/invoiceninja.mysite.com
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.
You cannot copy paste this entire document, you will need to edit appropriate sections to accomodate your own environment. I will try to “”“indicate”“” when specific strings of text need your attention.
server {
# NOTE That the 'default_server' option is only necessary if this is your primary domain application.
# If you run multiple subdomains from the same host already, remove the 'default_server' option.
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name """invoices.example.ca""";
client_max_body_size 20M;
# This if statement will forcefully redirect any connection attempts to explicitly use the domain name.
# If not, and your DNS doesn't provide IP address protection, accessing the server with direct IP can
# cause glitches with the services provided by the app, that could be security, or usability issues.
if ($host != $server_name) {
return 301 https://$server_name$request_uri;
}
# Here, enter the path to your invoiceninja directory, in the public dir. VERY IMPORTANT
# DO NOT point the root directly at your invoiceninja directory, it MUST point at the public folder
# This is for security reasons.
root /usr/share/nginx/"""invoiceninja"""/public;
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 php requests to the php8.1-fpm listen socket.
# PHP errors are often because this value is not correct.
# Verify your php8.1-fpm.sock socket file exists at the below directory
# and that the php8.1-fpm service is running.
fastcgi_pass unix:/run/php/php8.1-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;
server_name """invoices.example.ca""";
add_header Strict-Transport-Security max-age=2592000;
rewrite ^ https://$server_name$request_uri? permanent;
}
Create a symlink
In for NGINX to use the vhost file you just created, you must setup a symlink to the sites-enabled
folder, note that you must also use a full, explicit directory path and not a relative path for this command, or you will encounter an error:
# ln -s /etc/nginx/sites-available/invoiceninja.mysite.com /etc/nginx/sites-enabled/invoiceninja.mysite.com
Verify your NGINX configuration with the following command, and troubleshoot any errors on the lines it specifies for you;
# nginx -t
Disable & stop Apache2. Start & enable NGINX.
For Ubuntu Server edition, you might have apache2 installed and enabled by defualt. Follow the steps below to disable apache2, and enable nginx instead for webhosting service.
# systemctl stop apache2
# systemctl disable apache2
# systemctl start nginx
# systemctl enable nginx
Fourth: Installing Invoice Ninja
Installing the application files in the NGINX web server directory.
Please visit https://github.com/invoiceninja/invoiceninja/releases 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. Dropping to root will help us navigate the folder structure without permission issues.
# cd /usr/share/nginx
# mkdir invoiceninja && cd invoiceninja
# wget <latest invoiceninja.zip url link>
# unzip invoiceninja.zip
# rm invoiceninja.zip
Populate .env
file
The Invoice Ninja package doesn’t contain a .env
file, so it won’t overwrite your existing file when you update. It does include a .env.example
file. Note, that the .env
file will automatically be populated with
# cp .env.example .env
Backup your .env
file
# cp .env /path/to/backup/.env.bak
Prepare Invoice Ninja permissions
Set permissions for the directory and all its contents to allow web server permission to view and edit files. The default user for Ubuntu and debian based distros is www-data
.
# chown -R www-data:www-data /usr/share/nginx/invoiceninja
Enable Cron job automation
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: https://invoiceninja.github.io/selfhost.html#installing-invoice-ninja
# 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.
This will run, as user www-data, with the explicitly correct php version, the artisan schedule command in order to provide Invoice Ninja application with the backend services it needs to work properly. Edit the path according to your environment, also, specifying which version of php to use in the crontab, and other places, ensures we don’t inadvertently use the wrong version on a system with multiple versions of php running.
* * * * * php8.1 /usr/share/nginx/"""invoiceninja"""/artisan schedule:run >> /dev/null 2>&1
Fin
Now that your website is ready, you can run through the web-based setup of your company, by visiting the initial setup page:
https://invoiceninja.mysite.com/setup
BACKUP FILES & DATA
- Backup the
.env
file which holds primary server configurations - Backup the SQL database, by dumping it into a file.
- Backup the contents of the
public/storage
directory, where logo images, PDFs, attachments, etc are all saved in a nested structure, and referenced by the SQL database so the program can find them later.