WittCode💻

Nginx HTTPS Servers

By

Learn to configure an nginx HTTPS server, add a SSL certificate to an nginx HTTP server, generate an SSL certificate with openssl, and what the nginx ssl_certificate and ssl_certificate_key directives are.

Table of Contents 📖

Redirecting HTTP to HTTPS

To change an HTTP server to an HTTPS server we need to add encryption and verification. This is done through the TLS/SSL protocol. To begin, lets redirect traffic from port 80 to port 443. HTTP typically runs on port 80 while HTTPS typically runs on port 443. We can redirect traffic with nginx using the return directive. Lets also rename the server name to localhost and remove any uneccessary information.

server {
    listen 80;
    listen [::]:80;

    server_name localhost;

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

Specifically, the return directive can be used to change part of the URL in a client request. The 301 status code means Moved Permanently and indicates that the requested resource has been moved to the URL we provide. This url is https://localhost<request_uri>. Note how the protocol is being moved from http to https. $request_uri is an nginx variable that represents the original URI in the request. The variable $server_name has the server_name of the virtual host that processed the request. Here, this is localhost. Now, lets reload nginx with the new configuration and make a curl to localhost:80. What we will get back is a 301 Moved Permanently response.

sudo systemctl reload nginx && curl localhost:80
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.18.0 (Ubuntu)</center>
</body>
</html>

Creating an SSL Certificate

Now lets generate an SSL certificate. An SSL certificate verifies that a website has an ecrypted connection. When a website uses SSL, there will be a SSL certificate associated with it. Before we generate an SSL certificate, lets create a directory to store it in.

sudo mkdir /etc/nginx/ssl

Now lest generate a self signed certificate. As a side note, self signed certificates should not be used in production as they are not validated by any certificate authority. We can generate a self signed certificate with the openssl req command.

sudo openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout /etc/nginx/ssl/localhost.key -out /etc/nginx/ssl/localhost.crt

The openssl req command is a certificate generating utility. The -x509 flag outputs a self signed certificate instead of a certificate request. The -nodes flag will make it so the private key is not protected. The -days flag specifies the number of days the certificate is valid before expiring. The -newKey flag creates a certificate request and private key, it is generating a RSA key 4096 bits in size. The -keyout flag accepts the filename to write the created private key to. Finally, the -out flag accepts a filename to write the output to. Here, this is the certificate.

Adding Private Key and Cert to Nginx

Now lets create an HTTPS server on port 443 and add the generated certificate and private key to it.

server {
    listen                443 ssl;
    listen                [::]:443 ssl;

    server_name           localhost;
    
    ssl_certificate       /etc/nginx/ssl/localhost.crt
    ssl_certificate_key   /etc/nginx/ssl/localhost.key
}

To create an HTTPS server, we have to include the ssl parameter to the listen directive and specify the location of the SSL certificate and private key. The ssl_certificate directive accepts a file with an SSL certificate in the PEM format. PEM stands for privacy-enhanced mail and is a file format for storing crytographic keys, certificates, etc. The ssl_certificate_key directive accepts a file with a private key in PEM format. We can also use the directives ssl_protocols and ssl_ciphers to limit connections to using specific versions of ciphers or SSL/TLS but for this video we are sticking with the default values that nginx provides.

Making a Request to HTTP and HTTPS Servers

Finally, reload nginx and curl to localhost:80. We have to tag on the -L flag to the curl command so that we follow the redirect.

sudo systemctl reload nginx && curl -L localhost:80
curl: (60) SSL certificate problem: self-signed certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

The response talks about the security issues with the self-signed certificate. However, if we want to ignore the potential security issues with a self signed certificate, we can tag on --insecure to curl.

curl -L --insecure localhost:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
</body>
</html>

So the redirect is working, now we just need to make the same request on port 443 with the https protocol.

curl https://localhost:443 --insecure
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
</body>
</html>
Nginx HTTPS Servers