Certificates & Reverse Proxy

Run the init.sh script, to generate the required .env file based on the user input for the primary domain. The init.sh script will also create the docker-compose.yml file in the local directory and write the nginx configuration to /srv/docker/nginx/nginx.conf. The script will prompt the user, whether certificates should be obtained using certbot or if self-signed certificates are to be used. Depending on the response, the certbot container will be commented out from the created docker-compose.yml file.

If creating the .env file manually, it should contain the following variables:

NGINX_DOMAIN_LIST="example.org app.example.org grafana.example.org eln.example.org auth.example.org api.example.org teleport.example.org"
NGINX_PRIMARY_DOMAIN=example.org
NGINX_PROXY_PASS="http://example.org"
LETSENCRYPT_EMAIL=""
LETSENCRYPT_STAGING="0"
APP_PUBLIC_DOMAIN="app.example.org"
ELN_PUBLIC_DOMAIN="eln.example.org"
AUTH_PUBLIC_DOMAIN="auth.example.org"
GRAFANA_PUBLIC_DOMAIN="grafana.example.org"
API_PUBLIC_DOMAIN="api.example.org"
TELEPORT_PUBLIC_DOMAIN="teleport.example.org"

Warning

The LETSENCRYPT_STAGING setting only works for valid URLs (so example.org will not work). For local deployment using self-signed certificates this can remain at it’s recommended value of “0”. When moving to production and testing there, consider changing this to “1” to avoid the imposed rate limits.

Certbot

If certbot based certificates are to be obtained, the init.sh will automatically call the certbot.sh script, which in turn starts up both the certbot and nginx docker containers. The certificates are stored in /srv/docker/certbot/conf/live/${NGINX_PRIMARY_DOMAIN} (which are actually just soft links).

Warning

If running on arm-server make sure to select the correct docker image for certbot (image: certbot/certbot:arm64v8-latest), this should already be considered by the init script but if you’re seeing some “exec format” issues this is likely the cause.

Self-signed

This approach aims to reproduce the certbot directory and file structure so transitioning from testing to production setup is streamlined.

Similar to the certbot based setup, the init.sh will generate the .env file. However, the certbot.sh script is not called and the nginx container needs to be manually started after performing all steps below to generate a custom CA, adding it to clients

Creation of private key and root certificate

Make a folder to hold the certificates and make sure this folder, its subdirectories, and the files contained in it are in your gitignore file to exclude them from going public. However, you should backup the certificate files.

$ mdkir certs
$ cd certs

Generate a private key and set a passphrase during the procedure:

$ openssl genrsa -des3 -out exampleCA.key 2048

Now generate the root certificate:

$ openssl req -x509 -new -nodes -key exampleCA.key -sha256 -days 1825 -out exampleCA.pem

Adding the Root Certificate to Linux (all clients)

If it is not already installed, install the ca-certificates package with

$ sudo apt-get install -y ca-certificates

Copy the exampleCA.pem file to the /usr/local/share/ca-certificates directory as a exampleCA.crt file.

$ sudo cp ./exampleCA.pem /usr/local/share/ca-certificates/exampleCA.crt

Finally, update the certificate store.

$ sudo update-ca-certificates

You can test that the certificate has been installed by running the following command:

$ awk -v cmd='openssl x509 -noout -subject' '/BEGIN/{close(cmd)};{print | cmd}' < /etc/ssl/certs/ca-certificates.crt | grep

and appending one of the information provided during the root certificate creation process as grep input.

Creating CA-Signed Certificates for Your Dev Sites

Now we are a CA on all our devices and we can sign certificates for any new dev sites that need HTTPS. First, we create a private key for the dev site.

$ openssl genrsa -out privkey.pem 2048

Then we create a CSR:

$ openssl req -new -key privkey.pem -out example.org.csr

Now create a config file for each url to define the subject alternative name (SAN)

$ nano example.org.ext

with the following content

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = app.example.org
DNS.2 = api.example.org
DNS.3 = auth.example.org
DNS.4 = eln.example.org
DNS.5 = grafana.example.org
DNS.6 = teleport.example.org

Then run

$ openssl x509 -req -in example.org.csr -CA exampleCA.pem -CAkey exampleCA.key \
-CAcreateserial -out cert.pem -days 825 -sha256 -extfile example.org.ext

Complete certbot like folder and file system

$ cat cert.pem exampleCA.pem > fullchain.pem
$ sudo mkdir -p /srv/docker/certbot/conf/live/example.org/
$ sudo cp cert.pem fullchain.pem privkey.pem /srv/docker/certbot/conf/live/example.org/
$ openssl dhparam -out ssl-dhparams.pem 2048
$ sudo cp ssl-dhparams.pem /srv/docker/certbot/conf/

Remaining settings

DNS

Resolving the domain names for all services can either be done by adding them to the nameserver. Alternatively, all domain lookups can be added to a machine’s host file. Locate the host file and add the following lines (replace 127.0.0.1 with the host running the services):

127.0.0.1           example.org
127.0.0.1           app.example.org
127.0.0.1           api.example.org
127.0.0.1           auth.example.org
127.0.0.1           grafana.example.org
127.0.0.1           teleport.example.org
127.0.0.1           eln.example.org

Windows path: c:\Windows\System32\Drivers\etc\hosts

Linux path: /etc/hosts

Firefox settings

  1. Start Firefox

  2. Go to Settings > Privacy & Security

  3. Under Certificates, click “View Certificates…”

  4. In the Certificate Manager, click the Authorities tab

  5. Click the Import button to import the created exampleCA.pem

You might be prompted to set the trust level upon importing the certificate. If not, you can do that manually via the ‘Edit Trust’ button.

Grafana

Todo

See Grafana for details on how to make sure Grafana is working with oauth2 when using self-signed certificates.