Invoice Ninja v5 - New Server Build

Invoice-Ninja-Header-Logo

Wanted to share that I am working on building a new Invoice Ninja server based on v5 for production to replace the current server based on v4.5.xx. Maybe helpful if anyone was trying to build one or thinking about upgrading as there is a bit to it all. Possibly put my build sheet up when completed if anyone is interested.

Current Progress

  • Successfully constructed Invoice Ninja v5 on Debian 10 system with Apache2 and MariaDB
  • Successfully constructed with PHP 7.3, 7.4 and 8.0 (individual instances)
  • The PDF system was broken
  • Figured out the PDF issues

Debian? Apache? PHP v8.0?

  • Yes, I am a PITA and like my Debian and Apache2, nothing against other distros and NGINX
  • Why? In a word reliability and in another work simplicity. It comes down to the fact the Debian is NOT as cutting edge as Ubuntu and other distros. My goal is to build reliable systems that don’t require a lot of intervention to maintain and operate. less=simple=secure . My job is helping people with their systems not working on mine all day lol
  • Apache2 I know and can secure with things like QoS_mod, ModSec ModEvasive
  • Not running a high volume server. NGINX is great all around and excels at high volume, high demand websites.
  • PHP 8.0? Yes, 7.3 and 7.4 are old and getting older. 7.3 reaches EOL 6 December 2021, 7.4 about a year later. As this system will be up, in production for a year or more, I don’t want to deal with upgrading a production system. PHP 8 is stable and seems to have some performance gains over older versions too
  • Challenge level - No one else is doing it, I like to create my own path and it seems I like pain too, but no pain=no gain

Install Knowledge Gained

  • The current construction documents on Invoice Ninja dot org are a little confusing
  • Decide up front if you want to build from source or from the precompiled zip
  • I chose the precompiled zip for 2 main reasons; A. don’t have to install a compiler B. Don’t have to manage and secure a compiler - less=simple=secure is a must for production systems
  • Process, Process, Process
  • Suggest a “rapid build” as I call them. Build it in the lab, no, frills, no extras, plain stock, vanilla basic build, because things break and figuring out where and what caused the break can be massively time consuming.
  • Don’t put the system on line in production yet, even for “testing”. Just build the basics; OS LAMP with a self-signed certificate and Invoice Ninja, then test functionality before getting knee deep in the blood and guts of the system internals with security and other configurations.
  • Establishing a baseline of functionality is important so you can know how the system is supposed to function, and also know when something is broken
  • Test, Test, Test
  • Enable debugging (in the .env file) so you can see what happened when the system horks
  • One configuration change can break stuff, seems the most easily broken parts are the PDF generation in the business facing dashboard (Quote Creation, viewing quotes and others) and the customer facing client portal.
  • Debugging can be enabled in the .env file for Invoice Ninja and for PDF creation, suggest enabling these and then looking at the logs at /storage/logs/laravel.log
  • After making changes to .env, it is always required to run sudo php artisan optimize to make the changes take affect
  • Always test the ability to create or view existing PDFs in the dash and the client portal
  • Reboot and test after a group of config changes to see if anything was broken, caught two issues this way
  • Later configurations can cause minor to major security issues. You don’t want issues with anything handling your payments or your paying customers.
  • VM snapshots are your friend, rolled back a lot of stuff after I killed something with misconfiguration
  • If you want a turnkey system, look at Cloudron, they have Invoice Ninja v5 now and it installs with 2 clicks

PDF subsystem knowledge gained

  • There are 2 options for PDF creation, Phantom PDF and SnapPDF
  • Phantom PDF (PhantomJS) is the default built-in and is basically a cloud based service that has a default API key provided that allows for creation of 100 PDF pages per day
  • It looks like a free API key can be had for low volume generation, up to 500 PDF pages created per day
  • CRITICAL: PhantomJS development (and support) have been suspended. Seems the project has been forked but don’t want to deal with potential security or support issues - Statement here https://phantomjs.org/
  • CRITICAL: Phantom PDF is almost always required for Invoice Ninja Instances hosted on VPS or even some Docker hosts as access to the configs for NGINX, Apache2 or PHP are restricted
  • PhantomJS seems it does NOT require installation of NodeJS or NPM to work as those components are “baked-in” to Invoice Ninja
  • I went the other way on PDF as I self host on my XCP-ng system and use SnapPDF
  • SnapPDF works well and is easy to install
  • Lots of packages are needed to get the PDF engine working right

Cron Job to Refresh the data

  • Don’t forget this thing or you will have a nasty red “!” (bang) in the lower left corner of the dashboard. To quote the info from the site about this “Invoice Ninja relies heavily on the Laravel Scheduler, for this to operate it requires that a cron job to be configured, edit your crontab and enter the following record.”
  • Seems this is challenge for some trying to stand up instances on some VPS host or Docker as the provider has cron jobs locked down or inaccessible

Configuration and Management knowledge gained

  • .env is the primary config file for the site as it was in previous versions of Invoice Ninja
  • Make backups of the original .env before doing anything, A clean version is good for reference or restore if things hit the fan
  • Debugging can be enabled in the .env file for Invoice Ninja and for PDF creation, suggest enabling these and then looking at the logs at (ninja install)/storage/logs/laravel.log
  • After making changes to .env it is always required to run sudo php artisan optimize to make the changes take affect
  • Other commands that are your friend are sudo apache2ctl configtest, sudo systemctl restart apache2

