HTTPS with a Self-Signed Certificate on Nginx in Linux

CompTIABeginner
Practice Now

Introduction

In this lab, you will learn how to secure an Nginx web server on Linux by implementing HTTPS with a self-signed certificate. You will begin by installing the Nginx web server and ensuring it is running correctly, establishing the foundation for the secure configuration. Following the initial setup, you will use the OpenSSL toolkit to generate a self-signed SSL certificate, a critical component for enabling encrypted communications.

Once the certificate is created, you will proceed to modify the Nginx configuration to serve web content over the secure HTTPS protocol. The final steps of the lab focus on verification and testing. You will activate the new configuration and use command-line tools like curl and openssl to test the HTTPS connection and inspect the details of your newly created self-signed certificate, confirming that your server is properly secured.

Install and Start the Nginx Web Server

In this step, you will install the Nginx web server. Nginx is a high-performance web server that is widely used for serving web content. We will first install it and then verify that it is running correctly. This running Nginx instance will serve as the foundation for our subsequent HTTPS configuration.

First, it's a best practice to update your system's package list to ensure you are getting the latest versions of software.

Execute the following command in your terminal:

sudo apt update

You will see the system fetching package information from its configured sources. The output will look similar to this:

Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Get:2 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [119 kB]
...
Fetched 1,585 kB in 2s (924 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.

Now, you can proceed to install Nginx. We will use the apt install command. The -y flag is added to automatically confirm the installation, avoiding any interactive prompts.

sudo apt install nginx -y

The installation process will download and set up Nginx and its dependencies. Upon completion, you should see output indicating that the nginx package has been set up.

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  nginx-common nginx-core
...
Setting up nginx-common (1.18.0-6ubuntu14.4) ...
Setting up nginx-core (1.18.0-6ubuntu14.4) ...
Setting up nginx (1.18.0-6ubuntu14.4) ...
Processing triggers for ufw (0.36.1-4ubuntu0.1) ...
Processing triggers for man-db (2.10.2-1) ...

Although the installation process often starts the service, it's good practice to manage it explicitly. We will use systemctl, the standard utility for controlling services on modern Linux systems.

Start the Nginx service with this command:

sudo systemctl start nginx

This command will not produce any output if it executes successfully. To confirm that the service is running, check its status.

sudo systemctl status nginx

The output will provide detailed information about the service. Look for the Active: active (running) line, which confirms that Nginx is up and running.

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2023-10-30 08:30:00 UTC; 5s ago
       Docs: man:nginx(8)
   Main PID: 1234 (nginx)
      Tasks: 2 (limit: 4617)
     Memory: 4.8M
        CPU: 43ms
     CGroup: /system.slice/nginx.service
             ├─1234 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             └─1235 "nginx: worker process"

You have now successfully installed and started the Nginx web server. In the next step, you will generate a digital certificate, which is a prerequisite for enabling HTTPS.

Generate a Self-Signed SSL Certificate with OpenSSL

In this step, you will create a self-signed digital certificate and its corresponding private key. To enable HTTPS, a web server needs a digital certificate to prove its identity to clients and a private key to establish a secure, encrypted connection. We will use the openssl command-line tool, a robust utility for working with SSL/TLS.

A digital certificate binds a public key to an identity (like a website's domain name). Normally, certificates are issued and signed by a trusted Certificate Authority (CA). However, for testing and development purposes, we can create a self-signed certificate, which is signed by its own creator. While browsers will show a security warning for such certificates, they are perfectly functional for a lab environment like this.

First, let's create a dedicated directory within the Nginx configuration folder to store our SSL certificate and key. This keeps our files organized and secure.

sudo mkdir -p /etc/nginx/ssl

Now, we'll use a single openssl command to generate both the 2048-bit RSA private key and the self-signed certificate, valid for 365 days. We will place them directly into the /etc/nginx/ssl/ directory.

Here's a breakdown of the command options:

  • req -x509: Creates a self-signed certificate.
  • -nodes: Prevents the private key from being encrypted with a passphrase. This is important so Nginx can start without manual intervention.
  • -days 365: Sets the certificate's validity period to one year.
  • -newkey rsa:2048: Generates a new 2048-bit RSA private key.
  • -keyout: Specifies the output file for the private key (/etc/nginx/ssl/nginx.key).
  • -out: Specifies the output file for the certificate (/etc/nginx/ssl/nginx.crt).
  • -subj: Provides the certificate's subject information non-interactively. CN=localhost is the Common Name, which must match the address you use to access the site.

Run the following command:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/nginx.key \
  -out /etc/nginx/ssl/nginx.crt \
  -subj "/C=US/ST=State/L=City/O=LabOrg/OU=IT/CN=localhost"

After running the command, you will see output confirming the key generation.

Generating a RSA private key
writing new private key to '/etc/nginx/ssl/nginx.key'
-----

The private key (/etc/nginx/ssl/nginx.key) is extremely sensitive. If it is compromised, an attacker could impersonate your server. Therefore, it's critical to restrict its file permissions so that only the root user can read it.

sudo chmod 600 /etc/nginx/ssl/nginx.key

This command sets the permissions to read and write for the owner (root) only, and no permissions for anyone else. This is a crucial security measure.

Excellent! You have now created a self-signed certificate (nginx.crt) and a secure private key (nginx.key). In the next step, you will configure Nginx to use these two files to enable HTTPS.

Configure Nginx to Serve Content over HTTPS

In this step, you will modify the Nginx configuration to enable HTTPS. With the certificate and private key ready from the previous step, you now need to instruct Nginx to use them. This involves editing Nginx's site configuration file to listen on port 443 (the standard port for HTTPS) and specifying the paths to your certificate and key files.

Before editing any configuration file, it's a wise practice to create a backup. This allows you to easily revert to the original state if something goes wrong. Let's back up the default Nginx site configuration file.

sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak

Now, you will edit the main configuration file using the nano text editor. This file contains server blocks that define how Nginx handles incoming requests.

sudo nano /etc/nginx/sites-available/default

Inside the nano editor, you will see a default server block configured for HTTP on port 80. Scroll down until you find the section for SSL configuration, which is usually commented out. You need to uncomment this section and ensure it matches the configuration below. This block tells Nginx to listen for secure connections on port 443 and specifies which certificate and key to use for the TLS handshake.

Delete the existing commented-out SSL server block and replace it with the following content, or simply uncomment and edit it to match.

## --- CONTENT TO ADD/UNCOMMENT IN /etc/nginx/sites-available/default ---
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    server_name localhost;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;

    location / {
        try_files $uri $uri/ =404;
    }
}
## --- END CONTENT ---

Here's what these directives mean:

  • listen 443 ssl: Tells Nginx to listen for incoming connections on port 443 and to handle them using the SSL/TLS protocol.
  • server_name localhost: Defines which server block to use for requests to localhost.
  • ssl_certificate: Specifies the path to your public certificate file (nginx.crt).
  • ssl_certificate_key: Specifies the path to your private key file (nginx.key).

After adding the content, save the file and exit nano by pressing Ctrl+X, followed by Y, and then Enter.

Before applying the changes, it is crucial to test the Nginx configuration for any syntax errors. This prevents a broken configuration from taking down your web server.

sudo nginx -t

If the configuration is correct, you will see a success message.

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If you see any errors, reopen the configuration file and carefully check for typos or missing semicolons.

You have now successfully configured Nginx to serve content over HTTPS. The next step is to apply these changes by restarting the service and testing the connection.

Activate and Test the HTTPS Configuration with curl

In this step, you will apply the new Nginx configuration and confirm that your web server is correctly serving content over HTTPS. Although you have modified the configuration file on disk, the running Nginx process is still using the old configuration. You must restart the service for the changes to take effect.

To apply the new configuration, restart the Nginx service using systemctl.

sudo systemctl restart nginx

This command doesn't produce any output if it succeeds. Nginx will now be listening on port 443 and be ready to handle HTTPS requests using the certificate and key you provided.

Now, let's test the HTTPS endpoint. We will use curl, a command-line tool for transferring data with URLs. We'll try to fetch the homepage from our server using the https:// protocol.

When you connect to a server using HTTPS, your client (in this case, curl) checks if the server's certificate is signed by a trusted Certificate Authority (CA). Since we created a self-signed certificate, it is not trusted by default, and curl will refuse to connect, showing a certificate validation error.

To work around this for our test, we use the -k or --insecure flag. This flag tells curl to skip the certificate validation. This is insecure and should not be used in production, but it is necessary for testing a self-signed certificate in a lab environment.

Run the following command to test your HTTPS server:

curl -k https://localhost

If your configuration is correct, curl will successfully connect to the server and print the HTML content of the default Nginx welcome page.

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</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>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Receiving this HTML output confirms that your Nginx server is successfully configured and serving content over an encrypted HTTPS connection. In the final step, you will learn how to inspect the certificate that the server is presenting.

Inspect the Server's SSL Certificate with OpenSSL

In this final step, you will examine the details of the digital certificate that your Nginx server is presenting to clients. This is a crucial skill for troubleshooting TLS/HTTPS issues and verifying a server's identity. You will use the openssl tool again, but this time as a client to connect to your own server and inspect the certificate it provides.

We will use a combination of two openssl commands connected by a pipe (|).

  • openssl s_client -connect localhost:443: This command acts as a generic SSL/TLS client and connects to the specified server and port. It will output the server's certificate along with session details.
  • openssl x509 -text -noout: This command is used to parse and display the contents of an X.509 certificate in a human-readable format.

We will pipe the output of s_client directly into x509 to parse the certificate on the fly. The echo | at the beginning prevents s_client from waiting for user input, and 2>/dev/null hides connection status messages. We'll save the output to a file for clarity.

Execute the following command to connect to your server, extract the certificate, parse it, and save the details to a file named /tmp/server_certificate_details.txt.

echo | openssl s_client -connect localhost:443 2> /dev/null | openssl x509 -text -noout > /tmp/server_certificate_details.txt

Now, display the contents of the file you just created to see the certificate details.

cat /tmp/server_certificate_details.txt

You will see a detailed breakdown of the certificate's properties.

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, ST = State, L = City, O = LabOrg, OU = IT, CN = localhost
        Validity
            Not Before: Oct 30 09:00:00 2023 GMT
            Not After : Oct 29 09:00:00 2024 GMT
        Subject: C = US, ST = State, L = City, O = LabOrg, OU = IT, CN = localhost
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
                    ...
                Exponent: 65537 (0x10001)
...

Take a moment to examine the output. Notice these key fields:

  • Issuer: The entity that signed the certificate.
  • Subject: The entity the certificate was issued to.
  • CN (Common Name): The specific domain the certificate is for (localhost).

Because this is a self-signed certificate, the Issuer and Subject fields are identical. This is the defining characteristic of a self-signed certificate. You can also see the validity period and the public key details.

Congratulations! You have successfully set up an Nginx web server with a self-signed SSL certificate, configured it for HTTPS, tested the connection, and inspected the certificate details. You now have a foundational understanding of the components involved in securing web traffic with TLS/HTTPS.

Summary

In this lab, you learned the end-to-end process of implementing HTTPS on an Nginx web server in a Linux environment using a self-signed certificate. You started by setting up the foundation, which involved updating the system's package list and installing the Nginx web server using the apt package manager. The core of the lab focused on security, where you used the OpenSSL toolkit to generate a private key and a corresponding self-signed SSL certificate, which are the essential components for enabling encrypted connections.

With the certificate created, you proceeded to configure the Nginx server. This involved modifying its configuration files to create a server block that listens on port 443 for HTTPS traffic and pointing it to the paths of your new certificate and private key. To finalize the process, you activated the new configuration and performed crucial verification steps. You used the curl command to test the HTTPS connection from the command line and confirmed that the server was responding securely. Finally, you used OpenSSL as a client tool to inspect the server's certificate, validating that the correct certificate was being served.