Deploy Ghost 5 using docker compose and traefik

Have your ghost blog engine running in only a few minutes! Here's our configuration if you want some inspiration. We are using docker compose, traefik, and an SQLite database.

Our configuration

docker-compose.yml

version: '3.1'

services:

  ghost:
    image: ghost:5.x.x-alpine
    restart: always
    volumes:
      - /data/swag-ghost/content:/var/lib/ghost/versions/5.x.x/content
      - /data/swag-ghost/content:/var/lib/ghost/content
      - /data/swag-ghost/config.json:/var/lib/ghost/config.production.json
    environment:
      url: https://swag.industries
    labels:
      traefik.enable: "true"
      traefik.http.routers.swag-ghost.rule: "Host(`swag.industries`)"
      traefik.http.routers.swag-ghost.entrypoints: "https"
      traefik.http.routers.swag-ghost.service: "swag-ghost"
      traefik.http.routers.swag-ghost.tls.certresolver: "default"
      traefik.http.services.swag-ghost.loadbalancer.server.port: "2368"
networks:
  default:
    external:
      name: traefik

In our configuration, traefik acts as the proxy and this is the reason why the port 2368 isn't exposed.

There seems to be a bug in ghost where the "current" version isn't mounted with the content's volume. Our workaround was to mount it twice as the ghost/content and as the "current" version (for example, 5.1.1).

config.json

{
    "url": "https://swag.industries",
    "server": {
        "port": 2368,
        "host": "0.0.0.0"
    },
    "database": {
        "client": "sqlite3",
        "connection": {
            "filename": "content/data/threadlet.db"
        },
        "debug": false
    },
    "paths": {
        "contentPath": "content/"
    },
    "privacy": {
        "useRpcPing": false,
        "useUpdateCheck": false
    },
    "useMinFiles": false,
    "caching": {
        "theme": {
            "maxAge": 0
        },
        "admin": {
            "maxAge": 0
        }
    }
}

The config.json (config.production.json inside the docker container) is very basic, and we did not change anything in particular. Do note we expose ghost on the port 2368, make sure to use this port as traefik (or your own public port) won't know how to reach your blog.

Quick and easy import

We used to have a manual installation of ghost. As we migrated our blog to docker, we needed to migrate our articles as well. We did so in two steps:

We exported and imported our articles and accounts using the ghost admin interface.

Now that we exported the articles and accounts, we manually imported the related files. We only had images to import from "content/images".

Do not hesitate to reach us out if you have any questions.