Setting up a self-hosted Ghost site

This page contains referral links which help to maintain this site.

Getting Started

First, let us go through the list of services and tools we will be using to set up a self-hosted Ghost site.

  1. Ghost as our Content Management System, obviously
  2. Namecheap as our domain name registrar
  3. DigitalOcean as our web virtual machine host
  4. Cloudflare as our Content Delivery Network service
  5. Mailgun as our e-mail delivery service
  6. SSH with built in Terminal on MacOS or Putty on Windows

You may use other services and tools to achieve the same purpose (other than Ghost of course). The list above is simply the services that I have used.


Ghost

What is Ghost? Ghost is a blogging platform powering sites such as this. They offer a fully-managed Ghost(Pro) service which handles all the heavy-lifting of setting up and maintaining a web server for you. However, you can also self-host the platform should you choose to, in which case, carry on reading!


Register a Domain Name

First, choose a domain name for your site. I use Namecheap for their ease-of-use and reasonable pricing. But you may choose any other registrars.

At this step, you may also subscribe to Namecheap's Private Email service for your new site. Having a mailbox linked to your domain name helps to improve your newsletter deliverability and offers a more professional image to your newsletter. Setting up your newsletter with Mailgun integration is easy and will be explained in a later section. Can't decide? Don't worry, you can choose to add this later on, or use other e-mail providers.

Great! Now you have your domain name registered!


Spin Up a DigitalOcean Droplet

Next, we will create a DigitalOcean droplet (virtual machine) to host the website. I have selected DigitalOcean as Ghost has provided a pre-built droplet image that is easy to setup.

Sign up for a DigitalOcean account if you do not already have one. You may use my referral link to get US$100 credit for 60 days.

The first thing to do next is to add your SSH key to your account. DigitalOcean provides a guide to do this. This is recommended as it will improve the security of your droplet. Be careful to not lose this SSH key, or you will lose access to your droplet.

Upon entering your control panel, you will need to create a new project. Simply enter your project's name and description accordingly.

Now, we can create a droplet. At the top menu bar, select Create -> Droplets. Then select Marketplace on the navigation tab, and search for Ghost.

Next, select your droplet resources. The cheapest droplet is sufficient, until you have grown your website size and traffic. Increasing your droplet resources in the future is also easy. You may choose to select their Premium offerings, if you prefer a newer server hardware.

Then, select a data centre. I recommend selecting one nearest to where you expect most of your readers reside in.

In the next section, select SSH keys as your authentication method and select the SSH key you have added to your account previously.

Under additional options, you may select Enable backups to keep your droplet backed up (you can enable this later once your site is up and running). I also recommend enabling Monitoring so you can monitor the droplet's resource usage. I will let you explore the other options.

Finally, specify the number of droplets (1 will do) and a hostname for your droplet. Click Create Droplet to spin up your droplet!

After a couple of moments, you will receive a notification that your droplet has been created. You will see it in the control panel. Take note of the IP address as you will need it later.

Verify the droplet by accessing to the IP address specified. You should see this.

Great! Now you have a Ghost droplet set up. Next, you will need to access your droplet through SSH to initialise the Ghost site. But before that, let us point your new domain name to the droplet.


Set Up Cloudflare CDN

Cloudflare is a content delivery network service that helps to speed up website loading and adds a layer of security. You may learn more about CDNs here. Though not strictly necessary, I recommend you to set this up.

Create a Cloudflare account if you do not already have one. Then add your domain name to your account.

Next, select your plan. The free tier is sufficient; you may explore their paid tiers if they fit your needs.

Then, you will have to change your domain nameserver to point to Cloudflare's nameservers. The nameservers provided to you might not be the same as mine; use the ones provided to you.

Log in to your Namecheap dashboard and select MANAGE on your domain name. Then under the Domains navigation tab, change the nameservers to Custom DNS and supply the Cloudflare nameservers provided to you.

Wait for a couple of minutes for the DNS changes to be propagated. Upon completion, return to Cloudflare dashboard to configure your DNS settings. Feel free to enable the recommended settings. I recommend applying Enable Always use HTTPS.

Next, on the left navigation panel on Cloudflare, select DNS. You will see a list of DNS records for your domain name.

Modify the root A record to point to your droplet's IP address. Save the changes and let the DNS record propagate. After this step, you should be able to access your ghost site using your domain name instead of the droplet's IP address.

Now we can proceed to SSH into our droplet to complete the Ghost site initialisation.


Initialise Ghost Installation

At this point, you have set up the DigitalOcean droplet and Cloudflare CDN. We can proceed to initialise the Ghost installation and create an admin account. On your Terminal, execute the following command with your droplet's IP address to access the droplet.

ssh root@<your-droplet-ip-address>

If you have set up SSH key in your droplet, you should be able to log in automatically. Then, simply follow the prompts on the Terminal to complete the Ghost site initialisation. If any error occurs, an easy way to restart the installation is to delete and re-create your droplet. This ensures that no partial configuration is left on your final Ghost site.

After completion of this step, you should be able to view your Ghost website when you access your domain name again.

The next step is to take over the admin account of the Ghost site. Go to the url https://<your-domain-name>/ghost. You should be greeted with a page to create your account. Follow the steps to create your Ghost admin account. In order to invite staff to your site, you will need to set up email functionality on your Ghost site. As such, you can do this later.

Congratulations! You have a Ghost site set up!


Mailgun Integration

Mailgun is an email delivery service provider. It allows your Ghost site to send emails with Mailgun's SMTP server and also broadcast newsletters to your subscribers through Ghost's Mailgun integration. Mailgun does not offer a free tier, but their Flex tier is very affordable for a starter site.

