Host a blog on your Raspberry Pi with Ghost !
By: Pierre Averous
Tags: DevOps, Raspberry Pi, Tools, Blog

If you want to start a blog, but are unsure about the costs and complexity of hosting one, worry not ! Ghost is an open source CMS (Content Management System) that you can host 100% on your very own Raspberry Pi. This way you can keep hosting costs to a minimum.

In this article, I will show you how to install Ghost on your Raspberry Pi, using docker. I will also show you how to enable HTTPS traffic on your blog, using nginx and Letsencrypt certificates with certbot .

Prerequisites

To follow this tutorial, you will need:

A Raspberry Pi (of course)

Internet access

Basic understanding of Docker

Installing docker

If you have already installed Docker on your Raspberry Pi, you can skip this part.

To install Docker on the Pi, we will be using the helper script that Docker provides. Downloading and running it is as simple as:

Done, Docker is now installed ! To be able to run docker commands without sudo , you will need to add the docker group to your user:

sudo usermod -a -G docker $USER

If you close and reopen your terminal, you can run any Docker command as your non-sudo user !

Installing docker-compose

Installing docker-compose is not as straight-forward as for Docker. You first need to install a couple dependencies:

sudo apt-get install -y libffi-dev libssl-dev

sudo apt-get install -y python3 python3-pip

sudo apt-get remove python-configparser

Then, docker-compose can be installed using pip:

sudo pip3 -v install docker-compose

There you go, now we have all we need to run a Ghost instance on the Raspberry Pi. Let’s move on to setting it up.

Start up the ghost server

We will use docker-compose to launch our ghost server. To do so, we will use the ghost:3-alpine Docker image. By default, Ghost uses an SQLite database, but here we show you how to set it up with a MySQL one.

The setup is a bit trickier with MySQL, as the official Docker image has only been built for amd64 architectures. We used a different image, based on the official one, that has been re-build for arm : hypriot/rpi-mysql:5.5 (https://hub.docker.com/r/hypriot/rpi-mysql/).

Using docker-compose to set all of this up, we end up with the following docker-compose.yml file:

# docker-compose.yml

version: ‘3.1’

ghost:

image: ghost:3-alpine

restart: always

ports:

— 8080:2368

environment:

database__client: mysql

database__connection__host: db

database__connection__user: root

database__connection__password: example

database__connection__database: ghost

url:

volumes:

— ./content:/var/lib/ghost/content

db:

image: hypriot/rpi-mysql

restart: always

environment:

MYSQL_ROOT_PASSWORD: example

volumes:

— mysql-data:/var/lib/mysql services:ghost:image: ghost:3-alpinerestart: alwaysports:— 8080:2368environment:database__client: mysqldatabase__connection__host: dbdatabase__connection__user: rootdatabase__connection__password: exampledatabase__connection__database: ghosturl: https://example.com volumes:— ./content:/var/lib/ghost/contentdb:image: hypriot/rpi-mysqlrestart: alwaysenvironment:MYSQL_ROOT_PASSWORD: examplevolumes:— mysql-data:/var/lib/mysql # Use a docker managed volume for data persistency across reboots

volumes:

mysql-data:

Don’t forget to change the default database password, as we set it to example here. Also, you will need to set the URL Ghost will be exposed on. The example value is https://example.com , in a local setup you would set it to http://localhost:8080 , but in a production environment, you should set it to the domain name you expose your server on. Here, I set it to https://pivrous.wtf for this website.

When you’re done with the config, it’s time to boot it up !

docker-compose up -d

Forwarding traffic to your Raspberry Pi

A final step before obtaining your certificate and starting the HTTPS web server is to route the traffic coming to your domain, say pivrous.wtf in this example, to your Raspberry Pi.

There are two steps to that:

Adding a DNS record that points to your public IP

Adding port forwarding from your home router to your Raspberry Pi.

To add a DNS record that points to your public IP, you will of course need to buy a domain name. There are many DNS providers out there, just choose one that chooses you and with which you can buy a domain name that suits you.

All providers will then allow you to create DNS records. Here you will need to create an A type record, that points your domain name to your own public IP (your home router’s IP on the public internet). You can find that IP either on https://www.whatismyip.com/ or by using the following command:

Now, we need to route this traffic from your home router to your Raspberry Pi, in the local network. This can be done by accessing your home router’s admin interface, usually available at 192.168.0.1 or 192.168.1.1, depending on your internet provider.

You will then need to add a port-forwarding rule, or NAT rule, in your router’s config. You will want to route traffic from ports 80 and 443 on your router (HTTP and HTTPS traffic) to ports 80 and 443 on your Raspberry Pi.

Enabling HTTPS traffic

Now that our services are up and running, and that web traffic reaches our Raspberry Pi, all that’s left to do is to enable HTTPS traffic to reach our Ghost server.

To do this, we will use certbot to obtain a Let's Encrypt SSL certificate, and nginx to handle the HTTPS traffic. First, let's install nginx :

sudo apt-get install nginx

Then, install certbot from its own package repository:

sudo add-apt-repository ppa:certbot/certbot

sudo apt update

sudo apt install python-certbot-nginx

You can then obtain a certificate :

sudo certbot — nginx -d pivrous.wtf

This will place your certificate in /etc/letsencrypt/live/pivrous.wtf . We will then edit the default file located in /etc/nginx/sites-available to replace it with the following content:

server {

listen 80;

server_name pivrous.wtf;

return 301

}

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

server_name pivrous.wtf;

listen 443 ssl;

proxy_pass

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header Host $http_host;

proxy_set_header X-Forwarded-Proto https;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

} location / {proxy_pass http://127.0.0.1:8080 proxy_set_header X-Real-IP $remote_addr;proxy_set_header Host $http_host;proxy_set_header X-Forwarded-Proto https;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ssl_certificate /etc/letsencrypt/live/pivrous.wtf/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/pivrous.wtf/privkey.pem;

ssl on;

}

You will have to adapt the config with your domain name, this example is the one I used for pivrous.wtf . Finally, we will enable the site and restart the nginx service:

sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default

sudo systemctl restart nginx

And that’s it !

You can now access your Ghost site at https://pivrous.wtf ! Amazing, right ?