Dogfooding it, Pt 3 - Ghost

At this point, we have a Docker server and a PerconaDB / MySQL container. It's time to install the Ghost CMS itself. First, we'll need to establish the database user for it. Ghost itself does not support a shared secret, so we're just going to have to live with having it lie around. There are workarounds, but they are not easy, and at least at this point in time, I am aiming this blog towards homelab beginners... so we'll just deal.

Preparing the database is easy enough.

$ echo -n $(pwgen) | docker secrets create ghost -
$ docker service update --secret-add ghost percona
(( Start a shell on the PerconaDB container ))
$ mysql -u root --password=$(cat /run/secrets/percona-root) << EOSQL
create user if not exists 'ghost'@'%' identified by '$(cat /run/secrets/ghost)';
create database if not exists ghost;
grant all on ghost.* to 'ghost'@'%';
flush privileges;
EOSQL
$ cat /run/secrets/ghost

This creates the password for the database user 'ghost', creates that user, and grants it all privileges on the database that will back the Ghost CMS. The cat command outputs the password, since we'll need it to configure Ghost itself.

You'll also need a way for Ghost to send email. As an example, the configuration file will assume Google as SMTP server, but you may have a different service.

Next, we set up the Ghost configuration file. Edit ~/config.production.json to the following content:

{
  "url": "https://<domain name>",
  "server": {
    "port": 2368,
    "host": "0.0.0.0"
  },
  "database": {
    "client": "mysql",
    "connection": {
      "host": "percona",
      "user": "ghost",
      "password": "<as extracted from server earlier>",
      "database": "ghost"
    }
  },
  "mail": {
    "transport": "smtp",
    "options": {
      "service": "Google",
      "host": "smtp.gmail.com",
      "port": 587,
      "auth": {
        "user": "<your@google.email>",
        "pass": "<App Password>"
      }
    }
  },
  "logging": {
    "transports": [
      "file",
      "stdout"
    ]
  },
  "process": "systemd",
  "paths": {
    "contentPath": "/var/lib/ghost/content"
  }
}

Finally, we'll need a place for Ghost to store static persistent files.

$ mkdir -p /srv/data/docker/ghost/data
$ sudo chown -R 10000:10000 /srv/data/docker/ghost
$ sudo chmod -R g-rwx,o-rwx /srv/data/docker/ghost

And deploy the Ghost container.

$ docker config create ghost config.production.json
$ docker service create --config source=ghost,target=/var/lib/ghost/config.production.json --network homelab --network homelab-bridge --name ghost --replicas 1 --mount "type=bind","source=/srv/data/docker/gost/data","target=/var/lib/ghost/content" ghost:5

Docker config stores our configuration file inside docker. The config option to docker service create maps that configuration to where it belongs for Ghost to pick it up. Two networks - our homelab network has no outbound connectivity, but Ghost will need an SMTP server. We could set a relay up in another container, but this is easier. Running a mail server is hard.

Subscribe to Homelab Adventures

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe