DEV Community

Nico Braun
Nico Braun

Posted on • Updated on

Creating and Serving Self Signed Certificates with OpenSSL and Nignx

Open SSL

In order to create a safe certificate that satisfies the standards of all modern browsers, we have to make use of SSL version 3 keys.
If you run OpenSSL and use the default questions to fill out the cert, these keys are missing, and modern browsers will not accept the cert as safe, even when adding it to the trusted root authorities.

It is technically possible to provide all required extension keys with the -addext flag, when executing the openssl command

... -addext "subjectAltName=IP:my.public.ip.address" ...
Enter fullscreen mode Exit fullscreen mode

For this post, I will use a small config file and pass it to o the openssl command with the -config flag.

Providing a Config File

The main point of providing this config file is, to add the SAN key to our certificate, but all keys from the v3_req field are important.
SAN stands for Subject Alternative Names.

Enter the /tmp directory and create a file named ssl.conf

cd /tmp/
vi ssl.conf
Enter fullscreen mode Exit fullscreen mode

Add these lines to the file save with :wq

[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = UK
ST = NI
L = Belfast
O = KiwiCode
OU = Ministry of Fruit
CN = my.public.ip.address
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
IP.1 = my.public.ip.address
Enter fullscreen mode Exit fullscreen mode

Note, that I will use my public IP address for this post. If you have a domain name you can list it in the alt names with DNS.1 = your.domain.name.

Generating a Certificate and Private key

We are going to create the certificate and the key and place it in /etc/nginx/ssl

sudo mkdir /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048  -config ./ssl.conf   \
-keyout /etc/nginx/ssl/selfsigned.key -out /etc/nginx/ssl/selfsigned.crt
Enter fullscreen mode Exit fullscreen mode

We are using the widely accepted international X.509 public key infrastructure (PKI) standard to verify that a public key belongs to the user, computer or service identity contained within the certificate.

-nodes stands for "no DES". It means OpenSSL will not encrypt the private key in a PKCS#12 file.

RSA is the method of creating the key pairs, and we are using 2048-bit as size wich is not the highest value we can achieve but it is considered
an optimal key size for an RSA Private Key, since it provides a decent level of security and does not load the server’s CPU much.

Diffie-Hellman - Perfect Forward Secrecy

We should also create a strong Diffie-Hellman group, which is used in negotiating Perfect Forward Secrecy with clients.

sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096
Enter fullscreen mode Exit fullscreen mode

Diffie-Hellman is a mathematical algorithm to exchange a shared secret between two parties. This shared secret can be used to encrypt messages between these two parties. Note that the Diffie-Hellman algorithm does not provide authentication between these two parties.

Nginx

Creating SSL Config snippets

First, we create a reusable SSL parameter snippet that we will include in our main nginx.conf.

sudo mkdir /etc/nginx/snippets
sudo vi /etc/nginx/snippets/ssl-params.conf
Enter fullscreen mode Exit fullscreen mode

Add these lines and save with :wg

ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1;
ssl_session_timeout  10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
Enter fullscreen mode Exit fullscreen mode

Nginx will output a warning and disable stapling, since we are using a self-signed cert. But it will continue to operate correctly.

Modifying nginx.conf

sudo vi /etc/nginx/nginx.conf
Enter fullscreen mode Exit fullscreen mode

TLS support

Next we want to enable TLS support and include our parameter snippet in the /etc/nginx/nginx.conf. We can simply un-comment the whole TLS block and
add our three lines.

# Settings for a TLS enabled server.
    server {
        listen          443 ssl http2 default_server;
        listen          [::]:443 ssl http2 default_server;
        server_name     your.public.ip.address;
        root            /usr/share/nginx/html;

        # Add these three lines in the TLS block
        ssl_certificate /etc/nginx/ssl/selfsigned.crt;
        ssl_certificate_key /etc/nginx/ssl/selfsigned.key;
        include snippets/ssl-params.conf;

        include /etc/nginx/default.d/*.conf;

        location / {
        }
        ...
    }
Enter fullscreen mode Exit fullscreen mode

Redirect HTTP to HTTPS

We modify the regular server block above the TLS section and remove most things. We add our IP address as server name and return with
the redirect to HTTPS on the same request URL.

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  your.public.ip.address;

        return 302 https://$server_name$request_uri;
 }

Enter fullscreen mode Exit fullscreen mode

Note that we redirect with 302 and not 301. This is because we don't want to redirect permanently for now.

Discussion (0)