Hope you find this helpful.

Invoice_Ninja

3 Likes

Key Resources

Invoice Ninja Self Hosted Install Free Open-Source Invoicing, Expenses & Time-Tracking | Invoice Ninja

Precompiled Invoice Ninja (look for “5.x.xx- release”) Releases · invoiceninja/invoiceninja · GitHub
From the terminal pull the zip with sudo wget

Invoice Ninja Support Forums https://forum.invoiceninja.com/

PhantomJS Cloud https://phantomjscloud.com/

Free PhantomJS API key (up to 500 PDF pages per day) PhantomJs Cloud | Account Dashboard?

Snappdf GitHub - beganovich/snappdf: A simple library that lets you convert webpages or HTML into PDF files using Chromium or Google Chrome.

1 Like

@LTS_Tom Catching up on my podcasts and just realized that you are working on you Invoice Ninja v5 upgrade too.

Invoice Ninja v5 Self Hosted Build Sheet

Objective: Install and configure Invoice Ninja v5 on a Debian server for basic functionality testing.

Skill Level – Novice: This guide is written as a “soup to nuts” guide to help users with basic or entry level skills to stand up their own Invoice Ninja v5 self-hosted instance. Goal here is exposure, penetration and proliferation of using open source software and projects.

Critical Note: This is NOT a production quality build and is NOT secure for production use
Other Note: This is for new installations and not for upgrading or migrating existing installations
Other Note: This system build can be secured with additional configuration and then used for production and is how I have done mine. Securing the server for production is beyond the scope of this post.

System Environment

  • Self hosted VM on XCP-ng
  • Debian 10 server (no GUI)
  • 1 CPU
  • 4 GB RAM
  • 40 GB HDD
  • LAMP stack with
  • Apache 2 (latest version)
  • PHP v8.0 (latest version)
  • MariaDB (latest version)
  • Self-signed TLS (SSL) certificate

Resources
Debian 10 - Net install image amd64 Debian -- Network install from a minimal CD (current version is debian-10.9.0-amd64-netinst.iso) Requires internet connectivity during install
Invoice Ninja v5 - Primary Documentation https://invoiceninja.github.io/

Estimated time to complete – 40 mins to 1.5 hours (timed with many standard interruptions; phone calls emails and others)

Process Overview

  1. Installation and configuration of the OS
  2. Installation & configuration of base packages
  3. Installation, configuration and testing of Apache 2
  4. Installation and configuration of MariaDB
  5. Installation, configuration and testing of PHP 8.0
  6. Installing Composer and PDF Engine Considerations
  7. Installing Invoice Ninja
  8. Invoice Ninja v5 First Time Run Configuration
  9. Testing and House Keeping

I’ve wondered about upgrading to v5, but this makes it sound like it probably isn’t time yet.

Part 1 - Installing the Debian 10 OS

  • Using XCP-ng and Xen Orchestra
  • 1 CPU
  • 4 GB RAM
  • 1 NIC
  • 40 GB HDD

OS Install
Options in order of appearance

  • Install
  • English (default)
  • United States (default)
  • American English (default)
  • The next two settings are critical if setting this system up for production as it will establish the FQDN. This is the foundation for setting up critical things like TLS (SSL) certificates from Let’s Encrypt and configuration during the build process. It can be changed later but it can be challenging after the fact.
  • Configure the network Hostname: ninja01
  • Domain name: (your domain name)
  • (Optional) Root password – I skip this with continue. If you want to have root, then set the password. Skipping this will automatically install SUDO. I do this as the system will be converted into a production system and not using root is best practices for security
  • Configure the clock: Eastern (default)
  • Next setting is partitioning the disk. If this build will end up being used for production, strongly recommend setting up LVM (full disk encryption) at this point. It can be done later but is challenging. Because this is a demo build for me, I will not be setting this up. If you use LVM encryption, let the system wipe the partition and you will need to set a password to unlock the partition at start up or reboot
  • Partition disks: Guided – use entire disk (default)
  • Select disk to partition: Virtual disk 1 (xvda) – 42.9 GB Xen Virtual Block Device (default and only choice) (This is the designation used by XCP-ng and Citrix Xen Server. Bare metal install and other hypervisors will display other things like sda)
  • Partition scheme: All files in one partition (recommended for new user) (default)
  • Partition overview: Finish partitioning and write changes to disk (default)
  • Write the changes to disk: Yes
  • Installer will kick off and pull in the base packages over the internet
  • Configure package manager, scan another CD or DVD: No (default)
  • Debian archive mirror country: United States (default)
  • Debian archive mirror: deb.debian.org (default)
  • HTTP proxy information (blank for none): (blank) Continue
  • Participate in the package usage survey: No (default)
  • Software selection: This is critical if building a production system.

  • Debian desktop environment: Uncheck (no GUI will be installed and is recommended for server installs)
  • Print server: Uncheck
  • SSH server: Check
  • Standard system utilities: Check (default)
  • Continue
  • Software installation will start
  • Install the GRUB boot loader to the master boot record?: Yes (default)
  • Device for boot loader installation: /dev/xvda (This is the choice for XCP-ng VM. Bare metal installs or other hypervisors will list options with other names such as /dev/sda)
  • GRUB boot loader will install
  • Installation complete: Eject the ISO image, and select the XCP-ng guest tools ISO. After the system reboots, you will need to install the guest tools for whatever hypervisor you are using. Continue (default)
  • System will reboot. If you configured LVM, you will need to enter the password to unlock the drive

