UPDATE 2023-06-19: I switched from using Ghost to Hugo. My website is not complicated, I like writing my posts in Markdown, and I like the convenience of having everything in Git. I’m hosting my files in an S3 bucket and using CloudFront as my CDN. This combination has the benefit of being even cheaper than Lightsail.

UPDATE 2022-09-04: I switched from hosting Ghost on AWS EC2 to hosting it on AWS Lightsail. Lightsail is great for a smaller blog like this and makes configuration a breeze. The steps I followed can be found here.


If it wasn’t immediately evident, I created this blog fairly recently. After much deliberation and research, I chose Ghost as my blogging platform. I like its simplicity and focus on content. My desire was to use Amazon AWS for hosting, as it is fairly cheap and dependable. It took some fiddling to get Ghost running and I thought I would share what I did in the hope that it would aid someone else. Please note, these instructions assume the person following them already has an AWS account set up and ready to go.

Disclaimer: These steps are not 100% complete. This is just a guide to point people in the right direction. Chances are something will not work as expected and you will need to google an answer.

Create a new public/private key pair

First, you will need to create a public/private key pair in AWS. This will be used to secure your server and make sure only you can access it later.

  1. Log into the AWS Console.
  2. Make sure to select the region you desire in the upper right hand corner.
  3. Search for and select EC2.
  4. Select Key Pairs.
  5. Create a new key pair specifically for your new server.
  6. Make sure to save your private key .pem file somewhere safe. You’ll need it in the future.

Install Ghost using the Bitnami image

AWS has a marketplace where vendors can host certified images of software. Bitnami conveniently has a Ghost image in the marketplace which comes highly recommended. As such, I decided to start with the Bitnami image. I did not want to install Ghost from scratch unless I really needed to. Here’s how to launch a new Ghost server using the image from Bitnami:

  1. Navigate to the AWS Marketplace and find Ghost Certified by Bitnami
  2. Use the 1-Click Launch option. We want this to be as easy as possible.
  3. Keep version at the latest. Why would you want something old?
  4. Change Region to whichever Amazon region makes sense for you. FYI, some are cheaper than others.
  5. For EC2 Instance Type, start with a t2.micro. This covers the minimum requirements for running Ghost and you can always scale up later.
  6. Make sure to select the key pair you generated previously.
  7. Create the server by clicking Launch with 1-click.

Create an Elastic IP

An Elastic IP is a public IP address that will not change. You will need to associate one of these to your new Ghost instance that is running. If you don’t assign an Elastic IP, the instance will get a new public IP every time it restarts. Bad news for your DNS.

  1. Navigate back to EC2.
  2. Select Elastic IPs.
  3. Use the Allocate new address button to create a new Elastic IP.
  4. Select the Elastic IP you just created and use Actions -> Associate Address to link your new public IP address to your already running instance.

Configure DNS

Now that you have a static public IP address, you can associate it with your DNS (Domain Name Service) provider. GoDaddy is a fairly popular DNS, but there are plenty of other options as well. The steps should be fairly similar no matter what DNS you choose. Under your DNS management screen, add a few records:

  • Type: A, Name: @, Value: YOUR-PUBLIC-IP-ADDRESS
  • Type: CNAME, Name: www, Value: @

SSH into the Ghost instance

There are a few reasons why you would want to connect to your Ghost instance. There might be some configuration settings to adjust or you might need to update Ghost. You only have 24 hours to retrieve the initial randomly generated password. Instructions for retrieving the password can be found here. Once you have the password, you can SSH into the instance:

ssh -i INSTANCE-PRIVATE-KEY-FILE bitnami@ELASTIC-IP-ADDRESS

It’s possible you may have to modify the permissions on your key file first:

chmod 600 INSTANCE-PRIVATE-KEY-FILE

Now that you’ve achieved SSH awesomeness, you can finish configuring your instance.

Configure Ghost domain name

To configure your domain name, you will need to open the Ghost production config. There are multiple ways to do this, but the quickest and dirtiest will be to use vim:

vim /opt/bitnami/apps/ghost/htdocs/config.production.json

Now you can configure the url property to match your blog’s public url. After changing the url, save and quit:

:wq

Remove Bitnami info page

