Ghost: Self-Hosted Blogging Platform Setup
Deploy Ghost on Docker for a clean, fast self-hosted blog or newsletter platform with membership support, built-in SEO, and a polished editor.
Ghost is a publishing platform built specifically for blogs and newsletters. It’s not WordPress — there’s no plugin ecosystem, no theme marketplace with 10,000 options, and no block editor that requires three tutorials to figure out. Ghost has a clean Markdown-based editor, native newsletter delivery, membership and subscription support, and a CMS that gets out of the way and lets you write.
If you want to run a personal blog, a newsletter, or both on your own server, Ghost is the most focused tool for the job.
Ghost vs. WordPress
WordPress is the default recommendation for blogging because it’s everywhere. Ghost is the better recommendation if:
- You’re starting fresh and want something purpose-built
- You want a clean writing experience without plugin sprawl
- You’re interested in the membership/newsletter features
- You care about page performance (Ghost-generated sites are fast by default)
WordPress is still the right answer if you need its plugin ecosystem, want to build something beyond a blog, or are migrating from an existing WordPress site. For a new blog on a homelab, start with Ghost.
Architecture
Ghost runs with:
- Ghost — the Node.js application (content editor, API, rendering)
- MySQL — the database
- Nginx (optional in compose, required for production) — reverse proxy for HTTPS
This guide uses Nginx Proxy Manager for HTTPS since you probably already have it. Ghost needs a proper domain with SSL — the admin interface and member authentication require HTTPS.
Directory Setup
mkdir -p /opt/ghost/content
Docker Compose
Create /opt/ghost/docker-compose.yml:
services:
ghost:
image: ghost:5-alpine
container_name: ghost
environment:
- url=https://yourdomain.com
- database__client=mysql
- database__connection__host=ghost-db
- database__connection__user=ghost
- database__connection__password=changeme
- database__connection__database=ghost
- mail__transport=SMTP
- mail__options__host=
- mail__options__port=587
- mail__options__auth__user=
- mail__options__auth__pass=
- [email protected]
volumes:
- /opt/ghost/content:/var/lib/ghost/content
ports:
- "2368:2368"
depends_on:
- ghost-db
restart: unless-stopped
ghost-db:
image: mysql:8.0
container_name: ghost-db
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=ghost
- MYSQL_USER=ghost
- MYSQL_PASSWORD=changeme
volumes:
- /opt/ghost/mysql:/var/lib/mysql
restart: unless-stopped
url — The full URL where Ghost will be accessible. This must be the actual public URL — Ghost uses it for generating links, sending emails, and configuring cookies. Set this to your domain before starting.
changeme — Update both database password fields.
Mail settings — Ghost uses SMTP for sending newsletters and transactional emails (password resets, welcome emails for members). Fill in your SMTP server credentials. Options:
- Mailgun — Ghost’s recommended provider, free tier available
- Postmark — good deliverability, paid
- Gmail SMTP — use an app password, works for low volume
- Self-hosted mail — if you run your own mail server
Leave mail blank to skip email features initially — Ghost works without it but members won’t receive newsletters or confirmation emails.
Start Ghost
cd /opt/ghost
docker compose up -d
Ghost takes 30–60 seconds to start while it initializes the database. Watch the logs:
docker logs ghost -f
When you see Ghost is running in production..., it’s ready.
Nginx Proxy Manager Setup
In NPM, add a proxy host:
- Domain:
yourdomain.com - Scheme:
http - Forward Host: Your server IP
- Forward Port:
2368 - SSL: Request Let’s Encrypt certificate, enable Force SSL
First-Time Setup
Access your Ghost site at https://yourdomain.com.
Go to https://yourdomain.com/ghost to access the admin interface. Ghost runs a setup wizard for the first login — create your admin account.
The admin panel is at https://yourdomain.com/ghost. From here:
- Posts — write and publish blog posts
- Pages — static pages (About, Contact, etc.)
- Members — manage subscribers and membership tiers
- Settings — site configuration, design, integrations
Writing a Post
Click New Post. The editor is split — left side is your content, right side is metadata (tags, featured image, excerpt, publish settings).
Ghost uses a card-based Markdown editor. Type / to insert a card — images, embedded content, HTML, code blocks. Standard Markdown works inline.
Click Publish > Publish when the post is ready. Ghost shows it immediately on your site.
Membership and Newsletter Setup
Ghost has native membership support — readers can subscribe (free or paid) and receive newsletters.
Enable memberships: Settings > Access > Allow free members
Configure newsletter: Settings > Email Newsletter > set your newsletter name and sender email
When a reader subscribes, Ghost sends a confirmation email (requires SMTP configured). Confirmed subscribers receive your newsletter posts when you send them.
For paid memberships, Ghost integrates with Stripe. Configure under Settings > Membership > Connect with Stripe.
Custom Theme
Ghost ships with the Casper theme (clean, minimal — fine for most blogs). To change themes:
Appearance > Themes > Upload theme — you can upload a .zip file from the Ghost marketplace or from GitHub.
Custom theme development uses Handlebars templates. The Ghost documentation is thorough if you want to build your own.
Backups
Back up the content directory and database:
# Database dump
docker exec ghost-db mysqldump -u ghost -pchangeme ghost > /backup/ghost-db-$(date +%Y%m%d).sql
# Content directory (images, themes, settings)
tar -czf /backup/ghost-content-$(date +%Y%m%d).tar.gz /opt/ghost/content/
The content directory contains uploaded images, themes, and exported content. The database contains your posts, members, and settings.
Ghost also has a built-in JSON export: Settings > Labs > Export your content. This downloads a JSON file with all your posts and settings — useful as a lightweight snapshot and for migrating to another Ghost instance.
Updating
Ghost releases regularly. Check Ghost releases before updating — Ghost is good about noting when updates require data migration steps.
cd /opt/ghost
docker compose pull
docker compose up -d
Ghost 5.x has been stable for major version purposes. Minor and patch updates are generally safe to pull automatically via Watchtower.