Part 2 - Configuring the OS

Note: As I am not using the “root” user, all commands will be using SUDO – If you are using root, you can either remove SUDO from my commands or install SUDO to avoid editing every command.
Note: For users new to Linux, commands are case sensitive and will fail if the wrong case is used

First task is to install the hypervisor guest tools. Without these tools, the VM will not run well, it will be difficult to shutdown and reboot also. If this is a bare metal install, you can skip this part

Installing Guest Tools for VMs

  • Make sure the guest tools ISO is inserted

  • Log into the terminal

  • Commands to install the guest tools for XCP-ng are:
    sudo mount /dev/cdrom /mnt
    sudo bash /mnt/Linux/install.sh

  • If using another distro derived from a major distro, it may be necessary to use arguments to install the guest tools.More here for installing XCP-ng Guest Tools at VM | XCP-ng documentation

  • Example installing on REHL or CentOS 8 :
    sudo bash /mnt/Linux/install.sh -d rhel -m 8

  • Continue? Y

  • Unmount the CD Rom:
    sudo umount /dev/cdrom

REQUIRED - Reboot the system to enable the guest tools:
sudo shutdown -r 0

  • Eject the Guest Tools ISO
    After reboot, the VM will display the version of the management engine in the General tab

Install and Configure SSH for terminal use

  • Log into the system at the terminal console

  • Update the system:
    sudo apt update && sudo apt upgrade -yy && sudo apt autoremove -y

  • Install SSH (if not done during installation)
    sudo apt install ssh

  • Enable the SSH as a service:
    sudo systemctl enable ssh

  • Check the SSH service to see if it is running:
    sudo systemctl status sshd

  • If not running, then use:
    sudo systemctl start sshd

  • Display the local IP address of the system:
    ip a

  • Access the system using SSH – Windows users can install PuTTY

  • Note: For users new to Linux, using the terminal you can copy and paste commands when using the terminal

  • (Linux Terminal) ssh (user name of the invoice ninja system)@(IP address of the invoice ninja system)
    Example ssh root@192.168.3.15

  • (Optional) reboot the system to see that if the SSH service starts automatically:
    sudo shutdown -r 0
    then log on over ssh. If it doesn’t work, then the SSH service needs to be enabled

Installing Additional Base Packages

  • These packages will help get things setup for later and adds some basic utilities
    sudo apt install gnupg gnupg1 gnupg2 apt-transport-https tmux git curl wget net-tools traceroute htop unzip

Part 3 - Installation, configuration and testing of Apache 2

  • Install apache 2 and the apache utilities
    sudo apt install apache2 apache2-utils
  • Is the apache 2 service running?
    sudo systemctl status apache2
    Ctrl + C to exit
  • Creating self-signed TLS (SSL ) certificate :
    sudo openssl req -x509 -nodes -days 3650 -newkey rsa:4096 -keyout /etc/ssl/private/apache-selfsigned.key -out /etc/ssl/certs/apache-selfsigned.crt

Input for self-signed certificate

Country Name (2 letter code) [AU]: **US**
State or Province Name (full name) [Some-State]: **(Your state here)**
Locality Name (eg, city) []: **(your city here)**
Organization Name (eg, company) [Internet Widgits Pty Ltd]: **(Business or other name here)**
Organizational Unit Name (eg, section) []: *Optional field*
Common Name (e.g. server FQDN or YOUR name) []: ***(use the host name of the system with the  domain name set during the install process)***
Email Address []: ***set an email address here, suggest using either an email alias or a fake email address as the info can be harvested by spammers***
  • The self-signed certs will be created and can be viewed here at /etc/ssl/private/apache-selfsigned.key and /etc/ssl/certs/apache-selfsigned.crt

  • (Optional) If you want to see the newly created keys use:
    ls /etc/ssl/certs/ and look for a file named apache-selfsigned.crt

  • (Optional) To see the other file created, use
    sudo ls /etc/ssl/private/ and look for a file named apache-selfsigned.key

  • Create and edit the SSL parameters file
    sudo nano /etc/apache2/conf-available/ssl-params.conf

  • Add the following into the file, save and close

    SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4
    SSLProtocol -all +TLSv1.3 +TLSv1.2
    SSLHonorCipherOrder On
    # Requires Apache >= 2.4
    SSLCompression off
    # SSLUseStapling on
    # SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
    # Requires Apache >= 2.4.11
    SSLSessionTickets Off
    
  • Edit the default-ssl.conf file
    sudo nano /etc/apache2/sites-available/default-ssl.conf

  • We will add the following items to the file. A snipit of the file edit for example is shown

    ServerAdmin your email address (alias or fake) here
    ServerName ninja01.( your domain name here )
    ServerAlias ninja01
    

Replace

            SSLCertificateFile      /etc/ssl/certs/ssl-cert-snakeoil.pem
            SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

With

            SSLCertificateFile	    /etc/ssl/certs/apache-selfsigned.crt
            SSLCertificateKeyFile 	/etc/ssl/private/apache-selfsigned.key

