A self-hosted Ghost publishing platform, running in Docker and reverse-proxied by Caddy (not nginx).
| Service | Image | Role |
|---|---|---|
ghost |
custom (./ghost/Dockerfile, extends ghost:6-alpine) |
The publishing app |
mysql |
mysql:8.0 |
Database |
caddy |
caddy:2-alpine |
Reverse proxy + automatic HTTPS |
Data persists in local bind-mounted folders under ./data/
(data/ghost-content, data/mysql, data/caddy/data, data/caddy/config).
# 1. Configure secrets
cp .env.example .env
# edit .env and set MYSQL_ROOT_PASSWORD / MYSQL_PASSWORD
# 2. Build & start
make dev # or: docker compose up -d --build
# 3. Open the site / admin
# http://localhost/ -> the blog
# http://localhost/ghost -> admin setup (create your account here)Check status and logs:
docker compose ps
docker compose logs -f ghost- In
.env, setGHOST_URL=http://<public-ip>and leaveCADDY_SITE_ADDRESSunset (Caddy serves plain HTTP on port 80). - Open port 80 to the internet.
make prod— verifies the.envsettings, then starts the stack.
- Point your domain's DNS A/AAAA record at this server.
- In
.env, setGHOST_URL=https://your-domainandCADDY_SITE_ADDRESS=your-domain. - Ensure ports 80 and 443 are open to the internet (Caddy needs them to obtain a Let's Encrypt certificate).
make prod— Caddy provisions and renews the cert automatically.
The custom Ghost image ships with mysqldump. Back up the database with:
docker compose exec mysql sh -c \
'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" ghost' > ghost-backup.sqlGhost's uploaded images/themes live in ./data/ghost-content — back that
up too (e.g. tar czf ghost_content.tgz -C data/ghost-content .).
docker compose pull # newer mysql / caddy
docker compose build --pull # newer Ghost base image
docker compose up -d