# Create a Self-Signed Certificate for Nginx in 5 Minutes

## How to Create a Self-Signed SSL/TLS Certificate for Nginx in 5 Minutes

Published by Parmod Upadhyay on Feb 26, 2025

**How to Create a Self-Signed SSL/TLS Certificate for Nginx**

In this tutorial, I'm going to show you how you can create a self-signed SSL/TLS certificate and use it on Nginx in 5 minutes or less. I'm using Ubuntu for this tutorial, but if you're on Mac OSX you can follow along as the syntax and commands are nearly identical.

### **Why Create a Self-Signed Certificate?**

Self-signed certificates are useful for local development where you want to simulate an HTTPS environment. Take note that self-signed certificates are not meant for production, but they are ideal for [localhost](http://localhost) development.

### **An Overview of Creating a Self-Signed Certificate**

Before continuing, let's take a step back and look at the steps involved in generating a self-signed certificate for Nginx:

1. Generate a self-signed certificate using OpenSSL
    
2. Copy the certificate to the certificates folder on Ubuntu
    
3. Update the Nginx configuration file to load the certificate
    
4. Copy the certificate's public key to the CA trusted root database to prevent Google Chrome from showing the site as insecure
    

### **Step 1: Generate a Self-Signed Certificate using OpenSSL**

I'll use OpenSSL to generate the certificate on Ubuntu. OpenSSL is installed on Mac OSX by default and the commands are exactly the same.

OpenSSL will generate 2 files which consist of a private key and a public key. Even though most people refer to an SSL/TLS certificate in the singular sense, it is the combination of the private key and the public key that makes a certificate.

Before running the OpenSSL command to generate a self-signed certificate, I'm going to create a certificate configuration file that will specify the certificate bits and the Subject Alternative Names. The Subject Alt Names are required in Google Chrome 58 and later, and is used to match the domain name and the certificate. If the domain name is not listed in the certificate's Subject Alternative Names list, you'll get a `NET::ERR_CERT_COMMON_NAME_INVALID` error message.

```bash
sudo nano localhost.conf
```

```plaintext
[req]
default_bits       = 2048
default_keyfile    = localhost.key
distinguished_name = req_distinguished_name
req_extensions     = req_ext
x509_extensions    = v3_ca

[req_distinguished_name]
countryName                 = Country Name (2 letter code)
countryName_default         = US
stateOrProvinceName         = State or Province Name (full name)
stateOrProvinceName_default = New York
localityName                = Locality Name (eg, city)
localityName_default        = Rochester
organizationName            = Organization Name (eg, company)
organizationName_default    = localhost
organizationalUnitName      = organizationalunit
organizationalUnitName_default = Development
commonName                  = Common Name (e.g. server FQDN or YOUR name)
commonName_default          = localhost
commonName_max              = 64

[req_ext]
subjectAltName = @alt_names

[v3_ca]
subjectAltName = @alt_names

[alt_names]
DNS.1   = localhost
DNS.2   = 127.0.0.1
```

```bash
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -config localhost.conf
```

### **Step 2: Copy the Certificate Key Pair to the Certificates folder on Ubuntu**

Copy the public key to the `/etc/ssl/certs` directory

```bash
sudo cp localhost.crt /etc/ssl/certs/localhost.crt
```

Copy the private key to the `/etc/ssl/private` directory

```bash
sudo cp localhost.key /etc/ssl/private/localhost.key
```

### **Step 3: Update the Nginx Configuration File to Load the Certificate Key Pair**

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

```plaintext
server {
        listen 80;
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name localhost;

        ssl_certificate /etc/ssl/certs/localhost.crt;
        ssl_certificate_key /etc/ssl/private/localhost.key;
        
        ssl_protocols TLSv1.2 TLSv1.1 TLSv1;

        root /var/www/html;

        index index.html index.nginx-debian.html;
}
```

Reload the Nginx configuration changes

```bash
sudo service nginx reload
```

### **Open up the Google Chrome to Verify that Nginx Loads the Site Over HTTP and HTTPS**

Since I haven't added the self-signed certificate to Chrome's CA Root store, Chrome shows the site as insecure.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1740563260888/1e304448-2d00-46f7-b0e6-742e9f0c2ffa.webp align="center")

Click proceed to [Localhost](http://Localhost) to verify that Nginx is correctly configured

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1740563315200/a675ae54-77dd-4cb2-a8ff-693d0862bada.webp align="center")

### **Step 4: Configure Chrome to Trust the Certificate and to Show the Site as Secure**Add the certificate to the trusted CA root store

```bash
certutil -d sql:$HOME/.pki/nssdb -A -t "P,," -n "localhost" -i localhost.crt
```

Close all the Google Chrome windows and reopen. Chrome is now showing the site as secure.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1740563379823/73e77bd1-931a-4ab4-b7c7-37f3dcdb8c81.webp align="center")