Snippet example

 <IfModule mod_ssl.c>
    <VirtualHost _default_:443>
            ServerAdmin your email address (alias or fake) here
            ServerName ninja01.(your domain name here)
            ServerAlias ninja01
            DocumentRoot /var/www/html
            # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
            # error, crit, alert, emerg.
            # It is also possible to configure the loglevel for particular
            # modules, e.g.
            #LogLevel info ssl:warn

            ErrorLog ${APACHE_LOG_DIR}/error.log
            CustomLog ${APACHE_LOG_DIR}/access.log combined

            # For most configuration files from conf-available/, which are
            # enabled or disabled at a global level, it is possible to
            # include a line for only one particular virtual host. For example the
            # following line enables the CGI configuration for this host only
            # after it has been globally disabled with "a2disconf".
            #Include conf-available/serve-cgi-bin.conf

            #   SSL Engine Switch:
            #   Enable/Disable SSL for this virtual host.
            SSLEngine on

            #   A self-signed (snakeoil) certificate can be created by installing
            #   the ssl-cert package. See
            #   /usr/share/doc/apache2/README.Debian.gz for more info.
            #   If both key and certificate are stored in the same file, only the
            #   SSLCertificateFile directive is needed.
            SSLCertificateFile      /etc/ssl/certs/apache-selfsigned.crt
            SSLCertificateKeyFile   /etc/ssl/private/apache-selfsigned.key

            # SSLCertificateFile     /etc/ssl/certs/ssl-cert-snakeoil.pem
            # SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
  • Save and close

  • Edit the 000-default.conf file
    sudo nano /etc/apache2/sites-available/000-default.conf

  • We will add the following items to the file. A snipit of the file edit for example is shown

    ServerAdmin your email address (alias or fake) here
    ServerName ninja01.(your domain name here)
    ServerAlias www.ninja01.(your domain name here)
    DocumentRoot /var/www/html (no change here)
    Redirect permanent "/" "https://ninja01.(your domain name here)/" (this setting redirects HTTP to HTTPS)
    

Snippit example

<VirtualHost *:80>
    # The ServerName directive sets the request scheme, hostname and port that
    # the server uses to identify itself. This is used when creating
    # redirection URLs. In the context of virtual hosts, the ServerName
    # specifies what hostname must appear in the request's Host: header to
    # match this virtual host. For the default virtual host (this file) this
    # value is not decisive as it is used as a last resort host regardless.
    # However, you must set it for any further virtual host explicitly.
    #ServerName www.example.com

    ServerAdmin your email address (alias or fake) here
    ServerName ninja01.(your domain name here)
    ServerAlias www.ninja01.(your domain name here)
    DocumentRoot /var/www/html
    Redirect permanent "/" "https://ninja01.(your domain name here)/"

    # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
    # error, crit, alert, emerg.
    # It is also possible to configure the loglevel for particular
    # modules, e.g.
    #LogLevel info ssl:warn

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    # For most configuration files from conf-available/, which are
    # enabled or disabled at a global level, it is possible to
  • Save and close

  • Enable various items for Apache 2
    sudo a2enmod ssl
    sudo a2ensite default-ssl
    sudo a2enconf ssl-params
    sudo a2ensite 000-default.conf
    sudo a2enmod rewrite

  • Test the configuration and reload Apache 2
    sudo apache2ctl configtest
    sudo systemctl restart apache2

Functionality Testing of Apache

  • Look at the default Apache 2 page with a web browser
    http://ninja01
  • Should automatically switch from http to https

Part 4 - Installation and configuration of MariaDB

Installing MariaDB
sudo apt install mariadb-server mariadb-client

  • Enable MariaDB service :
    sudo systemctl enable mariadb
  • (Optional) view the status of the MariaDB service:
    sudo systemctl status mariadb

Configuring MariaDB

  • Securing MariaDB using:
    sudo mysql_secure_installation

    NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
    SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!
    
    In order to log into MariaDB to secure it, we'll need the current
    password for the root user.  If you've just installed MariaDB, and
    you haven't set the root password yet, the password will be blank,
    so you should just press enter here.
    
    Enter current password for root (enter for none): 
    
    Setting the root password ensures that nobody can log into the MariaDB
    root user without the proper authorization.
    
    Change the root password? [Y/n] y
    
    By default, a MariaDB installation has an anonymous user, allowing anyone
    to log into MariaDB without having to have a user account created for
    them.  This is intended only for testing, and to make the installation
    go a bit smoother.  You should remove them before moving into a
    production environment.
    
    Remove anonymous users? [Y/n] y
    ... Success!
    
    Normally, root should only be allowed to connect from 'localhost'.  This
    ensures that someone cannot guess at the root password from the network.
    
    Disallow root login remotely? [Y/n] y
    ... Success!
    
    By default, MariaDB comes with a database named 'test' that anyone can
    access.  This is also intended only for testing, and should be removed
    before moving into a production environment.
    
    Remove test database and access to it? [Y/n] y
    - Dropping test database...
    ... Success!
    - Removing privileges on test database...
     ... Success!
    
    Reloading the privilege tables will ensure that all changes made so far
    will take effect immediately.
    
    Reload privilege tables now? [Y/n] y
    ... Success!
    
    Cleaning up...
    
    All done!  If you've completed all of the above steps, your MariaDB
    installation should now be secure.
    
    Thanks for using MariaDB!
    

