Self-signed SSL Certificate with nginx in Ubuntu

Published Apr 25, 2018
Self-signed SSL Certificate with nginx in Ubuntu

Setting up self-signed SSL Certificate with nginx in Ubuntu Server

Let's first get familiar with the terms used in this post.

Self-signed certificate:- A self-signed certificate is an identity certificate that is signed by the same entity whose identity it certifies. There is no third-party involved while make a chain of Trust. A nice try has been made to explain it in layman term here.

SSL:- It is Secure Socket Layer that is used to transfer data securely over HTTPS connection. There are tons of resources available on the internet to understand SSL. A nice explanation is here.

Why do we need self-signed certificate ?

There are many services that only work over the HTTPS connection. Third-party services like GoDaddy generally charge some amount of money to provide SSL certificate. So in case you want your website to be SSL enabled but don't want to pay for it, you can go with a self-signed certificate. Let’s Encrypt provides an easy way to obtain and install trusted certificates for free.

The official client for let's encrypt is Certbot that fetches and stores the SSL certificate. Install it using.

sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot

There are two multiple methods to run the Let's Encrypt client but generallywe prefer these two:

  • Standalone: replaces the webserver to respond to ACME challenges
  • Webroot: needs your webserver to serve challenges from a known folder.

We will go with webroot method.

Let's say that your domain is yourdomain.com. HTML is served from /var/www/yourdomain, and certbot challenges are served from /var/www/letsencrypt. I will explain how the challenges works under the hood in the end of this tutorial.

Now create a file /etc/nginx/snippets/letsencrypt.conf containing:

  location ^~ /.well-known/acme-challenge/ {
      default_type "text/plain";
      root /var/www/letsencrypt;
  }

Create another file /etc/nginx/snippets/ssl.conf containing:

  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:50m;
  ssl_session_tickets off;
  ssl_protocols TLSv1.2;
  ssl_ciphers EECDH+AESGCM:EECDH+AES;
  ssl_ecdh_curve secp384r1;
  ssl_prefer_server_ciphers on;
  ssl_stapling on;
  ssl_stapling_verify on;
  add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload";
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

Create the folder for the challenge:

sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge

Now just add the line include /etc/nginx/snippets/letsencrypt.conf; to your HTTP configured nginx file. Here is what it will look like :-

  server {
    listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;
        server_name mydomain.com www.mydomain.com;
        
        # This line is included
        include /etc/nginx/snippets/letsencrypt.conf;
        
        root /var/www/yourdomain;
        index index.html;
        location / {
            try_files $uri $uri/ =404;
        }
 }

Now we have to create a syslink to activate this nginx file

ln -s /etc/nginx/sites-available/yourdomain.conf /etc/nginx/sites-enabled/yourdomain.conf

To check if nginx syntax to okay

sudo nginx -t

If there is no error then reload the nginx configurations :-

sudo systemctl reload nginx

Now we have setup the configuration, its's time to fire the command to get certificate.

Get the certificate

certbot certonly --webroot --agree-tos --no-eff-email --email YOUR@EMAIL.COM -w /var/www/letsencrypt -d domain.com -d anotherdomain.com

It will automatically save the relevant files in /etc/letsencrypt/live/yourdomain.com/ folder.

We have the certificate now, it's time to modify Nginx config file again to include those certificate:

  server {
      listen 80 default_server;
      server_name www.yourdomain.com;
      
      include /etc/nginx/snippets/letsencrypt.conf;
      
      location / {
      	   # Redirection from http to https i.e port 443
           return 301 https://www.mydomain.com$request_uri;
      }
  }

  server {
      listen 443 ssl http2;  # listen on https
      listen [::]:443 ssl http2;
      server_name yourdomain.com;
    
      # Include generated SSL credentials 
      ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
      ssl_certificate_key /etc/letsencrypt/live/yourdomain.comprivkey.pem;
      ssl_trusted_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
      include /etc/nginx/snippets/ssl.conf;

      location / {
      	  # passing it to local webserver
          proxy_pass http://localhost:80;
      }
  }

Reload again the nginx using

sudo nginx -t
sudo systemctl reload nginx

How the webroot challenge works under the hood :-

At the moment you run the above mentioned certbot command to get the certificate, a file with a random name e.g 'randomnamehereblablabla' is created in a Certbot challenge folder i.e /.well-known/acme-challenge/.
The challenge folder will be served as a Nginx static files path. Hence at that particular instance of time, that file is accessible at http://yourdomain.com/.well_known/acme-challenge/randomstinghereblablabla

This generated file will act as a key to check if the file found over that URL is same as the file generated locally. Certbot will match the two files, if they match Certbot will come to a conclusion that the domain is owned and configured in the same system from which the request was made to get the certificate i.e our own system. It will then generate SSL private and public key to the /etc/letsencrypt/live/yourdomain.com/ folder.

If you followed the procedure correctly, you will get a Congratulation message in terminal. Now visit the domain, you will see a green key icon and https written over the URL bar like this.
images.jpeg

Disadvantages of using self-signed certificates:-

  1. You can only generate SSL certificate for 5 domains from one account.
  2. These certificates are not trusted by other applications/operating systems. This may lead to authentications errors etc.
  3. Self-signed certificates may use low hash and cipher technologies. Due to this, the security level that implemented by self-signed certificates may not satisfy the current Security Policy etc.
  4. No support for advanced PKI (Public Key Infrastructure) functions (e.g. Online checking of the revocation list etc.).

Reference:- Digital Ocean


Please comment for any kind of confusion/suggestions etc. Also Follow me as I write about Blockchain, Web development(Django) and anything I find that I know and that is needed be shared.


Thanks for the reading and Happpy hacking 😃

Discover and read more posts from Mannu Gupta
get started