Custom themes and routes.yaml for a self-hosted Ghost site in Docker

How to install and update a custom Ghost theme in a Docker setup, and how to use routes.yaml for custom URLs.

Uploading a theme zip through Ghost admin works, but in a Docker setup it is easy to lose track of which theme version is live and where it is stored. Treating the theme as code, and knowing how routes.yaml works, makes a self-hosted Ghost site much easier to maintain.

Where themes live

In the official Ghost image, content is under /var/lib/ghost/content. Themes are in content/themes, and uploads in content/images. That directory must be a volume, or uploaded themes and images vanish when the container is recreated:

services:
  ghost:
    image: ghost:5
    volumes:
      - ghost_content:/var/lib/ghost/content

Keep the theme in Git

Develop the theme in its own repository. Run npx gscan . before each release; it is Ghost’s official theme validator and catches deprecated helpers that would break on upgrade. Then either upload the zip in admin, or deploy it with the Admin API, which lets CI push a theme on every tagged release.

Avoid bind mounting a theme folder from the host into content/themes in production. Ghost caches templates, and changes to a mounted folder can appear only partially until a restart.

routes.yaml basics

Ghost’s dynamic routing lives in routes.yaml, uploaded under Settings, Labs. It controls three things:

routes:
  /start/: start
collections:
  /blog/:
    permalink: /blog/{slug}/
    template: index
taxonomies:
  tag: /topic/{slug}/
  author: /author/{slug}/
  • routes maps a URL to a template, such as a custom landing page
  • collections decides which posts appear where and their permalink format
  • taxonomies sets tag and author URLs

Moving posts under /blog/

Changing the collection permalink changes every post URL. Add redirects for the old URLs in redirects.yaml, or from your reverse proxy, before you upload the new routes. Otherwise search traffic hits 404s.

Back up both files

Download routes.yaml and redirects.yaml from admin and commit them next to the theme. They are stored in the content volume, but having them in Git shows when and why URLs changed.

Upgrading Ghost

Before a major version upgrade, run gscan with the target version flag against your theme and fix errors first. Then back up the database and content volume, change the image tag, and watch the logs while migrations run.

For setup, email and reverse proxy configuration, see this guide to self-hosting a Ghost blog.

Disclosure: I help build Peon.


Write a comment