Add a user account to MariaDB
sudo mysql -u root -p

  • Enter the password just configured for root in previous step

  • Note: All commands in this MariaDB config part end in “;”

    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 218
    Server version: 10.3.27-MariaDB-0+deb10u1 Debian 10
    
    Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
     MariaDB [(none)]> CREATE DATABASE invoiceninja;
    
     MariaDB [(none)]> SHOW DATABASES;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | invoiceninja       |
    | mysql              |
    | performance_schema |
    +--------------------+
    4 rows in set (0.002 sec)
    
    MariaDB [(none)]> CREATE USER 'invoiceninjauser'@'localhost' IDENTIFIED BY 'password1234!';
    
    MariaDB [(none)]> GRANT ALL ON invoiceninja.* TO 'invoiceninjauser'@'localhost' IDENTIFIED BY 'password1234!' WITH GRANT OPTION;
    
    MariaDB [(none)]> flush privileges;
    
    MariaDB [(none)]> select user from mysql.user;
    +------------------+
    | user             |
    +------------------+
    | invoiceninjauser |
    | root             |
    +------------------+
    2 rows in set (0.001 sec)
    
    MariaDB [(none)]> exit;
    
  • MariaDB is configuration completed. You will need the invoiceninjauser and the password later for Invoice Ninja configuration

Part 5 - PHP 8.0 Install, Configuration and Testing

  • Before PHP 8.0 can be installed, we need to add somethings to the package repository

  • Add the repository to the local keyring

    sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
    
  • Add the source to the repository

    echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/php.list
    
  • Update the repository
    sudo apt update (if you don’t do this, the next step will fail)

  • Note: my build had updates ready to install (sudo apt upgrade)

  • Installing PHP version 8.0 and the required modules for Invoice Ninja to function

    sudo apt install php8.0-common php8.0-mysql php8.0 php8.0-cli php8.0-bcmath php8.0-gmp php8.0-gd php8.0-mbstring php8.0-xml php8.0-curl php8.0-zip php8.0-gmp php8.0-fpm libapache2-mod-php libapache2-mod-fcgid
    
  • At the end of installing you will see notice messages. We will run
    sudo a2enmod proxy_fcgi setenvif
    sudo a2enconf php8.0-fpm
    sudo a2dismod php8.0
    sudo a2dismod mpm_event

  • We can see if the configuration is sound
    sudo apachectl configtest

  • Reload Apache 2
    sudo systemctl restart apache2

Testing PHP Functionality

  • Need to create a file that will display the specifics of our PHP installation
    sudo nano /var/www/html/phpinfo.php

  • Add, save and close

     <?php phpinfo( ); ?>
    
  • Open a web browser on your local PC and point it to https://ninja01/phpinfo.php

- Strongly recommend saving this web page for future reference (right click save as)

Part 6 - Installing Composer and PDF Engine Considerations

  • Invoice Ninja is created with Lavavel and to for Composer to work, we need to get copy Invoice Ninja to the working directory at /var/www/html/invoiceninja
  • Critical: PDF Creation Engine - By default Invoice Ninja server comes with Phantom PDF (Phantom JS), a cloud based PDF creation engine. Phantom PDF seems to be required for VPS and containerized (Docker) server instances. It is optional for use on self-hosted setups like mine. The default configuration comes with the ability to create 100 PDF pages per day. If you decide to use Phantom PDF and need more than 100 pages per day, you can register here for a free API key that will provide creation of up to 500 PDF pages per day. The link is here at PhantomJs Cloud | Account Dashboard?
  • My build uses the SnapPDF Engine and will disable the PhantomJS Engine, so in the next few steps, you can skip anything marked " Required for SnapPDF"
  • (Required for SnapPDF) Installing the many things needed to make the SnapPDF engine work
    sudo apt install libappindicator3-1 libdbusmenu-gtk3-4 libgbm-dev libgbm1 libindicator3-7 libwayland-server0 libxshmfence-dev gconf-service libasound2 libatk1.0-0 libcairo2 libgconf-2-4 libgdk-pixbuf2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libx11-xcb1 libxcomposite1 libxcursor1 libxdamage1 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 fonts-liberation libappindicator1 libnss3 xdg-utils

Part 7 - Installing Invoice Ninja

  • Stop Apache 2
    sudo systemctl stop apache2

  • Create the working directory for Invoice Ninja
    sudo mkdir /var/www/html/invoiceninja

  • Change to the newly created directory as the commands will be run from there
    cd /var/www/html/invoiceninja

  • Download Invoice Ninja - Note the zip file is older then the current version so we can test the functionality of the update within Invoice Ninja. If you want to skip this, modify the URL in the nect command with the version number of the current release here at Releases · invoiceninja/invoiceninja · GitHub

    sudo wget https://github.com/invoiceninja/invoiceninja/releases/download/v5.1.62-release/invoiceninja.zip
    
  • (Optional) Display the downloaded invoiceninja.zip file in the /var/www/html/invoiceninja/ working directory
    ls -la - We should see a file called invoiceninja.zip

  • Unzip the invoiceninja.zip file in the /var/www/html/invoiceninja/ working directory
    sudo unzip invoiceninja.zip

