Run InvoiceNinja 5 Docker installation with a SSL/TLS certificate

In this post you will learn how to secure your InvoiceNinja 5 docker installation with a SSL/TLS certificate. This will securely encrypt the communication between the client and the server part of InvoiceNinja 5 and is hence a key part if you're running this on a public URL.

In my previous post I have explained how you can run InvoiceNinja 5 in a Docker image using docker compose.

To simplify this post, I will be using self-sigend certificates. You can obtain certificates also for a trusted authority like Let's encrypt. You can check out my post how to set up a NGINX with Let's encrypt here.

Create the SSL/TLS certificates

The first step is to create the certificates. This can be done with openssl and the following command.

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt

This will create a public (/etc/ssl/certs/nginx-selfsigned.crt) and a private key (/etc/ssl/private/nginx-selfsigned.key) in the directoy /etc/ssl and with a validity of 365 days. The private key will be without a password (-nodes).

Preparing the NGINX

The docker image of InvoiceNinja 5 comes with a NGINX as web server hosting the content. The configs for the web server are stored in ./docker/nginx/*. The standard configuration is the in-vhost.conf. Next you create a copy of tthe config and rewrite it to server port 443 for SSL/TLS.

cd /docker/nginx/
sudo cp in-vhost.conf in-vhost-ssl.conf
sudo vim in-vhost-ssl.conf

Change the content of the file to the following:

server {
    #port 443 to enable standard ssl
    listen 443 ssl;
    server_name localhost;
    #Adding the certificates
    ssl_certificate /etc/nginx/certs/nginx-selfsigned.crt;
    ssl_certificate_key /etc/nginx/certs/private/nginx-selfsigned.key;

    client_max_body_size 100M;

    root /var/www/app/public/;
    index index.php;

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

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

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        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;
    }

}

If you want to server both, 443 and 80 you can keep the inital port 80 config in the file, redirect all port 80 traffic to 443 or use a reverse proxy on 443 to redirect the traffic to port 80.

That's it for the NGINX config.

Config docker-compose for InvoiceNinja 5 to server SSL/TLS

As next step you will need to tell the docker image where the certificates are and open port 443. You need to edit the docker-compose.yml file and change it as follows:

version: '3.7'

services:
  server:
    image: nginx
    restart: always
    env_file: env
    volumes:
      # Vhost configuration
      - ./config/nginx/in-vhost-ssl.conf:/etc/nginx/conf.d/default.conf:ro
      - ./docker/app/public:/var/www/app/public:ro
      - /etc/ssl/certs:/etc/ssla #add certificates volume
    depends_on:
      - app
    # Run webserver nginx on port 80
    # Feel free to modify depending what port is already occupied
    ports:
      - "81:80"
      - "443:443" #uncomment this line to server port 443
    networks:
      - invoiceninja
    extra_hosts:
      - "in5.test:192.168.xx.xx " #host and ip

  app:
    image: invoiceninja/invoiceninja:5
    env_file: env
    restart: always
    volumes:
      - ./config/hosts:/etc/hosts:ro
      - ./docker/app/public:/var/www/app/public:rw,delegated
      - ./docker/app/storage:/var/www/app/storage:rw,delegated
    depends_on:
      - db
    networks:
      - invoiceninja
    extra_hosts:
            - "in5.test:192.168.xx.xx " #host and ip

  db:
    image: mysql:5
    ports:
      - "3305:3306"
    restart: always
    env_file: env
    volumes:
      - ./docker/mysql/data:/var/lib/mysql:rw,delegated
      
    networks:
      - invoiceninja
    extra_hosts:
            - "in5.test:192.168.xx.xx " #host and ip

networks:
  invoiceninja:

Now rebuild the docker and you can checkt InoiceNinja 5 out using SSL/TLS. E.g. with https://<your-ip>