← All Guides
intermediate

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.

Budget Homelab ·
dockerbloggingself-hosting

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:

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:

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:

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:

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:

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.