/ Raspberry PI

Deploy Ghost under Raspbian with MySQL / nginx / Let's Encrypt / strong SSL


Ghost is a wonderful blogging platform developped with node.js. It's easy to use, fast (You mean, like DC COMICS Flash ? Yeah dude ! Superpowers !) it manages SEO, mardown, and the default theme : Casper is sooooooo beautiful.

So now, we'll learn how to setup Ghost on your Raspberry PI, with Raspbian (of course !), nginx (because it's a damn good and fast http server), and secure it with SSL, but GREAT SSL, the kind of SSL that is rated A on ssllabs ! And... everything self-hosted at home !

__Ok let's do it !__

The Ghost Logo

Setup our Node.js environment :

First of all, Raspbian does not provide by default what we need, so we'll have to download our components elsewhere, but it's fine 'cause Linux users are a big familly and we have many friends able to help us.

What do we need ? Ghost helps us to find our way ...

Node.js >=6.9 <7.* Recommended

Ok... If you say so :

$ sudo curl -sL https://deb.nodesource.com/setup_6.x | sudo bash -
$ sudo apt-get install -y nodejs

You should see something like this :

$ node -v
$ npm -v 


It was so difficult, my fingers are sweating... but i'm a warrior, so let's continue. Let me think... Ghost needs Sqlite3 support (even if we won't use it) !

$ sudo apt-get install sqlite3


Setup and configure our MySQL server/database :

Don't pass out, this step is easy :

$ sudo apt-get install mysql-server
[enter password]

$ mysql_secure_installation

$ mysql -u root -p
> create database ghost;
> CREATE USER 'ghost'@'localhost' IDENTIFIED BY 'password';
> grant create,delete,insert,select,update,alter ON ghost.* TO 'ghost'@'localhost';
> flush privileges;
> quit

Dude what are you doing ? We spoke about Ghost, remember ? Oh yeah, let's download and deploy it !

Ghost installation :

$ mkdir ~/blog && cd ~/blog
$ curl -LOk https://ghost.org/zip/ghost-latest.zip
$ unzip ghost-latest.zip

Boom boom ! Setup everything we need...

$ sudo npm install --production

How should we run that... forever, for eternity, as long as the power is ON, as long as I want to live... ?! Well, Forever will do something for you :

$ sudo npm install forever

Should I configure something ? Yeah, it can be good :

$ mv config.example.js config.js
$ vi config.js

OMG it's full of stars.... What ? are your drunk ? Just edit what you need, and let's get over with...

config = {
         // ### Production
         // When running Ghost in the wild, use the production environment.
         // Configure your URL and mail settings here
    production: {
    url: 'https://blog.cagedmonster.net',
    mail: {},
    database: {
               client: 'mysql',
               connection: {
                            host: 'localhost',
                            user: 'ghost',
                            password: 'password',
                            database: 'ghost',
                            charset: 'utf8'
     debug: true

    server: {
        host: '',
        port: '2368'

Time to run the blog, my hands are shaking....

$ NODE_ENV=production ~/blog/node_modules/forever/bin/forever start index.js

We'll create a crontab task running your app when the system starts :

$ crontab -e
@reboot cd ~/blog/ && NODE_ENV=production ~/blog/node_modules/forever/bin/forever start index.js

What happend, is everything OK ? Of course not, let's broadcast to the whole world !

let's Encrypt

Strong SSL with Let's encrypt :

$ cd /etc/ssl/
$ sudo openssl dhparam -out dhparams.pem 4096
$ cd ~ && wget https://dl.eff.org/certbot-auto
$ chmod a+x ./certbot-auto
$ ./certbot-auto certonly

Nginx Logo

nginx configuration :

$ sudo apt-get install nginx-full
$ sudo vi /etc/nginx/ssl.conf

ssl_prefer_server_ciphers on;
ssl_certificate /etc/letsencrypt/live/<yourdomain>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<yourdomain>/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_dhparam /etc/ssl/dhparams.pem;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000;includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

$ sudo vi /etc/nginx/sites-enabled/default

server {
   listen 80;
   listen         [::]:80;
   server_name    blog.cagedmonster.net;
   return         301 https://$server_name$request_uri;
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name  blog.cagedmonster.net;
    include ssl.conf;
                    location / {
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header X-Forwarded-Proto $scheme;

             location /ghost {
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header X-Forwarded-Proto $scheme;
                    allow   2a01:cb06:3e0:eb00::/56;
                    deny    all;

Start nginx and manage your blog :

$ sudo service nginx start

Enjoy ;)