Install and Run Composer

  • Installing composer is different than other things that have been installed earlier

    curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin –filename=composer
    
  • You should get …

    All settings correct for using Composer
    Downloading...
    
    Composer (version 2.1.3) successfully installed to: /usr/local/bin/composer.phar
    Use it: php /usr/local/bin/composer.phar
    
  • Use Composer to install Invoice Ninja in the working directory
    sudo composer install --no-dev -o

  • Ignore the warning and install as sudo or the task will fail with the following error

    [ErrorException]                                                                                                               
    file_put_contents(/var/www/html/invoiceninja/vendor/composer/autoload_classmap.php): Failed to open stream: Permission denied 
    
  • Generate a new unique key, make sure to copy it somewhere during the .env configuration
    sudo php artisan key:generate (Do not run this command more than once,especially after the system is live as the key it generates is unique. If there is an issue or you need to migrate data, loss of this key will cause issues)

  • Create a clean untouched backup of the .env file
    sudo cp .env .env.oem.bak

  • Open the .env and edit
    sudo nano .env

The .env file is the main configuration file for Invoice Ninja and contains lots of important stuff. The important things to configure are the username and password to the local SQL database (MariaDB) we configured earlier. Also because this example uses SnapPDF instead of PhantomJS, we need to disable Phantom. In the .env file we can also enable debugging and PDF debugging as those seem to be the things that break frequently

.env local database configuration

The default configuration looks like this

DB_HOST1=localhost
DB_DATABASE1=ninja
DB_USERNAME1=ninja
DB_PASSWORD1=ninja
DB_PORT1=3306

We need to change it to this - for the DB_PASSWORD field, substitute the password established during the setup of MariaDB.

DB_HOST1=localhost
DB_DATABASE1=invoiceninja
DB_USERNAME1=invoiceninjauser
DB_PASSWORD1=password1234!
DB_PORT1=3306
  • Note: If you change the database password for the invoiceninjauser account in the future, you will need to update the password here in the .env file or Invoice Ninja can’t communicate with the database.
  • (Required for SnapPDF) Disabling PhantomJS to enable SnapPDF

Default configuration looks like this

#options - snappdf / phantom / hosted_ninja
PDF_GENERATOR=phantom

PHANTOMJS_KEY='a-demo-key-with-low-quota-per-ip-address'
PHANTOMJS_SECRET=secret

UPDATE_SECRET=secret

COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}'
SENTRY_LARAVEL_DSN=https://cc7e8e2c678041689e53e409b7dba236@sentry.invoicing.co/5

Add the line PHANTOMJS_PDF_GENERATION=false and comment out the things related to PhantomJS. Also, we will add the line LOG_PDF_HTML=true for PDF debugging as the PDF seems to be sensitive to many things and breaks frequently. Make it look like this to disable PhantomJS and enable SnapPDF

#options - snappdf / phantom / hosted_ninja
#PDF_GENERATOR=phantom 

#PHANTOMJS_KEY='a-demo-key-with-low-quota-per-ip-address'
#PHANTOMJS_SECRET=secret

UPDATE_SECRET=secret

PHANTOMJS_PDF_GENERATION=false
COMPOSER_AUTH='{"github-oauth": {"github.com": "${{ secrets.GITHUB_TOKEN }}"}}'
SENTRY_LARAVEL_DSN=https://cc7e8e2c678041689e53e409b7dba236@sentry.invoicing.co/5

LOG_PDF_HTML=true
  • Save and close
  • CRITICAL NOTE: Anytime the .env file is changed, or Invoice Ninja is updated to a new version, you need to run sudo php artisan optimize for the changes to take effect
  • Update Artisan with new configuration
    sudo php artisan optimize

Enabling Invoice Ninja in Apache

  • Create a copy of the default website config for Invoice Ninja
    sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/invoiceninja.conf
  • Edit the newly created invoiceninja.conf file
    sudo nano /etc/apache2/sites-available/invoiceninja.conf

Add at the top

<Directory /var/www/html/invoiceninja/public/>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

Change

   DocumentRoot /var/www/html 

To

   DocumentRoot /var/www/html/invoiceninja/public

Should look like this

<Directory /var/www/html/invoiceninja/public/>
   Options Indexes FollowSymLinks
   AllowOverride All
   Require all granted
</Directory>
<VirtualHost *:80>
    # The ServerName directive sets the request scheme, hostname and port that
    # the server uses to identify itself. This is used when creating
    # redirection URLs. In the context of virtual hosts, the ServerName
    # specifies what hostname must appear in the request's Host: header to
    # match this virtual host. For the default virtual host (this file) this
    # value is not decisive as it is used as a last resort host regardless.
    # However, you must set it for any further virtual host explicitly.
    # ServerName www.example.com

    ServerAdmin xxxx@(your fake email address here)
    ServerName ninja01.(your domain name here)
    ServerAlias www.ninja01.(your domain name here)
    DocumentRoot /var/www/html/invoiceninja/public
    Redirect permanent "/" "https://ninja01.(your domain name here)/"
  • Save and close the editor
  • Edit the default-ssl.conf file
    sudo nano /etc/apache2/sites-available/default-ssl.conf

Change

DocumentRoot /var/www/html

To

DocumentRoot /var/www/html/invoiceninja/public