There will be a banner for the Bitnami info page in the lower right corner of your Ghost admin page (www.yourdomain.com/ghost). Fortunately, they provide instructions for removing this banner here. You simply run a command and restart the server:

sudo /opt/bitnami/apps/APPNAME/bnconfig --disable_banner 1
sudo /opt/bitnami/ctlscript.sh restart apache

Run Ghost commands

There are a number of useful Ghost commands you can run when you are connected to the instance via SSH. First you will need to navigate to the Ghost installation folder:

cd /opt/bitnami/apps/ghost/htdocs

Then you can run any Ghost command:

  • View the complete list of Ghost commands
ghost help
  • View the Ghost logs
ghost log
  • View Ghost version information
ghost version

Updating Ghost

This should be easy, but sometimes is a pain. You may run into file permission issues or something else and need to spend some time searching the web for answers.

Update Ghost-CLI to latest version:

cd /opt/bitnami/apps/ghost/lib
sudo npm install ghost-cli

Update Ghost to latest version:

cd /opt/bitnami/apps/ghost/htdocs
ghost update

Configure AWS Simple Email Service

Ghost can be configured to send emails, but some work needs to be done to make the magic happen. In keeping with the AWS theme, we’ll use the AWS Simple Email Service.

  1. Navigate to AWS SES.
    • Click Domains and Verify a New Domain.
    • Make a note of the TXT Value under the Verification section.
    • Make sure you save your Access Key ID and Secret Access Key somewhere secure.
  2. Verify your domain by adding a new record to your DNS.
    • Type: TXT, Name: _amazonses, Value: TXT Value
  3. Navigate back to AWS SES.
    • Click Email Addresses and Verify a New Email Address.
    • Follow instructions to verify the email address.
  4. Instructions for configuring Ghost to use SES can be found here.
    • Open the Ghost config file.
    • /opt/bitnami/apps/ghost/htdocs/config.production.json
  5. Add a mail section with your credentials:
"mail": {
    "transport": "SMTP",
    "from": "do-not-reply@yourdomain.com",
    "options": {
        "host": "email-smtp.AWS-REGION.amazonaws.com",
        "port": 465,
        "service": "SES",
        "auth": {
            "user": "ACCESS-KEY-ID",
            "pass": "SECRET-ACCESS-KEY"
        }
    }
}
  1. After you update the configuration, make sure to restart Ghost:
sudo /opt/bitnami/ctlscript.sh restart ghost
  1. Test your email configuration in Ghost.
    • Navigate to the Ghost admin page (www.yourdomain.com/ghost).
    • Click on Labs under Settings.
    • Click on the Send button next to Test email configuration.
    • You should receive an email shortly.

Fix first paragraph font size

For some strange reason, Ghost enlarges the font size for the first paragraph in a blog post. I think it looks funny, so after some digging, I found these instructions to change the first paragraph to a normal size. Basically, you just put a style in the Blog Header section of the Code injection settings page.

<!-- Fix first paragraph font size -->
<style type="text/css">
 .post-template .kg-card-markdown > p:first-child {font-size: 1em;}    
</style>

Thanks to Tim for figuring that out. The large first paragraph size was going to drive me crazy.

Add syntax highlighting

The default Ghost theme, Casper, does not have syntax highlighting by default. We can add Prism to the Casper theme to support this important feature. I followed the instructions found here.

  1. Configure Prism however you like and download the prism.js and prism.css files.
  2. Copy the prism.js file to your Casper/assets/js folder.
  3. Copy the prism.css file to your Casper/assets/css folder.
  4. In the root of your Casper folder, modify default.hbs with the following:
{{!-- Syntax Highlighting --}}
<link rel="stylesheet" type="text/css" href="{{asset "css/prism.css"}}" />
<script type="text/javascript" src="{{asset "js/prism.js"}}"></script>
  1. Zip up your modified Casper theme and upload it to Ghost in the Design settings page.
  2. Activate the modified theme and check out your new syntax highlighting!

The forked Casper theme that I use can be found on my GitHub: https://github.com/eleniums/Casper

Final thoughts

In the end, it took a bit longer than I expected to get Ghost configured and running how I wanted. But, it was worth it. Hopefully my notes in this post will help someone else who is trying to create their own blog.