Create a Mailgun account if you do not already have one. On you Mailgun dashboard, select Sending -> Domains on the left navigation panel. Then, click on Add New Domain.

I recommend setting up separate email subdomain for transactional (e.g. member sign up, password reset) and newsletter emails. You may read more about this here and here. These subdomains can be human-readable

account.<your-domain-name>
newsletter.<your-domain-name>

or simply be

mail1.<your-domain-name>
mail2.<your-domain-name>

After specifying your new domain, you will be asked to add some DNS records. Go to your Cloudflare dashboard and add the DNS records as provided by Mailgun.

After verifying the DNS settings, you can find the relevant SMTP credentials under Domain Settings on the left navigation bar, and going to the SMTP credentials tab.

Next, supply these credentials to the Ghost configuration. SSH into your droplet, switch to the Ghost user and go to the Ghost install directory.

sudo -i -u ghost-mgr
cd /var/www/ghost

Edit your configuration file,

sudo nano config.production.json

and edit the mail entry using your transactional email subdomain:

{
  "mail": {
    "transport": "SMTP",
    "from": "'YourName' <noreply@your-mail-sub-domain-name>",
    "options": {
      "service": "Mailgun",
      "host": "smtp.mailgun.org",
      "port": 587,
      "secure": false,
      "auth": {
        "user": "user-provided-by-mailgun",
        "pass": "password-provided-by-mailgun"
      }
    }
  }
}

Port 587 already uses encrypted transmission and hence we can specify "secure": false. In the from field, you can specify how your recipient sees the sender of your emails.

Finally, restart Ghost.

ghost restart

The above credentials will allow your Ghost site to send transactional emails. To configure newsletter emails, we will use Mailgun API.

Go to your Ghost admin page and navigate to Settings -> Email newsletter. Under Mailgun configuration, supply your Mailgun API key. Here, use your newsletter email subdomain. You can obtain this information in your Mailgun dashboard under the Settings > API Keys in the left navigation panel.

That's it! You have successfully set up and configured your Ghost site!

Additional note: Mailgun is a paid service. After the free trial, you will automatically be subscribed to the lowest paid tier. If you prefer the pay-per-use (Flex) tier, you will need to manually downgrade your subscription.


Additional Configurations

Below are a couple of additional configurations you can apply to make your Ghost site more secure and reliable.

Enable Cloudflare SSL/TLS Full mode

You may enable Full mode for Cloudflare SSL. Log in to your Cloudflare dashboard. Under your site, select SSL/TLS on the left navigation panel. Change the encryption mode to Full.

Secure your database

By default, the MySQL database installed in the droplet is not very secure. You can increase the database security by running this command over SSH.

mysql_secure_installation

Follow the prompts on the Terminal to complete upgrading your database security. The key step required from you is to create a password to access the database key.

Add droplet monitoring alert

If you have enabled monitoring during the droplet creation, you can enable alerts which will notify you if the droplet resources are reaching their limits.

Go to your DigitalOcean control panel, and select Monitoring on the left navigation pane. Here, you can set up alerts for the resources you desire. I suggest setting up an alert for Memory and Disk. Hitting these alerts will mean you need to start considering upgrading your droplet or optimising your resource usage.

Create droplet swap file

If you have enabled monitoring during the droplet creation, you will be able to observe the resource usage of your droplet. In particular, we are interested in the memory usage.

The official system requirements for a Ghost installation is 1GB of RAM. If you recall, we have selected the cheapest droplet with 1GB of RAM. This is barely sufficient as shown in the resource graph showing 80% to 90% memory utilisation, even with no content and barely any traffic.

Out of memory errors are bad, as it can lead to your entire droplet crashing. Hence, we would like to prevent that. Instead of increasing your droplet resources (and spending more money), we will use some of our Disk space as Memory (this is called a "swap file"). DigitalOcean community forum has a great tutorial covering this, which I will not reproduce here.

After enabling swap file, you can observe the memory usage decreasing to around 60% as more data is stored in the swap file. Of course, we cannot indefinitely increase the swap file size as the site expands and you should eventually increase the droplet resources.

Separate subdomain for Ghost admin

Ghost documentation also suggests loading Ghost admin on a separate domain. We can use a subdomain to achieve this. The outcome is to have the admin to load on this URL.

https://<subdomain>.<your-domain-name>/ghost

First, create a subdomain on Cloudflare DNS settings by creating an A record that points to your droplet IP address.

Verify the subdomain works by navigating to https://<subdomain>.<your-domain-name>, you should see your Ghost site.

Next, SSH into your droplet, switch to the Ghost user and go to the Ghost install directory.

sudo -i -u ghost-mgr
cd /var/www/ghost

Edit your configuration file,

sudo nano config.production.json

and add the following admin entry:

{
  "url: "https://<your-domain-name>"
  "admin": {
    "url": "https://<subdomain>.<your-domain-name>",
    "redirects": false
  }
}

The "redirects": false configuration disables redirecting the old admin page (on the root domain) to the new one (with subdomain).

Another configuration to change is the iframe security configuration so that we can preview the site on the admin page even though they are on a different FQDN.

Open the configuration file

sudo nano /etc/nginx/snippets/ssl-params.conf

Then, edit the X-Frame-Options header

add_header X-Frame-Options "allow-from <subdomain>.<your-domain-name>";

and add this Content-Security-Policy header

add_header Content-Security-Policy "frame-ancestors <subdomain>.<your-domain-name>";

Finally, reload the Nginx configuration and restart Ghost to apply the changes.

sudo nginx -s reload
ghost restart

You should now be able to access your admin page only on the subdomain and not the root domain.