Should look like this

 <IfModule mod_ssl.c>
    <VirtualHost _default_:443>
            ServerAdmin your email address (alias or fake) here
            ServerName ninja01.(your domain name here)
            ServerAlias ninja01
            DocumentRoot /var/www/html/invoiceninja/public
            # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
            # error, crit, alert, emerg.
            # It is also possible to configure the loglevel for particular
            # modules, e.g.
            #LogLevel info ssl:warn

            ErrorLog ${APACHE_LOG_DIR}/error.log
            CustomLog ${APACHE_LOG_DIR}/access.log combined

            # For most configuration files from conf-available/, which are
            # enabled or disabled at a global level, it is possible to
            # include a line for only one particular virtual host. For example the
            # following line enables the CGI configuration for this host only
            # after it has been globally disabled with "a2disconf".
            #Include conf-available/serve-cgi-bin.conf

            #   SSL Engine Switch:
            #   Enable/Disable SSL for this virtual host.
            SSLEngine on

           #   A self-signed (snakeoil) certificate can be created by installing
           #   the ssl-cert package. See
           #   /usr/share/doc/apache2/README.Debian.gz for more info.
           #   If both key and certificate are stored in the same file, only the
           #   SSLCertificateFile directive is needed.
           SSLCertificateFile      /etc/ssl/certs/apache-selfsigned.crt
           SSLCertificateKeyFile   /etc/ssl/private/apache-selfsigned.key

           # SSLCertificateFile     /etc/ssl/certs/ssl-cert-snakeoil.pem
           # SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
  • Save and close

  • Critical Step: Set up cron job for Invoice Ninja – Without this you get a red “!” on the dashboard and data won’t refresh
    sudo -u www-data crontab -e

Add this at the bottom, save and close

* * * * * cd /var/www/html/invoiceninja && php artisan schedule:run >> /dev/null 2>&1
  • (Optional) display the cron job
    sudo -u www-data crontab -l

  • Enable cron
    sudo systemctl enable cron

  • (Optional) see if cron is running or restart cron
    sudo systemctl status cron
    sudo systemctl start cron
    Ctrl + C to exit the status

  • Clean up the Apache and PHP test web page files from earlier
    sudo mv /var/www/html/index.html /var/www/html/index.html.bak
    sudo mv /var/www/html/phpinfo.php /var/www/html/phpinfo.php.bak

  • Set the owner and file permissions on the web root directories
    sudo chown -R www-data:www-data /var/www/html/invoiceninja/
    sudo chmod -R 755 /var/www/html/invoiceninja/

  • Disable the default site and enable the new Invoice Ninja site in Apache
    sudo a2dissite 000-default.conf
    sudo a2ensite invoiceninja.conf

  • Enable various modules for Apache to communicate with PHP
    sudo a2enmod proxy_fcgi setenvif
    sudo a2enconf php8.0-fpm
    sudo a2dismod php8.0
    sudo a2dismod mpm_prefork
    sudo a2enmod mpm_event

  • Test the Apache configuration and reload Apache
    sudo apache2ctl configtest
    sudo systemctl restart apache2
    sudo systemctl restart cron

Part 8 - Invoice Ninja v5 First Time Run Configuration
Open a local web browser and navigate to the system at https://ninja01/setup
If all went well during install, the first time run page will appear

  • URL - Set this to the FQDN name of the server. Example https://ninja01.mydomain.com
  • HTTPS should be checked by default
  • (Opional) Reports - to forward data to the developers
  • Test PDF to continue with the setup, you will need to press this button. If the PDF engine is broken, troubleshooting will be needed here

Troubleshooting Issues

  • Log files are the place to see whats happening when things break
  • Invoice Ninja Logs
    nano /var/www/html/invoiceninja/storage/logs/laravel.log
    Or
    cat /var/www/html/invoiceninja/storage/logs/laravel.log
  • Apache Logs
    nano /var/log/apache2/error.log
    Or
    cat /var/log/apache2/error.log

Database Connection

  • Even though this was configured earlier when we edited the .env, we still need to populate the info again. I consider this a design issue as the setup needs to communicate with the database before the setup is completed (circular reference?!). That is why we added the database info earlier
  • Host: localhost (default)
  • Port: 3306 (default)
  • Database: invoiceninja (configured in the MariaDB setup earlier)
  • Username: invoiceninjauser (configured in the MariaDB setup earlier)
  • Password: (password established for invoiceninjauser during the MariaDB earlier)
  • Test Connection when completed

Email Settings

-This will be specific to your email provider. I run my own mail servers, so your configuration may differ from mine

  • Driver: SMTP
  • From Name: (Name of your business or your name)
  • From Address: (email address of the account you want to use for relaying emails through your email service or server)
  • Username: (email address of the account you want to use for relaying emails through your email service or server, can be the same or different from the address set for From Address)
  • Port: 587 (is standard for encrypted email communications)
  • Password: (password for the username entered above)
  • Encryption: STARTTLS (depends on your email host configuration)
  • Send Test Email when completed to move to the last part of setup

User Details

  • In this section we set the administrator account for the Invoice Ninja web console
  • First Name: (Anything)
  • Last Name: ( Anything)
  • Email: (set a real email address for this field as it used for password resets and alerts)
  • Agree to the Terms of Service and Terms Privacy Policy
  • Submit to complete. It takes a few seconds even on fast systems for this to complete

Part 9 - Testing & Housekeeping Tasks

Congrats if you made it this far

0029 - Red Bang

  • Red bang “!” in the lower left corner?
    sudo systemctl restart cron
    Ctrl + F5 to refresh the Invoice Ninja dashboard web page and the red bang “!” should be gone
  • This is related to the cron job setup earlier in the build process

