Run Ghost inside a Docker container on DigitalOcean

Recently I created a new theme for Ghost, that you can find here (opens new window) and can currently experience on this website. I wanted a way of showing it off, so anyone that wants to contribute to it or just plain use it, can get a feel of what it looks like in a live environment.

Initially I looked at Heroku, but I soon fell into a rabbit hole of errors, because Docker doesn't play nice with Heroku and I didn't like that I would have to jump through hoops just to keep the app online. Keep in mind that this is an open source project and having to pay for keeping the Heroku app was not something I was prepared to do at that moment.

But, Stefan, you already have a server, where you host your website! Why don't you use that? Initially, I wanted to keep my server clean off other systems and just use it for my website. I changed my mind and here we are.

Enough backstory, let's get to the actual implementation. Bellow is my current stack and the process I followed that works for my setup. It may work differently for you and your stack.

My whole stack is like this:

  1. I have the domain registered and I use Cloudflare as a DNS provider.
  2. The website itself is hosted on a DigitalOcean droplet, that runs their Ghost image (an older version but I keep it up to date).

Nothing fancy, right?

So, the first thing I did was to get Docker working on my droplet. After running apt-get update I installed Docker using this:

apt-get install

Once that was done, I just spun up a new Docker container for Ghost. Luckily there is already a Docker image for Ghost. You can check it out here (opens new window).

Now the tricky part. I ran this command to expose the Ghost instance in the Docker container, to the outside world.

docker run -d --name name_your_container -p 3001:2368 -e url=https://ghost_url ghost

So, what this command does, is that it runs a new container with a custom name and it exposes the Ghost port 2368 on the host's 3001 port. Of course you can use a different port on your machine, if you so desire. Another cool thing is that this Docker image accepts, as parameters, any Ghost configuration parameters, found here (opens new window). The Docker image name is ghost.

So now, if you access your droplets IP followed by the 3001 port, you should see a new Ghost instance up and running.

The last thing I did was to spin up a new subdomain inside Nginx and add it to Cloudflare. The configuration I used for Nginx is similar to the one bellow:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;


    ssl_certificate certificate.cert;
    ssl_certificate_key key.key;
    include conf.conf;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;


    location ~ /.well-known {
        allow all;

    client_max_body_size 50m;

Besides the above configuration, I've added a CNAME record with the subdomain name that points to the root domain.

And that's it. All good and done.

Nothing out of the ordinary. How would you have done it differently? Tweet @stefanbc (opens new window) or email me [email protected].

Until next time, code long and prosper.