Schrödinger's cat is a famous hypothetical experiment designed to point out a flaw in the Copenhagen interpretation of superposition as it applies to quantum theory.

Sometimes I'm cheap. As in "$5?! WTF!" cheap. And recently my Digital Ocean bill was nearing $20 a month, when I figured WTF? I run maybe 5 small websites (Wordpress and Ghost),  and play around with personal projects (Node and stuff), I shouldn't have to pay this kind of money. What I should do, though, is to run every site in a container, of course, and just use 1 droplet instead of 3. What could possibly go wrong?

Well, apperantly, many things could go wrong. From proper domain and port mapping to SSL certificates and config file permissions. Especially, if you start the process with Ghost, the less popular blogging platform than WordPress. I chose Ghost as a platform for a variety of reasons (basically, I just like it), and I will outline them sometime later (I need time to come up with things besides "I just like it"), so join me on this bumpy journey to the containerized Ghost.

Ghost Docker Container

First thing you need is, not surprisingly, a proper Docker container. Ghost doesn't officially support Docker, however, this is Internet in 2018, and of course there're people who made this happen for us.

Here it is: Ghost Docker container.

You could probably get away with any of the setup options on the page, at least to some extent, but I'd suggest going with the docker-compose one. Is it the best one? Is it the easiest one? I don't really know. What I do know, that after experiencing all sorts of issues with other ways to spin a working setup, I ended up with this one actually working out in the end. Besides, it gives you a way to extend your setup later, which certainly is a plus. We'll get back to this whole docker-compose thing later, after we have a server to run it on.

Digital Ocean

Now, let's create a droplet for our server. Here's how:

Just kidding, simply go to Digital Ocean and create a small droplet (or use an existing one). I'm using Ubuntu 16, you can use whatever you prefer as long as it supports Docker.

Now we're ready to get move forward with the Docker part.

Bringing things together

Let's connect to the droplet we just created via ssh and install Docker. The last part is pretty easy:

apt-get update
apt-get install docker.io

Next step is to create a ghost.yml file for our docker-compose:

touch ghost.yml
nano ghost.yml

Here's what we're going to put it the ghost.yml (disregard everything else):

version: '2'

services:
    ghost:
        image: ghost:2.2.4
        restart: always
        ports:
          - 80:2368
    environment:
        url: https://[YOUR DOMAIN NAME]

There we go. This part it complete, and we are almost there!

SSL

It's 2018, and not having SSL for a domain is no longer acceptible. Not only major browsers see this kind of non-SSL websites as a threat (and rightly so), with free and really-really easy certificate installations from Let's encrypt (simple CLI wizard) and Cloudflare (web), there's no justification to not have an SSL certificate for your domain. It is SO simple now, that we don't really need to do anything to make our Ghost accessible via HTTPS! All there is to it, is obtaining a certificate for your domain and pointing Ghots configs to https://[your domain]. Done and done.

Docker

Now we need to actually spin-up a container with a ghost inside (see what I did here?):

docker-compose -f ghost.yml up

Ghost

Finish line! Now we have (hopefully) our Ghost up and running inside of container in a droplet in the cloud 1. The only thing left is to convince our Ghost that its url is not http://localhost:2368, but https://[your domain]. In fact, we already have it in our environment variable of ghost.yml. However, I found out that it's not necessarily enough, and we do need to update Ghost config. Which is sitting inside of a container. With no editor installed and no Internet access. Well, let's learn a bit more about workarounds:

  • We need to get inside of our container
  • create a ghost user (otherwise Ghost-CLI will cuss at us for using root)
  • exit ghost user and as a root, give ghost user permissions to write to a config file
  • log back in as ghost user and run Ghost-CLI command setting up our default url

Here's how we're going to do this.

First, let's enter the container:

docker ps

This will list your containers and you need to find one with ghost inside. Use the ID of this container to enter it:

CONTAINER ID        IMAGE         ...      
8307bbc42bf4        ghost:2.2.4    ...

docker exec -it 8307bbc42bf4 bash

Now let's create a user, make them an owner of a config file, and run a Ghost-CLI commend:

adduser ghost
exit
chown ghost config.production.json
su - ghost
ghost config --url https://[your domain]
exit

Phew! All set now. Do a simple docker container restart 8307bbc42bf4 and enjoy your new Ghost blog at https://yourdomain.

This is certainly not a comprehansive setup. There's no backup. What happens if the droplet is shutdown or restarts? (the container will restart as well, but hey, think about it!) Should we use MySQL instead of SQLite? (probably, we should). What if there's more sites running in separate containers? But with the information above, you'd be able to update your ghost.yml with MySQL environment settings and add an extra MySQL container, add different Ghost instances and map ports and domains to match them and more.

1 - 20 years ago you'd end up in an insane asylum if you said this out loud around people