0028 - Blue Bang

  • Blue bang “!” in the lower corner?
  • Invoice Ninja is ready to update
  • Lower left corner > Blue Bang > Update Now

0030 - Update

  • If you check the system health after updating, it will say it needs to be optimized
    From the terminal
    cd /var/www/html/invoiceninja
    sudo php artisan optimize

0031 - Opto

Open Basedir

  • Played with this setting in PHP but was not able to disable the alert
  • Can break the system (Error 500) easily trying to correct this issue
  • Leaving it alone for now as it seems to be a bug?

Functionality Testing

  • These test exposed many issues. Recommend enabling debugging in the .env while working through issues.
    sudo nano /var/www/html/invoiceninja/.env
    Set APP_DEBUG=true
    Save and close, then reload the change with
    sudo php artisan optimize
    Refresh the web page of Invoice Ninja console and the debugging notice will appear.
    Ctrl + F5
    Additional logging happens in the /var/www/html/invoiceninja/storage/logs/laravel.log

  • Testing is critical, most of the first issues encountered were related to the PDF creation. Strongly suggest using this process for testing PDF functionality

  1. Create a test user and fully populate name, email address, phone number and address. Suggest using a real email address to fully test relay functionality
  2. Create a quote and save it but don’t send it yet
  3. View the PDF related to the quote (Quotes > Click on the quote to select the quote > 3 dots on the right side >) Select View PDF and Client Portal to test PDF rendering
  4. In the Client Portal try downloading the PDF, opening the PDF in another tab
  5. Back in the dash board, edit the quote adding more items and changing the quantity of items and save the changes
  6. Open the PDFs again from the dash and client portal
  7. Email the quote and try opening the quote from a system on the same local network as the server. Again try downloading the quote
  8. Edit the same quote again and resend it. Try opening or refreshing the PDF from the client portal

Dumping your command history in the terminal
sudo history - copy and paste somewhere for reference

Final Notes

  • This configuration is minimal and is in no way ready for production
  • Can turn this system into a production server with additional configuration

This guide is for new builds and is not intended for in place upgrades. It seems like a lot, but it goes quickly. Wanted to put up a step by step with testing as we go to help new users

2 Likes

Login bug I ran into here at Invoice Ninja v5 - Log In Bug (Confirmed - Fixed by Devs and Pending Release)

Bug has been fixed and the fix will be applied in an upcoming update

September 2021 - Recent issues with Invoice Ninja

  • v5.3.9 had issues in the upgrade breaking Invoice Ninja
  • v5.3.15 issue after upgrade with the Invoice Ninja application connecting to the local database; to overcome the issue, run the following command on the server Invoice Ninja is installed on.

sudo -u www-data php artisan migrate --force

Related error message is: 500: SQLSTATE[42S02]: Base table or view not found: 1146 Table ‘invoiceninja.recurring_expenses’ doesn’t exist (SQL: select * from recurring_expenses where recurring_expenses.company_id = 1 and recurring_expenses.company_id is not null)
Selection_309

NOTE: the command needs to be run from the directory where Invoice Ninja is installed at. My environment, Invoice Ninja is installed at //var/www/html/invoiceninja

  • I get there by using cd /var/www/html/invoiceninja
  • Then running the command to correct the issue sudo -u www-data php artisan migrate --force

OTHER NOTE: Seems there may be a minor issue with the displayed version from the web dashboard, it should read v5.3.15 but read reads v5.3.16

Selection_312

This is an amazing write up! I have never gotten Invoice Ninja to run before this tutorial. However, doing this in March of 2022 I am having some issues. I will admit that I used the latest version of Debian so that might be my problem. Using version 11 the following packages don’t work: libappindicator3-1, libindicator3-7, and libappindicator1. I also am having issues running composer in the /var/www/html/invoiceninja directory.

I tried this on Debian 10 and ran into less problems but the red triangle never goes away. It just says the cron needs to be enabled even though the cron job is running.

Thanks for the kind words.

Encountered the same thing when we did a first pass, “rapid build” when Debian 11 was released. We were able to work through a lot of the changes but, there were some dependencies and other limitations that kept us from completing a working instance. Have a tentative task to review this build on Debian 11 this summer, if resources allow.

The Invoice Ninja devs did state in a recent update for v5 there was an update for composer, around the time v.5.3.75 was released. We successfully updated our production systems and a few client systems without issues.

Agreed, getting the CRON job to run is important as this does some important housekeeping tasks. Troubleshooting the CRON and queue here at https://invoiceninja.github.io/docs/self-host-troubleshooting/#cron-not-running-queue-not-running

Also, I highly recommend enabling the queue system to greatly improve overall performance. This can be done if you have root access to your instance of Invoice Ninja.

This is NOT recommended for shared instances on hosted VPS servers or similar setups. Also NOT recommended for setups hosting more than one web based service as it can create issues for other Laravel based applications sharing the same system.

More on enabling this enhancement here at https://laravel.com/docs/8.x/queues#supervisor-configuration

Don’t forget to edit the .env on the Invoice Ninja instance to enable the change, followed by the php artisan optimize command (Source for enabling this setting here at https://invoiceninja.github.io/docs/self-host-installation/)

QUEUE_CONNECTION=database