Ghost Production Deployment — Scale, Reliability and Maintenance
In this tutorial, you'll learn how to deploy Ghost CMS in production — provisioning production-grade servers, configuring high availability with failover, scaling Ghost horizontally with load balancers, disaster recovery planning, and establishing long-term maintenance procedures.
What You'll Learn
- Production server provisioning and sizing
- High-availability architecture for Ghost
- Load balancing multiple Ghost instances
- Horizontal scaling strategies
- Disaster recovery planning
- Backup and restore procedures
- CI/CD deployment pipelines
- Staging and production environments
- SSL certificate management at scale
- Long-term maintenance schedules
- Ghost(Pro) vs self-hosted comparison
- Migration strategies for scaling up
Why It Matters
A development Ghost setup is not a production setup. Production means reliability, scalability, and recoverability. When your site grows from 100 to 100,000 daily visitors, the architecture that worked for development will fail. Proper production deployment ensures your site stays fast, available, and recoverable regardless of traffic spikes or infrastructure failures.
Real-World Use
A media company's Ghost site is featured on a major news aggregator, driving 50,000 concurrent visitors. Their architecture includes: two application servers behind an Nginx load balancer, a managed MySQL database with read replicas, S3 storage for images, Cloudflare CDN, and automated CI/CD deploys. The traffic spike causes CPU to rise to 60% on both app servers, but with load balancing and CDN caching, 95% of requests never reach the application. The site stays fast and no downtime occurs.
Learning Path
flowchart LR A["Monitoring & Logging"] --> B["Production Deployment
You are here"]:::current B --> C["Ghost CMS Course Complete"] classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px
Server Provisioning
Minimum Production Server
| Spec | Requirement |
|---|---|
| CPU | 2 cores (4 recommended) |
| RAM | 2 GB (4 GB recommended) |
| Storage | 40 GB SSD |
| OS | Ubuntu 22.04 LTS |
| Node.js | 18.x LTS |
| Database | MySQL 8.0+ |
Recommended Production Server
| Spec | Small Site | Medium Site | Large Site |
|---|---|---|---|
| CPU | 2 cores | 4 cores | 8+ cores |
| RAM | 4 GB | 8 GB | 16+ GB |
| Storage | 80 GB SSD | 160 GB SSD | 320 GB+ SSD |
| DB | SQLite | MySQL (same server) | MySQL (dedicated) |
| Visitors/day | < 1,000 | 1,000-10,000 | 10,000+ |
Cloud Provider Options
| Provider | Recommended For | Example Spec |
|---|---|---|
| DigitalOcean | Small to medium | Premium Droplet $48/mo (4 GB, 2 CPU, 80 GB) |
| Linode | Small to medium | Dedicated 4 GB $36/mo |
| AWS | Large, scalable | t3.medium + RDS db.t3.small |
| Vultr | Medium | High Frequency 4 GB $40/mo |
High-Availability Architecture
Single-Server HA (Basic)
flowchart LR A["Cloudflare CDN"] --> B["Nginx + Ghost"] B --> C["MySQL"] B --> D["S3 Storage"] style A fill:#4ade80,color:#0f172a style D fill:#38bdf8,color:#0f172a
Multi-Server HA (Advanced)
flowchart LR A["Cloudflare CDN"] --> B["Nginx Load Balancer"] B --> C["Ghost Instance 1"] B --> D["Ghost Instance 2"] C --> E["MySQL Primary"] D --> E C --> F["S3 Storage"] D --> F E --> G["MySQL Replica"] style A fill:#4ade80,color:#0f172a style F fill:#38bdf8,color:#0f172a
Load Balancer Configuration
# /etc/nginx/nginx.conf
upstream ghost_cluster {
least_conn;
server 10.0.0.1:2368 max_fails=3 fail_timeout=30s;
server 10.0.0.2:2368 max_fails=3 fail_timeout=30s;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name yoursite.com;
location / {
proxy_pass http://ghost_cluster;
proxy_http_version 1.1;
proxy_set_header Connection "";
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;
}
}
Session Persistence
Ghost uses stateless sessions by default, so load balancer requests can go to any backend instance. No sticky sessions are required.
Horizontal Scaling
Shared Storage
For multiple Ghost instances, use shared storage for images:
{
"storage": {
"active": "ghost-s3",
"ghost-s3": {
"accessKeyId": "YOUR_KEY",
"secretAccessKey": "YOUR_SECRET",
"region": "us-east-1",
"bucket": "my-ghost-images",
"assetHost": "https://cdn.yoursite.com"
}
}
}
Shared Database
All Ghost instances point to the same MySQL database:
{
"database": {
"client": "mysql",
"connection": {
"host": "database.yoursite.com",
"port": 3306,
"user": "ghost_user",
"password": "your-password",
"database": "ghost_production"
}
}
}
Auto-Scaling
For cloud providers, set up auto-scaling rules:
| Trigger | Action |
|---|---|
| CPU > 70% for 5 minutes | Add 1 instance |
| CPU < 30% for 10 minutes | Remove 1 instance |
| Memory > 80% for 5 minutes | Add 1 instance |
Disaster Recovery
Recovery Plan
A complete disaster recovery plan covers these scenarios:
| Scenario | RTO | RPO | Recovery Action |
|---|---|---|---|
| Application crash | 5 minutes | 0 | PM2 auto-restart |
| Server failure | 30 minutes | 5 minutes | Restore from backup to new server |
| Database corruption | 1 hour | 1 hour | Restore from latest backup |
| Full region outage | 4 hours | 24 hours | Deploy to secondary region |
| Accidental content deletion | 1 hour | 24 hours | Restore content from backup |
Recovery Steps
#!/bin/bash
# disaster-recovery.sh
# 1. Provision a new server
# 2. Install Ghost CLI and dependencies
# 3. Restore configuration
cp /backup/config.production.json /var/www/ghost/
# 4. Restore database
gunzip < /backup/latest-database.sql.gz \
| mysql --user=ghost_user --password ghost_production
# 5. Restore content
tar -xzf /backup/latest-content.tar.gz -C /var/www/ghost/
# 6. Start Ghost
cd /var/www/ghost && ghost start
# 7. Update DNS if IP changed
# 8. Verify site is operational
CI/CD Pipeline
GitHub Actions for Ghost Deployment
# .github/workflows/deploy.yml
name: Deploy Ghost
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to production
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.GHOST_HOST }}
username: ${{ secrets.GHOST_USER }}
key: ${{ secrets.GHOST_SSH_KEY }}
script: |
cd /var/www/ghost
# Backup before deploy
mysqldump --user=ghost_user --password=${{ secrets.DB_PASSWORD }} ghost_production \
| gzip > /home/ghost/backups/pre_deploy.sql.gz
# Update theme
rsync -av --delete /var/www/ghost/themes/my-theme/ /var/www/ghost/content/themes/my-theme/
# Update custom code
# Restart Ghost
ghost restart
Deployment Checklist
Before every production deployment:
- Test in staging environment
- Backup database and content
- Verify theme compatibility
- Check custom integrations
- Review release notes for breaking changes
- Schedule during low-traffic window
- Prepare rollback plan
- Notify team members
Staging Environment
Staging Architecture
# Clone production to staging
mysqldump --user=ghost_user --password ghost_production \
| mysql --user=ghost_staging --password ghost_staging
rsync -av /var/www/ghost/content/ /var/www/staging/content/
# Set up staging with different URL
cp /var/www/ghost/config.production.json /var/www/staging/config.staging.json
# Edit URL to: https://staging.yoursite.com
# Start staging
cd /var/www/staging && ghost start
Staging vs Production Differences
| Aspect | Staging | Production |
|---|---|---|
| URL | staging.yoursite.com | yoursite.com |
| Database | Copy of production (refreshed weekly) | Production data |
| SSL | Let's Encrypt | Let's Encrypt + HSTS |
| CDN | Disabled | Enabled |
| Monitoring | Basic | Full alerts |
| Disabled (preview mode) | Enabled |
Long-Term Maintenance Schedule
Daily Tasks
- Check uptime monitor alerts
- Review error logs (5-minute check)
- Verify backup cron jobs ran
Weekly Tasks
- Review Ghost logs for warning patterns
- Check disk usage trend
- Update dependencies (npm audit)
- Review analytics for traffic changes
Monthly Tasks
- Apply Ghost security patches
- Run database maintenance (OPTIMIZE, ANALYZE)
- Test backup restoration in staging
- Review SSL certificate expiry dates
- Audit user accounts and permissions
Quarterly Tasks
- Review server resource allocation
- Test disaster recovery plan
- Update Node.js version if needed
- Review CDN configuration and costs
- Audit third-party integrations
Annual Tasks
- Review hosting provider and plan
- Full security audit
- Content audit (stale posts, broken links)
- Architecture review and scaling plan
- Update emergency contact information
Ghost(Pro) vs Self-Hosted
| Aspect | Ghost(Pro) | Self-Hosted |
|---|---|---|
| Monthly cost | $25-$500+ | $10-$200+ (server + bandwidth) |
| Maintenance | Managed | You manage everything |
| Scalability | Automatic | Manual configuration |
| CDN | Fastly included | You set up |
| Backups | Automatic | You configure |
| Monitoring | Included | You set up |
| Customization | Limited to theme/API | Full server control |
| Support | Priority support | Community + self |
Migrating to Ghost(Pro)
If self-hosting becomes too complex:
- Export your content from Ghost admin: Settings → Labs → Export
- Create a Ghost(Pro) account and site
- Import the JSON export file
- Set up custom domain and SSL
- Redirect your old domain to Ghost(Pro)
- Update DNS records
Common Mistakes
Using a development server for production: A 1 GB VPS with SQLite might work for a personal blog but fails under any real traffic. Size your production server based on expected traffic, not current traffic. Over-provision initially and scale down if needed.
No disaster recovery plan: Most Ghost sites have no documented recovery procedure. When the server fails at 3 AM, the admin has to figure out what to do under pressure. Write and test a disaster recovery plan before you need it.
Single point of failure: One server means one failure takes the whole site down. For critical sites, use at least two application servers behind a load balancer, a managed database, and off-server storage for images.
Skipping the staging environment: Deploying directly to production without testing in staging is the leading cause of deployment failures. Always test theme updates, configuration changes, and Ghost upgrades in staging first.
Not planning for scale: A site that works perfectly at 1,000 visitors/day may fail at 10,000. Plan for 10x your current traffic. CDN caching, database indexing, and image optimization should be in place from day one, not added during a crisis.
Practice Questions
What is the recommended production architecture for a high-traffic Ghost site? Answer: Multiple Ghost application servers behind an Nginx load balancer, a managed MySQL database with read replicas, S3-compatible storage for images served via CDN, Cloudflare for edge caching and DDoS protection, and CI/CD pipeline for automated deployments with a staging environment.
How do you handle session persistence with multiple Ghost instances? Answer: Ghost uses stateless sessions by default, so no sticky sessions are needed. Each Ghost instance independently authenticates requests using the same database. The load balancer can distribute requests to any backend instance using round-robin or least-connections algorithm.
What is the difference between RTO and RPO in disaster recovery? Answer: RTO (Recovery Time Objective) is the maximum acceptable downtime — how long until the site is back online. RPO (Recovery Point Objective) is the maximum acceptable data loss — how much data you can afford to lose. For a blog, RTO of 1 hour and RPO of 24 hours may be acceptable. For an e-commerce site, RTO of 5 minutes and RPO of 0 may be required.
Challenge: Design and implement a full production Ghost deployment. Provision servers with the recommended specs, configure Nginx load balancing with health checks, set up S3 storage for images with CDN, create a CI/CD pipeline with staging environment, write a disaster recovery plan with tested recovery steps, and set up automated monitoring with alerts. Document the entire architecture.
FAQ
Mini Project
Your task: Design and document a complete production deployment plan for a Ghost site.
- Design the architecture: single-server vs multi-server, load balancing, CDN, storage.
- Provision servers with appropriate sizing for expected traffic.
- Set up CI/CD pipeline with staging environment.
- Configure high availability (load balancer, health checks, auto-restart).
- Implement disaster recovery plan with tested procedures.
- Create a long-term maintenance schedule (daily, weekly, monthly, quarterly, annual).
- Document everything: architecture diagram, deployment steps, recovery procedures, runbook.
- Test the full deployment: provision from scratch, deploy, scale up, handle failure, recover.
This exercise completes your Ghost CMS training and prepares you to run Ghost at any scale.
Course Complete
Congratulations! You have completed the 40-lesson Ghost CMS tutorial series. You now have a comprehensive understanding of Ghost, from installation and content creation to theme development, membership management, API integration, and production deployment.
What You Have Learned
| Module | Topics |
|---|---|
| Fundamentals | Ghost architecture, CLI, editor, installation, configuration |
| Content Management | Posts, pages, tags, authors, media, content organization |
| Theme Development | Handlebars, assets, custom themes, theme customization |
| Memberships | Subscription system, content gating, newsletters, member management |
| APIs | Content API, Admin API, Webhooks, custom integrations, headless Ghost |
| SEO & Performance | SEO settings, sitemaps, analytics, structured data, caching |
| Advanced | routes.yaml, database management, upgrades |
| Production | Security, monitoring, production deployment |
Next Steps
- Build a real Ghost site from scratch using everything you have learned
- Explore the Ghost marketplace for premium themes and integrations
- Join the Ghost community forum for support and networking
- Consider Ghost(Pro) for managed hosting if you prefer not to self-host
Return to the Ghost CMS Tutorials to start a different topic or review any lesson.
Related tutorials:
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro