Rock IT

Setting up SSL with NGINX and LetsEncrypt for your website


We all know that sweet green padlock in our browsers, meaning that our connection to a website is secure. Don't underestimate encrypted connection! Without it, all data is sent in plain text. It's very dangerous if your site handles secret data, like passwords or emails.

Recently, my colleague from work logged into our office router. It's usually very simple if you are connected to a WIFI network. After that, he was able to tell exactly what sites we are visiting and what data each of us sends. And now imagine that our visitors are using not secured networks, like airport / hotel / restaurant hotspots. Network admins or hackers can easily capture exchanged data. Damn, even internet providers can read it!

If you want to prevent that and guard your users, use SSL!


  • Installed Nginx (you can find instructions here)
  • Working webserver (In article I'm assuming localhost:8080 address)
  • Site proxied through Nginx

So, let's start!

Generating Certificates

Before setting up certificate, you need to somehow get one. One of the easiest (and free!) way is using Let's Encrypt Certificate Authority.

Remember! Certificate can't be issued for an IP address.
It can be generated and self-signed, but browsers won't accept it.

Let's Encrypt certificates are valid for 3 months, and need to be regenerated afterwards. Thankfully, there is an automated way to do this, called Certbot. It's a bit different depending on your operating system and I won't show how to use it. Instead, I'll present a way to generate certificates using website sslforfree.

Visit website and type all domains and subdomains you want to be protected by generated certificate. Remember that 'www' is also a subdomain.

Main page of sslforfree

Now we need to prove that we own selected domains. We can do it in multiple ways, but probably the most straightforward one is to upload provided files to our website

Upload file instructions

Download files and store them in nginx static files root, so they are publicly available. For example if your site static root is /usr/share/nginx/html/, you can to create files using:

sudo su - # we want to have root privileges
mkdir -p $DIR
echo "file1_content" > $DIR/file1_name
echo "file2_content" > $DIR/file2_name 
# repeat for all files

Now you should be able to verify your request and get certificates. If everything went ok, you should receive 3 files: Certificate, Private Key and CA Bundle. Save it on your local computer or directly on the server. Remember, always protect you private key!

Nginx require 2 files, one is your private key, and second one is made by concatenating Certificate and CA Bundle. Sample script how to do this in Bash:

sudo su - # we want to have root privileges
mkdir /etc/nginx/ssl
echo "private_key_content" > /etc/nginx/ssl/example.key
echo "certificate_content" >> /etc/nginx/ssl/example.crt
echo "ca_bundle_content" >> /etc/nginx/ssl/example.crt  # '>>' for appending 

Now we're all set! Time for configuring nginx.

Nginx configuration

I'm assuming you already have something like this for serving your site:

upstream site {
    server localhost:8080;

server {
    listen 80;        
    location / {                
        proxy_pass http://site;

Working configuration for SSL (with few improvements) looks like this:

upstream site {
    server localhost:8080;

# blocks if someone want to access your server by IP address
server { 
    listen 80 default_server;
    return 444;  

# redirects to HTTPS version
server {
    listen 80;
    return         301$request_uri;

# proper request handling
server {
    listen 443 ssl;
    # location of key and certificate files
    ssl_certificate /etc/nginx/ssl/example.crt;
    ssl_certificate_key /etc/nginx/ssl/example.key;
    # cache ssl sessions 
    ssl_session_cache  builtin:1000  shared:SSL:10m;    
    # prefer server ciphers (safer)
    ssl_prefer_server_ciphers on;
    # important! protects your website against MITM attacks.
    add_header Strict-Transport-Security "max-age=604800";

    location / {
         # these headers contains information about original request
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header Host $http_host;
         proxy_pass http://site;

I'm using as a domain. Of course you should replace it to your own :)

Also, remember to unblock port 443 on your firewall. If you are using ufw (uncomplicated firewall), you can do it like this:

sudo ufw allow 443
sudo ufw reload

Check if it's working

Reload nginx (on Ubuntu sudo service nginx reload) and visit your site. If everything is done correctly, you should see that connection is encrypted.

Hope it helps someone!

PS. I really appreciate comments. Right now it's very young site, and every comment is priceless. Tell me if you liked it, or what should be changed. Thanks!

PS2. Actually I've set up SSL for my blog while creating this post ^^

Author image
Warsaw, Poland
Full Stack geek. Likes Docker, Python, and JavaScript, always interested in trying new stuff.
You've successfully subscribed to Rock IT
Great! Next, complete checkout for full access to Rock IT
Welcome back! You've successfully signed in.
Unable to sign you in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.