Development SSL for .NET Core and NGINX in Docker

padlock on door latch

Photo by James Sutton on Unsplash

We’ve all been there. You want to use SSL in development to mirror a production setup but it’s a pain to generate self-signed certificates, share them with the development team, and have them trusted locally.

Thankfully combining Docker and the dotnet dev-certs command makes this nice and easy for .NET Core Applications and NGINX - which I’m sharing here so I don’t forget :)

.NET Dev Certs Command

To make it easier for developers to generate and access development SSL certificates, the .NET Core provides the dotnet dev-certs command as part of the CLI experience.

This command allows you to generate, export, trust and clean up self-signed developer certificates for your applications.

The beauty of this command on Window is that it adds the certificate to the trusted store locally meaning that browsers will validate it as such.

By using this approach each developer can quickly generate their own certificates locally and mount them in Docker as part of a Docker Compose file.

.NET Core Application

.NET Core applications expect certificates in PFX format, so to generate a certificate in this format you can use the –format pfx option for the dotnet dev-certs command.

Below is an example of generating a certificate into a config folder:

dotnet dev-certs https -ep ./config/app-certificate.pfx -p BlahBlah --trust --format pfx

This command will then create a new certificate and trust it in the machines certificate store, before exporting it to the PFX file, with the private key protected by the password BlahBlah.

Having done this, we can then mount this certificate as a volume in Docker and set some environment variables to configure the .NET Core application to use this certificate:

app:
  build:
    context: app/.
    dockerfile: Dockerfile
  ports:
    - "50000:50000"
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - ASPNETCORE_URLS=https://+:50000
    - ASPNETCORE_Kestrel__Certificates__Default__Password=BlahBlah
    - ASPNETCORE_Kestrel__Certificates__Default__Path=/certs/app-certificate.pfx
  volumes:
    - ./config/app-certificate.pfx:/certs/app-certificate.pfx

Voila! We have our .NET Core application listening on Port 50000 secured using SSL.

NGINX Docker Image

In many cases your application will be running on HTTP with a reverse proxy in front of it, such as NGINX.

To use a similar approach with the NGINX docker image, you can use the –format pem option for the dotnet dev-certs command to generate a key pair (i.e. crt and key files) in the PEM format.

Below is an example of generating a certificate pair into a config folder:

dotnet dev-certs https -ep ./config/certificate.crt -np --trust --format pem

In this example, the -np flag has been used to export the private key in the PEM file without the need for a password to be provided to read it.

In this approach, the NGINX config file can be updated to used these keys in it’s appropriate server block:

listen              443 ssl;
server_name localhost;
ssl_certificate     /etc/nginx/proxy-certificate.crt;
ssl_certificate_key /etc/nginx/proxy-certificate.key;

If a password is desired, it can be provided in the export command:

dotnet dev-certs https -ep ./config/certificate.crt -p BlahBlah --trust --format pem

Doing this then requires you to pass a ssl_password_file to NGINX using the ssl_password_file directive. For example:

listen              443 ssl;
server_name localhost;
ssl_certificate     /etc/nginx/proxy-certificate.crt;
ssl_certificate_key /etc/nginx/proxy-certificate.key;
ssl_password_file /etc/nginx/proxy-certificate.pass;

This file is just a simple text file with the password for the key inside it, or a list of passphrases to be tried, if you wish to have one single password file for multiple certificates.

Just like in the .NET Core Application example, these key files can be mounted as volumes:

proxy:
    image: nginx
    ports:
     - "80:80"
     - "443:443"
    volumes:
      - ./config/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./config/proxy-certificate.crt:/etc/nginx/proxy-certificate.crt
      - ./config/proxy-certificate.key:/etc/nginx/proxy-certificate.key
    depends_on:
      - web-app
    links:
      - web-app

Refreshing Certificates

If you want to start from scratch with a set of certificates, you can run the following command:

dotnet dev-certs https --clean

This clears down the https certificates.