Creating Self-Signed SSL Certificates For Docker and Nginx

How to create and install self signed SSL certificates on nginx docker images

I was recently asked to run local docker sites on https using self signed ssl certs. I am pretty new to this and just learnt this myself. So I thought I would share it with you all.

The set up

Assuming I start with dir following directory structure

- ssl-docker-nginx/
   - nginx
     - logs/
       - my-site.com.access.log
     - nginx.conf
   - site/
     - index.html
   - docker-compose.yml

site/index.html looks like…

<html>
    <head>
        <title>My Site</title>
    </head>
    <body>
        <h1>My Site</h1>
    </body>
</html>

Nginx/nginx.conf looks like…

events {
  worker_connections  4096;  ## Default: 1024
}

http {
    server {
        listen 80;
        server_name my-site.com;
        root         /usr/share/nginx/html/;
    }
}

docker-compose.yml looks like…

version: '2'
services:
  server:
    image: nginx:1.15
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./site:/usr/share/nginx/html
    ports:
    - "8080:80"

I have the domain my-site.com in my /etc/hosts file looking like

0.0.0.0 my-site.com

Upon running …

docker-compose up -d

I should receive a webpage looking like the below when I hit http://my-site.com:8080/ in my browser

Screenshot of site on http

Now lets get to work

Lets get to work, we are going to do the following;

  1. Create a self signed SSL certificate
  2. Mount the self signed certificate and key into the docker image
  3. Configure nginx to serve my-site.com over https using the self signed certificate
  4. Party

Creating a self signed SSL certificate

To do this we will use the openssl program to generate a key/cert pair

openssl req -newkey rsa:2048 -nodes -keyout nginx/my-site.com.key -x509 -days 365 -out nginx/my-site.com.crt

You will have to fill in the following questions;

  1. Country Name (2 letter code)
  2. State or Province Name (full name)
  3. Locality Name (eg, city)
  4. Organization Name (eg, company)
  5. Organizational Unit Name (eg, section)
  6. Common Name (eg, fully qualified host name)
  7. Email Address

Once that is done you will have two new files in your nginx dir

- nginx/
  - my-site.com.crt
  - my-site.com.key

Mounting our new key/pair into our container

This will be accomplished via adding two additional volumes to docker-compose.yml

version: '2'
services:
  server:
    image: nginx:1.15
    volumes:
      - ./site:/usr/share/nginx/html
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/my-site.com.crt:/etc/nginx/my-site.com.crt # New Line!
      - ./nginx/my-site.com.key:/etc/nginx/my-site.com.key # New Line!
    ports:
    - "8080:80"

Opening port 443 on our nginx container

A simple change to our docker-compose.yml

version: '2'
services:
  server:
    image: nginx:1.15
    volumes:
      - ./site:/usr/share/nginx/html
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/my-site.com.crt:/etc/nginx/my-site.com.crt
      - ./nginx/my-site.com.key:/etc/nginx/my-site.com.key
    ports:
    - "8080:80"
    - "443:443" # Docker open external port 443 and redirect all traffic to internal port 443

Configure Nginx to serve my-site.com over https using the self signed certificate

Next we are going to configure nginx.conf to listen and server requests on port 443 using our new key/cert pair. This will require an update to the nginx/nginx.conf file.

events {
  worker_connections  4096;  ## Default: 1024
}

http {
    server {
        listen 80;
        server_name my-site.com;
        root         /usr/share/nginx/html;
    }

    server { # This new server will watch for traffic on 443
        listen              443 ssl;
        server_name         my-site.com;
        ssl_certificate     /etc/nginx/my-site.com.crt;
        ssl_certificate_key /etc/nginx/my-site.com.key;
        root        /usr/share/nginx/html;
    }
}

Run docker-compose down && docker-compose up -d and visithttps://my-site.com to see the results, you will get a not secure certificate warning, tell your browser to accept and you should get something like

Screenshot of site on https

Getting your browser to trust your self signed certificate

This varies on your OS and browser, I would google for something like getting <browser-name> to accept self signed certificates on <your-os-here>

The complete codebase can be found here