so, I am back with Ghost

Published on 24 Jul 2016

I thought I would settle down with Jekyll + GitHub + Travis CI + Amazon S3 combination for a resilient, fault-tolerant blog. But, it takes so much time to write, then committing the changes to GitHub, waiting the Travis to build the assets, then having it live by serving the page from Amazon S3. At first, it came to me as being geek, hacky, and resistant to failure. By that I mean GitHub won’t go down, I can switch to different CI quite easily, and Amazon S3 also won’t go down.

Every part of the pipeline is configurable and switchable, but having a lot of moving parts makes the maintenance a bit of a hassle. After all, CaspershireNet is just a small blog. Ideally, writing a post shouldn’t be a long workflow, and updating is possible from almost everywhere. When using git with my previous setup, that makes it harder to write when I don’t my computer with me.

The current setup includes installing nginx for reverse proxy, Ghost CMS, NodeJS, Let’s Encrypt client for generating certificate for SSL, and setting up backup strategy to AWS S3.

sudo apt-get update; sudo apt-get upgrade
sudo apt-get install nginx vim htop s3cmd letsencrypt

# installing nvm for managing NodeJS installation
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.3/install.sh | bash
hash -r

# when I was installing Ghost v0.8.0, the guide says it work best with NodeJS v4 Argon LTS (v4.2.3 as of now)
nvm install -s v4.2.3

Follow this guide (Ghost Documentation) to install Ghost. Make sure you have more than 512mb RAM. I am using DigitalOcean 512mb plan. To compensate the low RAM, create 1GB swapfile to prevent OOM from killing the installation. Follow this guide (DigitalOcean) on setting up swapfile. Also, set up the nginx reverse proxy. Follow this guide (Ghost for Beginners).

When I was about to get Let’s Encrypt SSL certificate, I referred to CertBot documentation. I had trouble using the webroot module to generate the certificate. My theory is that since nginx already reverse proxy-ing Ghost, it couldn’t access the ACME although I had the nginx to use /var/www as web root directory. The solution? Use standalone module, but nginx must be stopped first.

sudo service nginx stop
sudo letsencrypt certonly --standalone -d caspershire.net -d www.caspershire.net

Then, instruct the nginx to serve HTTPS, also forcing HSTS. Don’t forget to renew the certificate once every 3 months, because that’s the requirement for using Let’s Encrypt.

ssl_certificate /etc/path/to/certificate.pem;
ssl_certificate_key /etc/path/key.pem;
add_header Strict-Transport-Security "max-age=31536000";

Restart nginx. If everything is fine, the blog is ready.

Let’s set up the backup with bash script and cron. The files intended for backup will be zipped, date-stamped, and sent to an AWS S3 bucket. I started with creating an S3 bucket, named it as ghostbackup. I am a bit of a security paranoid, so I created an IAM user and then granting it specific inline policies to access ghostbackup bucket only, so that my other buckets on AWS S3 won’t be accessed. For the sake of brevity, I don’t include the guide for IAM user creation and introduction into policy because it would make this tutorial 3 times longer than it should. Below is the inline policies I am currently using for IAM user that can only have access to ghostbackup bucket on S3.

{
    "Statement": [
        {
            "Action": [
                "s3:ListAllMyBuckets"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Action": [
                "s3:ListBucket",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::ghostbackup",
                "arn:aws:s3:::ghostbackup/*"
            ]
        }
    ]
}

There are 3 moving parts of this backup strategy: archiving files with tar utility and date-stamp it, sending the archive by synchronizing it to AWS S3 with s3cmd utility, and automate these 2 processes with cron job. Configure s3cmd first.

s3cmd --configure -c ghost.cfg

If you run --configure without -c argument, by default it will create a configuration file at ~/.s3cfg. By adding -c ghost.cfg, a configuration file is specifically created. Then you will be asked for AWS access key and AWS secret key, along with other questions. It will ask you to set up a password for encryption, and also an option to transmit data through HTTPS.

Test your configuration with s3cmd -c ghost.cfg ls to see that if it is working as intended. This will list all available buckets in your account. Below is the bash file (I name it as backup.sh) for archiving Ghost with tar, and then synchronizing it to ghostbackup backup with s3cmd.

#!/bin/bash

tar -czf ghost_backups3/archive-`date '+%y%m%d'`.tar.gz ghost/content ghost/config.js
s3cmd -c ghost.cfg sync --recursive --preserve ~/ghost_backups3/* s3://ghostbackup

Then, set up the cron job. Issue crontab command, and then add the line below. Everyday at 10 PM, cron will execute backup.sh file, the tar command will archive Ghost, and having it synchronized with s3cmd to my ghostbackup S3 bucket.

0 22 * * * /home/clyne/backup.sh

closing words

I had used Ghost before. In fact, CaspershireNet was setup when I first started using Ghost (hence, the name). It makes sense to have CaspershireNet running on Ghost, right?