This is an example setup to run a self-hosted Invoice Ninja instance via Docker container. The idea is to run everything inside a container and to not expose any involved services to the public, except for the web interface via a reverse proxy supporting HTTPS.
As a bonus, the SQL database can be accessed directly via phpmyadmin. This shouldn't be necessary, but I have experienced situations where this became necessary. This interface is also not for public use.
** Caution: Services not intended for public use should NEVER be made available publicly. **
This multi-container setup requires a running server with a recent operating system supporting Docker. The containers involved are:
-
invoiceninja_web
: web-server to provide HTTP access to the Invoice Ninja application; it's interface will be made available onlocalhost
only and can be accessed through a reverse proxy providing HTTPS. It can be tweaked via its own config file. -
invoiceninja_app
: The application's backend container, provided by the Invoice Ninja application. It will store its files in a persistent storage and share the public files with the web-server container. No ports will be published. -
invoiceninja_db
: The official MySQL 8 Docker container running the database for the instance. It contains the data entered through the app's web interface. The data is stored in a persistent mount point. -
invoiceninja_dbadmin
: The official phpMyAdmin container running a web interface to the database. This container is completely optional. Its interface is not made public, but available vialocalhost.
We can access it through a temporary forward SSH tunnel.
The containers share the same network to be able to communicate with each other.
The full setup further requires a reverse-proxy configuration for Apache2 or Nginx, and a systemd system service to automatically start and restart the container union.
This software is required:
docker.io
|docker-ce
|docker
- optional:
docker-compose
(one can usedocker compose
command as well) apache2
|nginx-light
|nginx
The docker version shipped in most distributions might already be fine. It definitely is for Debian Bullseye, for example. There is not really a reason to get the docker CE packages.
If SysVinit is used instead of systemd, then the service file contains every necessary to write an init script based on it.
Although one can change the docker-compose.yml
file,
most configuration takes place in the .env
file. There is an example
configuration in the .env.example
file.
Let's go though each item:
INVOICE_NINJA_HOME
: This is used in thedocker-compose.yml
file to define the local path where the database and the application files should be stored outside the container in a persistent location. The variable in the systemd service file overwrites the variable defined here.
It is intended to not expose the port to access the phpMyAdmin service to the
public. To use it, we can create an SSH forward tunnel from our host to the
server running the container. A forward tunnel is basically a tunnel, that
starts on a local IP and port and forwards all packetsi from there to a remote
IP and port. So, if phpMyAdmin is available on the remote server on localhost
port 8000
, we can do:
ssh -N -L localhost:8000:localhost:8000 <remote server>
then we can access phpMyAdmin locally via http://localhost:8000/ as long as the tunnel exists, and we can view, change, and backup the remote database.
I: The interface shows only a few languages and currencies and misses most after the first login
Open http://your.domain.tld/update?secret=secret in the browser. Of course replace the placeholder here by the real domain.
Thanks to https://forum.invoiceninja.com/t/missing-languages-currencies/12026/3.
I: There is an update available
If we run the systemd service, we just restart the server:
sudo systemctl restart invoiceninja.service
If we run the containers manually, then we basically have to shut the containers down, pull the updates, and start them again:
docker-compose down
docker-compose pull --include-deps
docker-compose up (-d)