How to Create Self-Signed SSL Certificate for Nginx on Ubuntu 18.04

SSL stands for "Secure Sockets Layer", which is the standard security technology meant for creating an encrypted link between a Web server and a Web browser. This link ensures that all information passed between the server and browser remains private and secure. The main purpose of the SSL certificates is to assure the website security and encrypt data transferred between the client and the browser to prevent any theft of sensitive information such as credit card details, account numbers, and passwords etc.

A self-signed certificate is a certificate that is signed by the person creating it rather than a trusted certificate authority (CA). Most of the clients and organizations are tempted to use self-signed SSL Certificates instead of those issued and verified by a trusted Certificate Authority mainly because of the cost difference. But it still offers the same level of encryption to a limit.

In this article, I'll explain how to create a Self-Signed SSL certificate on an Ubuntu 18.04 server with Nginx Web server.

Pre-requisites

A well-configured server with root privileges and OpenSSL library. The OpenSSL library is required to generate your own certificate. Run the following command in your ubuntu server to see if you already have OpenSSL installed.

# which openssl
/usr/bin/openssl

If the which command didn't return the binary, then we will need to install it using the command:

#apt install openssl

Creating the Self-Signed Certificate

SSL comprises of mainly two parts one is the private key and the other public certificate.  The SSL key is kept private on the server restricted to the root user. It is actually used to encrypt content sent to clients. The public SSL certificate is shared with anyone requesting the content. It can be used to decrypt the content signed by the associated private SSL key. Here, I'm using this command to generate a self-signed certificate namely example.com.crt and a private key example.com.key using the OpenSSL tool.

#openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/example.com.key -out /etc/ssl/certs/example.com.pem

Please see the details of each option below:

  • req: This subcommand is used for creating a new X.509 cert. The "X.509" is a public key infrastructure standard that SSL and TLS adhere to for its key and certificate management.
  • -x509: This further modifies the previous subcommand by telling the utility that we want to make a self-signed certificate.
  • -nodes: This is used to skip the passphrase option to secure our certificate.
  • -days 365: This option sets the validity for the certificate in days. We are setting it for a year here.
  • -newkey rsa:2048: This specifies that we want to generate a new RSA key with 2048 bits long along with the certificate.
  • -keyout: This option tells OpenSSL where to place the generated private key file.
  • -out: This option tells OpenSSL where to place the generated certificate.

During this command execution, it will prompt us to provide the domain/client details for generating a Certificate Signing Request (CSR). You can provide these details as required.

Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:Victoria
Locality Name (eg, city) []:Melbourne
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Linoxide LLC
Organizational Unit Name (eg, section) []:Web
Common Name (e.g. server FQDN or YOUR name) []:example.com
Email Address []:[email protected]

Now we have our newly generated self-signed certificate and private key is these locations namely: /etc/ssl/certs/example.com.pem and /etc/ssl/private/example.com.key. Next, we should create a strong Diffie-Hellman group, which is used in negotiating Perfect Forward Secrecy with clients. You can run this command to create one.

#openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

This might take some time to complete, but when it's done we will have a strong DH group at /etc/ssl/certs/dhparam.pem that we can use in our configuration.

Configuring Nginx to use Self-signed Certs

Before we begin, we need to make sure that Nginx web server is installed on our Ubuntu 18.04 server. If it's not installed then you can install it by using this simple command:

#apt install nginx

I've installed and enabled this service on my server.

# nginx -v
nginx version: nginx/1.14.0 (Ubuntu)

#systemctl enable nginx
#systemctl start nginx
#systemctl status nginx

Next. we can configure Nginx to use SSL. I'll explain that in three steps:

  1. Creating a snippet configuration with the generated SSL certificate details.
  2. Creating a snippet configuration for maintaining a Strong and Secure SSL settings overcoming possible SSL vulnerabilities.
  3. Updating the domain virtual host with the above snippet configurations to enable SSL

Step 1: Creating a snippet configuration with the SSL certificate details

Let's create a new snippet configuration file namely "self-signed.conf" for pointing our generated Self-Signed Certificate details inside the Nginx snippet folder: /etc/nginx/snippets/ as below:

# cat /etc/nginx/snippets/self-signed.conf
# Self signed certificates generated by the ssl-cert package
# Don't use them in a production server!

ssl_certificate /etc/ssl/certs/example.com.pem;
ssl_certificate_key /etc/ssl/private/example.com.key;

Here we need to specify our generated certificate path:/etc/ssl/certs/example.com.pem and Key path: /etc/ssl/private/example.com.key for the directive as mentioned above.

Step 2: Creating a snippet configuration for maintaining Strong and Secure SSL settings overcoming possible SSL vulnerabilities

Secondly, we need to maintain a fully functional and strong SSL server configuration protecting our server from all possible SSL vulnerabilities. I have configured my Nginx with a strong SSL cipher suite and enabled some advanced features to ensure the server security. All these parameters are included in the file: /etc/nginx/snippets/ssl-params.conf

cat /etc/nginx/snippets/ssl-params.conf
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling off;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

You can get these Nginx Cipher recommendations in the Cipher list. These parameters will be used in future Nginx configurations for SSL. As you can see we have set the ssl_dhparam setting to point to the Diffie-Hellman file we generated earlier here. Since we are using a self-signed certificate, the SSL stapling will not be used. Hence, I have turned it off or else Nginx will simply output a warning like this nginx: [warn] "ssl_stapling" ignored, issuer certificate not found for certificate. After making these changes you can save the configuration and exit.

 Step 3: Updating the domain virtual host with the above snippet configurations to enable SSL

We are ready with our required snippet configuration, now we can include those in our domain virtual host and enable SSL. Here in this article, I'm using the default Nginx configuration file located at /etc/nginx/sites-available/default. I've modified this file to enable SSL and fetch the generated Self-signed certificates. Please see the modified section below in this configuration:

cat /etc/nginx/sites-available/default

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

# SSL configuration

listen 443 ssl default_server;
listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
include snippets/self-signed.conf;
include snippets/ssl-params.conf;

Now we can save these configurations and restart the Nginx service to make these changes effective.

# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
#systemctl restart nginx

Testing

This is our final step, where we can open up our browser and try to access our server IP at the URL >> https://Server_IP or Hostname. It will display a security warning since we are using a self-signed certificate, you can ignore that warning and click to confirm security to proceed further as shown in the snapshot.

Certificate Warning

Read Also :

That's all! we've successfully configured Nginx with Self-signed certificate using strong encryption methods for secure client connections. I hope this article is useful to you! Please post your valuable comments and suggestions on this.

Saheetha Shameer 12:05 am

About Saheetha Shameer

Self-motivated and dedicated Linux Administrator having 10 years of working experience on various web-hosting control panels and Unix distributions. I'm a quick learner and have a slight inclination towards following the current and emerging trends in the industry. I'm passionate about testing/reviewing new Linux applications and open source tools.

Author Archive Page

Have anything to say?

Your email address will not be published. Required fields are marked *

All comments are subject to moderation.