Ghost
Self-hosted Ghost blog and newsletter platform, Docker installation with MySQL and Nginx reverse proxy
Ghost is a modern, performance-focused blogging and newsletter platform. Self-hosted Ghost provides complete control, unlimited content, and powerful newsletter capabilities without hosting fees, making it an excellent alternative to WordPress for content creators.
Requirements
- Docker and Docker Compose
- MySQL 8 or MariaDB database
- Domain name with DNS configured
- 2GB+ RAM recommended
- Port 80 and 443 accessible
Installation with Docker Compose
Create docker-compose.yml
mkdir -p /opt/ghost && cd /opt/ghost
nano docker-compose.ymlAdd the following configuration:
version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: ghost-mysql
restart: always
volumes:
- mysql_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: change_me_secure_password
MYSQL_DATABASE: ghost
MYSQL_USER: ghost
MYSQL_PASSWORD: change_me_ghost_password
ports:
- "127.0.0.1:3306:3306"
ghost:
image: ghost:5-alpine
container_name: ghost-blog
restart: always
depends_on:
- mysql
ports:
- "127.0.0.1:2368:2368"
volumes:
- ghost_content:/var/lib/ghost/content
environment:
NODE_ENV: production
url: https://yourdomain.com
database__client: mysql
database__connection__host: mysql
database__connection__port: 3306
database__connection__user: ghost
database__connection__password: change_me_ghost_password
database__connection__database: ghost
mail__transport: SMTP
mail__options__service: mailgun
mail__options__auth__user: postmaster@mg.yourdomain.com
mail__options__auth__pass: your_mailgun_api_key
volumes:
mysql_data:
ghost_content:Replace yourdomain.com and all passwords with your actual values.
Start Services
docker compose up -d
docker compose logs -f ghostWait for Ghost to initialize (watch for "Ghost is running" message).
Nginx Reverse Proxy Configuration
Configure Nginx to expose Ghost on your domain with SSL:
nano /etc/nginx/sites-available/ghostAdd configuration:
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:2368;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}Enable and test:
ln -s /etc/nginx/sites-available/ghost /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginxInstall SSL Certificate
certbot certonly --standalone -d yourdomain.comInitial Setup
Access Ghost Admin
Open browser and visit https://yourdomain.com/ghost
- Create your admin account
- Add site title, description, and publication details
- Invite additional staff members if needed
Configure Site Settings
In Ghost admin panel:
- General: Site title, description, language
- Email: Sender name and address for newsletters
- Customization: Brand color, logo, favicon
- Members: Enable free and paid memberships
- Labs: Enable beta features (email, portals, etc.)
Newsletter Configuration with Mailgun
Set up email delivery for newsletters:
Get Mailgun Credentials
- Sign up at mailgun.com (free tier available)
- Add your domain
- Retrieve API key from dashboard
- Update docker-compose.yml:
environment:
mail__transport: SMTP
mail__options__service: mailgun
mail__options__auth__user: postmaster@mg.yourdomain.com
mail__options__auth__pass: your_mailgun_api_keyRestart Ghost:
docker compose down
docker compose up -dCreate Newsletter
- Go to Ghost admin → Newsletters
- Create a newsletter (free or paid)
- Add subscribers and publish newsletters from your posts
Theme Installation
Upload Custom Theme
- Go to Ghost admin → Design & Branding → Change Theme
- Upload a ZIP file of your theme
- Customize in theme settings
Use Community Themes
Download themes from ghost.org/themes and upload as ZIP.
Example popular themes: Casper (default), Alto, Edition, Aspire.
Content Management
Create Posts
- Click "New story" in editor
- Write with Markdown or rich text
- Add featured image, excerpt, tags
- Set publish date (schedule future posts)
- Choose email newsletter delivery if enabled
Create Pages
Similar to posts but not dated. Use for About, Contact, etc.
Manage Members
Enable members for:
- Free subscriptions
- Paid subscriptions
- Email delivery based on tier
- Comment sections
Backup Strategy
Backup Content Folder
# Backup Ghost content directory
docker compose exec ghost tar czf - /var/lib/ghost/content | \
gzip > ghost_content_$(date +%Y%m%d).tar.gzBackup Database
# Backup MySQL database
docker compose exec mysql mysqldump -u ghost -p'change_me_ghost_password' ghost | \
gzip > ghost_db_$(date +%Y%m%d).sql.gzComplete Backup Script
#!/bin/bash
BACKUP_DIR="/backups/ghost"
DATE=$(date +%Y%m%d)
mkdir -p $BACKUP_DIR
# Backup database
docker compose -f /opt/ghost/docker-compose.yml exec -T mysql \
mysqldump -u ghost -p'change_me_ghost_password' ghost | \
gzip > $BACKUP_DIR/ghost_db_$DATE.sql.gz
# Backup content
docker compose -f /opt/ghost/docker-compose.yml exec -T ghost \
tar czf - /var/lib/ghost/content > $BACKUP_DIR/ghost_content_$DATE.tar.gz
echo "Ghost backup completed: $BACKUP_DIR"Add to crontab for daily backups:
0 2 * * * /usr/local/bin/ghost-backup.shUpdates
Update Ghost safely:
cd /opt/ghost
# Pull latest image
docker compose pull ghost
# Stop and start (automatic database migration)
docker compose down
docker compose up -d
# Monitor startup
docker compose logs -f ghostAlways backup before updating. Test updates in staging if possible. Major version upgrades may require theme adjustments.
Performance Tips
- Enable Nginx caching for static assets
- Use a CDN for images (Cloudflare, AWS CloudFront)
- Enable members portal for engagement
- Use scheduled posts to maintain consistency
- Monitor Ghost logs for errors:
docker compose logs ghost
Important Notes
Ghost's self-hosted version is completely free. There's no licensing cost, unlike the hosted version (ghost.org). You pay only for hosting infrastructure. Ghost is optimized for fast performance and scales well on modest VPS resources.
Troubleshooting
Ghost won't start
docker compose logs ghost
docker compose down
docker compose up -dNewsletter emails not sending
Check Mailgun configuration in admin panel and verify API credentials.
Database connection error
Ensure MySQL container is running:
docker compose ps
docker compose restart mysqlPermission denied on content folder
docker compose exec ghost chown -R node:node /var/lib/ghost/content