I started using Ghost as a headless cms for my personal website and it works like a charm, but I had to spend some time to try and deploy it using Dokku, that's what I am going to write about.
Dokku, oh, it is my favorite self-hosted deployment software for personal and sometimes commercial needs. It has its flaws but overall it works in most situations and allows me to save some money, so I use it for my pet-projects and for my website too.
Before we start, I assume you've already installed Dokku on your server, configured all the things properly, installed dokku-mysql, created a new database (ex: ghost-db), created a new app for Ghost, let's call it simply ghost and linked them.
As of v0.24.0 Dokku allows to deploy Docker images using a straightforward command, before this it was a nightmare with tagging.
dokku git:from-image node-js-app dokku/node-js-getting-started:latest
So, dokku git:from-image is exactly what we need.
Step 1. Deploy Ghost image
We are going to use Docker Ghost image that can be found here. You can use any of the tags, but it is fine to use :latest for initial deployment.
dokku git:from-image ghost ghost:latest
This will build your app using the image you provided and then deploy it using your Dokku settings. By the end of the process you will have a working Ghost instance without any persistance and wrong public ports.
Step 2. Dealing with ports
Here we are going to make Ghost app public by adding some new ports and removing those that we don't need.
dokku proxy:ports-add ghost http:80:2368
dokku proxy:ports-remove ghost http:2368:2368
By the end of this step your Ghost app should now be accessible via a domain you provided initially to Dokku or via port mapping.
Step 3. Persist it
Docker images do not keep any data between restarts, that's why we should provide some persistant volumes to it. Dokku allows us to do this easily via storage:mount command.
dokku storage:ensure-directory ghost
dokku storage:mount /var/lib/dokku/data/storage/ghost:/var/lib/ghost/content
dokku ps:rebuild ghost
In this step we create a new folder ghost in a special place where Dokku docs suggests us to keep persisted data, then we use our new folder /var/lib/dokku/data/storage/ghost to keep Ghost data from docker image folder /var/lib/ghost/content. This way everything that Ghost creates and keeps in this content folder will be persisted between reloads.
Step 4. Database
Ghost can work even without a separate database, using a SQLite and keeping it on the disk, I don't really like it but if you are okay with this, then skip this step. Before we even started, you already installed dokku-mysql and created a database for Ghost, we will need it here.
dokku config:set \
database__client=mysql \
database__connection__database=<YOUR_DATABASE_NAME> \
database__connection__host=<YOUR_DATABASE_HOST> \
database__connection__password=<YOUR_DATABASE_PASSWORD> \
database__connection__port=<YOUR_DATABASE_PORT> \
database__connection__user=mysql
In this step we provide some essential database configuration params to the Ghost app, as you set them, Dokku will restart it and it should then work using mysql database.
Step 5. Domain
One of the main things we should do, is to add a domain to our app, Dokku has some useful commands for this.
dokku domains:add ghost my.ghost.website
dokku config:set ghost url=http://my.ghost.website
Step 6. SSL certificate
You need SSL certificate for your website. With Dokku you can add it in several ways, using official Let's Encypt plugin, or using your own certificate, or using a Cloudflare SSL. Any of these do, but don't neglect this step.
Just don't forget to change your website url in configs.
dokku config:set ghost url=https://my.ghost.website
That's it, by now you have a working website powered by Ghost and deployed using Dokku on your own server for little to no money 🪄🦄✨.
Top comments (1)
Hi, thanks for the tutorial.
Even if I install mysql, set the config database_connection_ keys, I still get the following error:
`ERROR connect ECONNREFUSED 127.0.0.1:3306
I cannot manage ghost to pick the config. Any ideas on how to fix this?