Let’s Encrypt | SSL Certificate For Ghost Blog Running Ubuntu + NGINX

Prerequisites:

  1.  A server running nginx with root access via SSH
  2. An installation of ghost located at
    /var/www/ghost

     

  3. wget (which should come out of the box with Ubuntu
  4. DNS correctly pointing at your server.  I always run my domains through CloudFlare for security and to help caching and page performance.  Note if you do this, under the Crypto tab you want SSL set to “Full (Strict)”.

5. Some patience if you fail at first :)

Let’s Do This or Let’s Encrypt

 

As encryption, privacy, safety and now even SEO rankings continue to be topics of discussion among the internet’s common discussion points, there is a new need to encrypt your traffic using SSL (Secure Socket Layer).  The problem is that typically SSL certificates were expensive, and  a pain in the ass to install.  Couple that with deploying a node application like Ghost which serves its content over port 2368, which your web browser would never know existed unless the server told it to go there when you visit  a site.  The process bridging the gap between port 80 (default http port that you view all your web content with) and a port such as 2368 needs to be communicated by a server, in this case nginx works very nicely to achieve this outcome.

That’s great, and let’s assume you did some light googling and found a boilerplate nginx config file to pass along traffic to your Ghost blog, you set up your DNS with something like myblog.com and everything is working nicely.  Well, to throw a wrench in your success I am challenging you to dig a little deeper and think about the possibility of adding an SSL certificate to your site so that visitors are secure as is all communication on your server.  You might say something like:

Dude, I am not paying $119 a year for this, for a few points scored with Google.

I agree, I wouldn’t either.  But there is a new certificate authority called “Let’sEncrypt” that issues valid SSL certificates for your site and all you need is a basic guiding hand and a decent knowledge of the command line to obtain and install a certificate and begin sending your visitors to port 443 instead of the traditional 80.

So if you are like me I have my webroot of my ghost blog located at

/var/www/ghost

 

Now we need to obtain our certificate and key, add them to our site’s config file and tell Ghost the url of our site is going to be https not http.  First let’s set up our nginx configuration file for our site.  It is located under

/etc/nginx/sites-available/ghost

Before I enable SSL on my site I should have something that looks like the sections of this config file that ARE NOT commented out.

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    location ~ ^/.well-known {
        root /var/www/ghost;
    }

    location / {
        return 301 https://$server_name$request_uri;
    }
}

# server {
#     listen 443 ssl;
#     server_name yourdomain.com www.yourdomain.com;

#     root /var/www/ghost;
#     index index.html index.htm;
#     client_max_body_size 10G;

#     location / {
#         proxy_pass http://localhost:2368;
#         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#         proxy_set_header Host $http_host;
#         proxy_set_header X-Forwarded-Proto $scheme;
#         proxy_buffering off;
#     }

#     ssl on;
#     ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
#     ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
#     ssl_prefer_server_ciphers On;
#     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#     ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;

#     location ~ ^/(sitemap.xml|robots.txt) {
#         root /var/www/ghost/public;
#     }

#     location ~ ^/.well-known {
#         root /var/www/ghost;
#     }
# }

So for now any line beginning with “#”, just ignore for the time being.  For our server routing trafic over port 80 we don’t have:

location / {....}

This section that is currently commented out is telling the server “hey, when a request comes to visit the root url or “/” redirect the traffic to a port that is set by the line:

proxy_pass http://localhost:2368;

The 2368 is the previously mentioned default port that runs ghost.  So nginx is rerouting direct traffic to the server to your Ghost web application.  So back to ssl, so we can uncomment our ssl server from our ghost nginx server configuration file.  In order to properly set up SSL with Let’s Encrypt, you have to have the A record of your domain pointing to the correct IP of your server, along with the subdomain ‘www’ should you choose to use that as well.  We will also need to modify Ghost’s configuration file to match the https protocol.  Let’s start with the Ghost config.js file.

cd /var/wwww/ghost
nano config.js
# Now find this line under the production section of the config.js file
# url: http://myblog.com <-- we want to change to url: https://myblog.com
# obviously myblog.com is whatever domain you are going to get the certificate for
# Now save the file by hitting Ctrl + O then Ctrl + X 

Don’t restart ghost just yet we still need to get our certificate.  In the terminal run:

# Download the letsencrypt tool certbot-auto for obtaining the certificate

cd /opt && wget https://dl.eff.org/certbot-auto && chmod a+x certbot-auto

# Now let's grab that certificate

./certbot-auto certonly --webroot -w /var/www/ghost -d yourdomain.com -d www.yourdomain.com

# Remember about leaving port 80 section of server alone in the ghost configuration file for nginx?
# This is why: cert-bot auto creates a directory inside the root directory of your server called .well-known
# This is a hidden directory with a 'challenge' generated by certbot, and is used to verify that your domain is indeed pointing to your server
# We have let this run and it was successful, you will get a successful output and keys for installing on the server

Now it is time to uncomment all of the lines in our ghost nginx configuration file located at /etc/nginx/sites-available/ghost

your new configuration should look like this:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    location ~ ^/.well-known {
        root /var/www/ghost;
    }

    location / {
        return 301 https://$server_name$request_uri;
    }
}

 server {
     listen 443 ssl;
     server_name yourdomain.com www.yourdomain.com;

     root /var/www/ghost;
     index index.html index.htm;
     client_max_body_size 10G;

     location / {
         proxy_pass http://localhost:2368;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header Host $http_host;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_buffering off;
     }
# here where ssl_certificate_key and ssl_certificate are located, change yourdomain.com  with the domain you chose when running certbot
     ssl on;
     ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
     ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
     ssl_prefer_server_ciphers On;
     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
     ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;

     location ~ ^/(sitemap.xml|robots.txt) {
         root /var/www/ghost/public;
     }

     location ~ ^/.well-known {
         root /var/www/ghost;
     }
 }

Now save that file.   Test the configuration by running

nginx -t
#if succesful run
service ghost restart
service nginx restart

# if you don't have a ghost service file located in /etc/init.d and 
# are using a node module like forever then simply 
cd /var/www/ghost
forever stop 0 # Assuming that ghost is the only forever process
NODE_ENV=production forever start index.js
#ghost back up and running
service nginx restart
#nginx now running with new configuration and over port 443 with valid SSL 
#certificates.

That’s it, you now have traffic to your Ghost blog set up with SSL using nginx and certbot auto.  No more outrageous fees to enjoy your right to a more secure private web browsing experience.

5 comments

Thanks for the article. But what about renewing the certificate?
Apparently, you need the “.well-known” to be accessible for the renewing. Ghost router won’t direct that. How to manage to do so?

He man! Sorry for such a terribly late response. I am going to write another post shortly that will show you how this all now can be automated using npm i -g ghost-cli or if you wanna keep it on the wild side npm i -g ghost-cli@latest

This will take care of just about every problem you’ve experienced in setting up a Ghost or any node web app for that matter — well idk. the example express server code snippet is pretty simple, hard to screw that one up.

I love Let’s Encrypt! Unless all your visitors still run Windows XP, it’s an excellent choice for most things. Hopefully it’ll be around for a long time to come.

Leave a Reply