How to Self-Host Ghost with Docker Compose
What Is Ghost?
Ghost is an open-source publishing platform built for professional bloggers, journalists, and content creators. It handles content creation, memberships, newsletters, and monetization in a single platform. Think of it as a self-hosted alternative to Substack or Medium with full control over your content and audience. Official site
Updated March 2026: Verified with latest Docker images and configurations.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 2 GB of free disk space
- 1 GB of RAM (minimum)
- A domain name (required for production use)
- SMTP credentials for transactional email (Mailgun, SendGrid, or similar)
Docker Compose Configuration
Create a docker-compose.yml file:
services:
ghost:
image: ghost:6.22.0
container_name: ghost
environment:
database__client: mysql
database__connection__host: ghost_db
database__connection__user: ghost
database__connection__password: ghost_db_password # Change this
database__connection__database: ghost_db
url: https://example.com # MUST match your actual site URL
NODE_ENV: production
# Mail configuration (required for member signups and newsletters)
# mail__transport: SMTP
# mail__options__host: smtp.mailgun.org
# mail__options__port: 587
# mail__options__auth__user: [email protected]
# mail__options__auth__pass: your-smtp-password
# mail__from: [email protected]
volumes:
- ghost_content:/var/lib/ghost/content # Themes, images, settings
ports:
- "2368:2368" # Web UI
depends_on:
ghost_db:
condition: service_healthy
restart: unless-stopped
ghost_db:
image: mysql:8.0
container_name: ghost_db
environment:
MYSQL_ROOT_PASSWORD: root_password_change_me # Change this
MYSQL_USER: ghost
MYSQL_PASSWORD: ghost_db_password # Must match above
MYSQL_DATABASE: ghost_db
volumes:
- ghost_db_data:/var/lib/mysql
restart: unless-stopped
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
volumes:
ghost_content:
ghost_db_data:
Create a .env file for sensitive values:
# Ghost database credentials
GHOST_DB_PASSWORD=change_me_to_a_strong_password
MYSQL_ROOT_PASSWORD=change_me_root_password
Start the stack:
docker compose up -d
Initial Setup
- Open
http://your-server-ip:2368/ghostto access the admin panel - Create your admin account (first user becomes the owner)
- Set your site title, description, and branding under Settings → General
- Configure your publication’s design under Settings → Design
Important: The url environment variable must exactly match the URL users will access your site at, including the protocol (https://). A mismatch causes asset loading failures and broken links.
Configuration
Email (SMTP)
Ghost needs SMTP for member signups, password resets, and newsletters. Uncomment the mail configuration in your Docker Compose and set your SMTP provider details:
environment:
mail__transport: SMTP
mail__options__host: smtp.mailgun.org
mail__options__port: 587
mail__options__secure: "true"
mail__options__auth__user: [email protected]
mail__options__auth__pass: your-api-key
mail__from: "Your Blog <[email protected]>"
Ghost supports Mailgun natively for bulk newsletter sending. Configure under Settings → Email newsletter → Mailgun.
Memberships and Subscriptions
Ghost has built-in membership and payment support:
- Free members: Collect emails, gate content behind free signup
- Paid members: Connect Stripe for paid subscriptions
- Configure tiers under Settings → Membership
Themes
Ghost uses Handlebars templates. The default Casper theme is solid, but you can:
- Install themes via Settings → Design → Change theme
- Upload
.ziptheme files - Edit the default theme files in the
content/themes/directory
Popular free themes: Casper (default), Starter, Edition, Alto.
Content API
Ghost provides two APIs:
- Content API: Read-only, for building custom frontends (headless CMS use)
- Admin API: Full CRUD, for automation and integrations
Create API keys under Settings → Integrations → Add custom integration.
Advanced Configuration (Optional)
Headless Ghost (API-only)
Ghost works well as a headless CMS. Use the Content API to fetch posts and render them with any frontend framework (Next.js, Astro, Hugo). This decouples your frontend from Ghost’s built-in themes.
Custom Redirects
Create a redirects.yaml or redirects.json file and upload via Settings → Labs → Redirects. Useful for maintaining SEO when migrating from another platform.
Bulk Email with Mailgun
For newsletters to large subscriber lists, Ghost integrates directly with Mailgun’s bulk sending API. This bypasses SMTP limits and provides delivery analytics. Configure under Settings → Email newsletter.
Reverse Proxy
Ghost must run behind a reverse proxy for production use (HTTPS is required for memberships and Stripe).
For Nginx Proxy Manager:
- Scheme:
http - Forward Hostname:
ghost(container name) or server IP - Forward Port:
2368 - Enable Websockets Support
- Request an SSL certificate via Let’s Encrypt
Ensure the url environment variable matches your domain with https://.
See Reverse Proxy Setup for detailed configuration.
Backup
Ghost stores content in two locations:
- MySQL database: All posts, members, settings, tags
- Content volume (
/var/lib/ghost/content): Themes, uploaded images, redirects
Back up both. Ghost also has a built-in export under Settings → Labs → Export content that exports posts as JSON (but not images or themes).
For database backup:
docker compose exec ghost_db mysqldump -u ghost -p ghost_db > ghost_backup.sql
See Backup Strategy for a comprehensive approach.
Troubleshooting
Ghost Shows “Site is Starting Up”
Symptom: Browser shows a loading screen that never resolves.
Fix: Check logs with docker compose logs ghost. Common causes: database not ready yet (wait for MySQL healthcheck), incorrect url environment variable, or missing database credentials.
Images Not Loading After Reverse Proxy Setup
Symptom: Pages load but images are broken (mixed content errors).
Fix: Ensure url is set to https://your-domain.com (with https://). Ghost generates image URLs based on this setting. If it says http://, images won’t load over HTTPS.
”Cannot Send Email” Errors
Symptom: Member signups fail or newsletters don’t send. Fix: Verify SMTP credentials. Test with a simple integration (Mailgun’s sandbox domain works for testing). Check that port 587 is not blocked by your hosting provider. Some providers block outbound SMTP — use an API-based email service instead.
Database Connection Refused
Symptom: Ghost logs show “ECONNREFUSED” for MySQL.
Fix: Ensure ghost_db container is healthy before Ghost starts. The depends_on with condition: service_healthy in the Docker Compose handles this. If the database was just created, give it a minute to initialize.
High Memory Usage
Symptom: Ghost consuming 500+ MB of RAM.
Fix: Ghost runs on Node.js, which pre-allocates memory. This is normal for a Node.js application. For memory-constrained servers, add node__env: production (already set in our config) and avoid running Ghost’s background jobs too frequently.
Resource Requirements
- RAM: 512 MB idle, 800 MB-1 GB under moderate traffic
- CPU: Low to moderate (Node.js single-threaded)
- Disk: ~200 MB for the application, plus uploads and database
Verdict
Ghost is the best self-hosted option for professional publishing and newsletter platforms. Its editor is excellent, the membership system is built-in (no plugins needed), and it’s fast. If you’re building a publication, newsletter, or content business, Ghost beats WordPress on simplicity and performance. WordPress wins on extensibility and plugin ecosystem. For a blog that “just works” with modern features, Ghost is the clear choice.
FAQ
Ghost vs WordPress — which should I self-host?
Ghost is purpose-built for publishing — it’s faster, simpler, and has built-in memberships. WordPress is more flexible with thousands of plugins but requires more maintenance. See our Ghost vs WordPress comparison for details.
Can I migrate from WordPress to Ghost?
Yes. Ghost has a WordPress migration plugin under Settings → Labs → Migration. It imports posts, tags, and authors. Images need to be migrated separately (exported from WordPress uploads directory).
Is Ghost free to self-host?
Ghost is open source (MIT license) and free to self-host. Ghost(Pro) is the paid hosted version. Self-hosting gives you the same software without monthly fees, but you’re responsible for hosting, backups, and updates.
Related
- Self-Hosted Blog Setup Guide
- Headless CMS Comparison Guide
- Ghost Docker: Migration Issues — Fix
- Ghost vs Medium: Self-Host or Use a Platform?
- Ghost vs Strapi: CMS Showdown
- How to Self-Host WordPress
- Ghost vs WordPress
- Ghost vs Hugo
- Ghost vs Directus
- Best Self-Hosted CMS Platforms
- Docker Compose Basics
- Reverse Proxy Setup
- Backup Strategy
- How to Self-Host Nginx Proxy Manager
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments