Caddy, wildcard certs and ghost

Caddy, wildcard certs and ghost

The problem

Let's suppose you have multiple things to host an will hang those applications off a sub-domain. Here we will setup ghost blogging system to sub-domain blog.geoffcorey.com and have geoffcorey.com redirect to the sub-domain by default. We are also going to use wildcard Let's Encrypt certificate so we don't have to generate a certificate for each sub-domain we create.

Cloudflare API Token

You will need your DNS setup on Cloudflare. To obtain an API token please refer to the instructions for the docker image we are using.

GitHub - CaddyBuilds/caddy-cloudflare: Caddy Docker image with Cloudflare DNS module
Caddy Docker image with Cloudflare DNS module. Contribute to CaddyBuilds/caddy-cloudflare development by creating an account on GitHub.

Setup Docker Compose/Caddy file

Here we have Caddy, Ghost and Maria database

docker-compose.yml


x-logging: &default-logging
  options:
    max-size: "500m"
  driver: json-file
networks:
  web:
    external: true
  caddy_internal:
    external: false
    driver: bridge
services:
  caddy:
    image: ghcr.io/caddybuilds/caddy-cloudflare:latest
    restart: unless-stopped
    container_name: caddy    
    env_file:
      - .env
    cap_add:
      - NET_ADMIN
    environment:
      - CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./data/Caddy/Caddyfile:/etc/caddy/Caddyfile
      - ./data/Caddy/data:/data # Optional
      - ./data/Caddy/config:/config # Optional
    networks:
      - web
      - caddy_internal
    depends_on:
      - ghost
      - ghost_gc
  ghost_gc:
    image: ghost:latest
    container_name: ghost_gc
    hostname: ghost_gc
    volumes:
      - ./data/ghost_gc/content:/var/lib/ghost/content
    env_file:
      - .env
    environment: # this section can be commented to start in dev mode by default
      url: https://blog.geoffcorey.com
      database__client: mysql
      database__connection__host: ${GHOST_DB_HOST}
      database__connection__user: ${GHOST_DB_USER}
      database__connection__password: ${GHOST_DB_PASSWORD}
      database__connection__database: ${GHOST_DB_DATABASE_NAME}
    depends_on:
      - ghost_db_gc
    networks:
      - caddy_internal
    restart: unless-stopped
  ghost_db_gc:
    image: lscr.io/linuxserver/mariadb
    container_name: ghost_db_gc
    env_file:
      - .env
    environment:
      - PUID=1000
      - PGID=1000
      - MYSQL_ROOT_PASSWORD=${GHOST_DB_ROOT_PASSWORD}
      - TZ=America/New_York
      - MYSQL_DATABASE=${GHOST_DB_DATABASE_NAME}
      - MYSQL_USER=${GHOST_DB_USER}
      - MYSQL_PASSWORD=${GHOST_DB_PASSWORD}
    volumes:
      - ./data/ghostdb_gc:/config
    networks:
      - caddy_internal
    restart: unless-stopped

Next setup the .env file with secrets

.env

#
# cloudflare token
#
CLOUDFLARE_API_TOKEN=biglongstring
#
# blog.geoffcorey.com - ghost
#
GHOST_DB_HOST=ghost_db_gc
GHOST_DB_USER=ghost
GHOST_DB_PASSWORD=itsasecret
GHOST_DB_DATABASE_NAME=ghost
GHOST_DB_ROOT_PASSWORD=itsabiggersecret

Caddyfile

{
        email myemail@somewhere.com
}

geoffcorey.com {
        redir https://blog.geoffcorey.com
}

*.geoffcorey.com {
        tls {
                dns cloudflare <insert cloudflare API token here too>
        }
        @blog host blog.geoffcorey.com
        handle @blog {
                reverse_proxy ghost_gc:2368
        }
}

Results

You can go to https://geoffcorey.com and it will redirect to https://blog.geoffcorey.com

You can now host other apps such as Immich, Jellyfin and just add to the *.geoffcorey.com section a new entry for the sub-domain used.