How to Self-Host Ghost CMS on a VPS: Newsletter, Membership, and Blog Without Ghost(Pro) Fees
Ghost is the leading open-source publishing platform for blogs, newsletters, and membership sites. Ghost(Pro) costs $9–$199/month depending on subscriber count. Self-hosting Ghost on a VPS eliminates the platform fee entirely — you pay only for the VPS and your email delivery service. For publications with large subscriber lists where Ghost(Pro) charges $199+/month, self-hosting saves thousands annually.
Ghost vs WordPress: When Ghost Wins
- Choose Ghost: Pure publishing focus, built-in newsletter and membership, clean editor, fast by default, native Stripe integration, no plugin maintenance
- Choose WordPress: Needs ecommerce, page builder, extensive plugin ecosystem, large team with different content types
Server Requirements
- Ubuntu 22.04 or 24.04 LTS
- Minimum 1 GB RAM (2 GB recommended for active newsletters)
- Node.js 20.x, MySQL 8.0, Nginx
- A domain with email delivery service (Mailgun, Postmark, or SendGrid)
Step 1: Install Dependencies
<code">sudo apt update && sudo apt upgrade -y # Node.js 20 LTS curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt install -y nodejs # MySQL 8.0 sudo apt install -y mysql-server sudo mysql_secure_installation # Nginx and Certbot sudo apt install -y nginx certbot python3-certbot-nginx # Ghost CLI sudo npm install -g ghost-cli node --version # Verify Node.js 20.x ghost --version # Verify Ghost CLI
Step 2: Create Ghost User and Directory
<code"># Ghost requires a non-root user sudo adduser --disabled-password --gecos "" ghost-user sudo usermod -aG sudo ghost-user # Create and own the Ghost directory sudo mkdir -p /var/www/ghost sudo chown ghost-user:ghost-user /var/www/ghost sudo chmod 775 /var/www/ghost # Switch to ghost-user for installation sudo su - ghost-user
Step 3: Create MySQL Database
<code">sudo mysql -u root -p
<code">CREATE DATABASE ghost_production CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'ghost'@'localhost' IDENTIFIED BY 'StrongGhostPassword!'; GRANT ALL PRIVILEGES ON ghost_production.* TO 'ghost'@'localhost'; FLUSH PRIVILEGES; EXIT;
Step 4: Install Ghost
<code"># As ghost-user cd /var/www/ghost ghost install \ --url https://yourdomain.com \ --db mysql \ --dbhost localhost \ --dbuser ghost \ --dbpass StrongGhostPassword! \ --dbname ghost_production \ --mail SMTP \ --mailhost smtp.mailgun.org \ --mailport 587 \ --mailuser postmaster@mg.yourdomain.com \ --mailpass your_mailgun_password \ --mailservice Mailgun \ --mailfrom noreply@yourdomain.com # Ghost CLI will: # 1. Download and install Ghost # 2. Configure Nginx with SSL (via Certbot) # 3. Set up systemd service # 4. Start Ghost ghost status # Verify running
Step 5: Manual Nginx Configuration (if needed)
<code">sudo nano /etc/nginx/sites-available/ghost
<code">server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_cache_bypass $http_upgrade;
}
}
Step 6: Configure Ghost Settings
<code">cat /var/www/ghost/config.production.json
Key settings to verify or add:
<code">{
"url": "https://yourdomain.com",
"server": {
"port": 2368,
"host": "127.0.0.1"
},
"database": {
"client": "mysql8",
"connection": {
"host": "127.0.0.1",
"port": 3306,
"user": "ghost",
"password": "StrongGhostPassword!",
"database": "ghost_production"
}
},
"mail": {
"transport": "SMTP",
"options": {
"service": "Mailgun",
"host": "smtp.mailgun.org",
"port": 587,
"auth": {
"user": "postmaster@mg.yourdomain.com",
"pass": "your_mailgun_password"
}
}
},
"imageOptimization": {
"resize": true,
"srcsets": true
},
"logging": {
"transports": ["file", "stdout"]
}
}
Step 7: Set Up Paid Memberships with Stripe
- Ghost Admin → Settings → Membership → Enable memberships
- Connect Stripe: Settings → Membership → Stripe → Connect with Stripe
- Set pricing tiers: monthly and annual subscription prices
- Customize the signup page and member portal
- Create members-only content: Posts → change Visibility to “Members only” or “Paid members only”
Step 8: Newsletter Configuration
- Ghost Admin → Settings → Email newsletter
- Configure sender name and email address
- Set up Mailgun domain authentication (SPF, DKIM) for deliverability
- Test newsletter: create a post → Email newsletter tab → Send test email
Ghost Management Commands
<code"># All commands run as ghost-user in /var/www/ghost ghost status # Check running status ghost stop # Stop Ghost ghost start # Start Ghost ghost restart # Restart Ghost ghost update # Update to latest version ghost log # View recent logs ghost config # View configuration ghost doctor # Diagnose common issues
Backup Ghost
<code"># Export content via Ghost Admin:
# Ghost Admin → Settings → Labs → Export your content (downloads JSON)
# Backup database directly
mysqldump -u ghost -p ghost_production | \
gzip > /opt/backups/ghost-db-$(date +%Y%m%d).sql.gz
# Backup uploaded images and themes
tar czf /opt/backups/ghost-content-$(date +%Y%m%d).tar.gz \
/var/www/ghost/content/
Custom Themes
<code"># Install a custom theme cd /var/www/ghost/content/themes git clone https://github.com/yourtheme/ghost-theme mytheme # Or upload via Ghost Admin: # Ghost Admin → Settings → Design → Upload a theme # Restart Ghost after theme changes ghost restart
Getting Started
Ghost on a 1–2 GB Ubuntu VPS at VPS.DO handles publications with 10,000–100,000 subscribers comfortably. The Ghost CLI automates Nginx configuration and SSL certificates. For publications currently on Ghost(Pro) at $199/month (50,000 subscribers), migrating to self-hosting on a $20/month VPS saves $2,148 annually — with full control over your data, themes, and infrastructure.
Conclusion
Self-hosted Ghost provides the full publishing platform — blog, newsletter, and paid memberships — without Ghost(Pro)’s subscriber-based pricing. The Ghost CLI makes installation and updates straightforward, Nginx and Let’s Encrypt handle SSL, Mailgun handles newsletter delivery, and Stripe handles paid subscription billing. For serious publications, self-hosting Ghost is the most cost-effective path to owning your publishing infrastructure.