Ghost Monitoring and Logging — Track Site Health, Errors and Alerts
In this tutorial, you'll learn how to monitor Ghost CMS — reading and interpreting Ghost logs, setting up uptime monitoring with external services, configuring error alerts via email or Slack, tracking performance metrics over time, and debugging common issues using log analysis.
What You'll Learn
- Ghost log structure and location
- Reading and filtering Ghost logs
- Setting up uptime monitoring (Pingdom, UptimeRobot)
- Error alerting via email, Slack, and webhooks
- Performance metrics monitoring (response time, memory usage)
- Database query monitoring
- Ghost Health API endpoint
- Using PM2 for process monitoring
- Setting up log rotation
- Debugging common errors using logs
- Creating a monitoring dashboard
Why It Matters
You cannot fix what you cannot see. Without monitoring, your site could be down for hours before you notice. Ghost logs contain the first clues when something goes wrong — a database connection failure, a memory limit exceeded, a theme error. A proper monitoring setup notifies you within minutes of an issue and provides the log data needed to diagnose and fix it quickly.
Real-World Use
A Ghost site starts returning 502 Bad Gateway errors at 3 AM. The admin receives an email alert from UptimeRobot within 2 minutes. They check the Ghost logs and find: "Error: connect ECONNREFUSED 127.0.0.1:3306." The MySQL service stopped due to an out-of-memory condition. The admin restarts MySQL, the site comes back up, and they add MySQL to the monitoring system so it auto-restarts next time.
Learning Path
flowchart LR A["Security"] --> B["Monitoring & Logging
You are here"]:::current B --> C["Production Deployment"] C --> D["Course Complete"] classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px
Ghost Log Structure
Log Locations
| Log | Path | Purpose |
|---|---|---|
| Ghost application log | content/logs/<filename>.log |
Ghost process logs |
| Nginx access log | /var/log/nginx/access.log |
HTTP request log |
| Nginx error log | /var/log/nginx/error.log |
Nginx-level errors |
| MySQL log | /var/log/mysql/error.log |
Database errors |
| System log | /var/log/syslog |
System-level events |
Log Format
Ghost logs follow this format:
[YYYY-MM-DD HH:MM:SS] LEVEL: Message
[2026-06-28 14:30:15] INFO: Ghost is running in production mode
[2026-06-28 14:30:16] INFO: Ghost is using MySQL database
[2026-06-28 14:30:18] INFO: Ghost server started on http://127.0.0.1:2368
Log Levels
| Level | Meaning | Example |
|---|---|---|
| INFO | Normal operation | Server started, migration complete |
| WARN | Potential issue | Slow query, deprecated API call |
| ERROR | Operation failed | Database connection failed |
| FATAL | Process stopping | Out of memory, critical config error |
Reading and Filtering Logs
Basic Log Reading
# View last 50 lines
ghost log --tail 50
# View logs in real time
ghost log --tail
# View errors only
ghost log errors --tail 20
# View specific date range
ghost log --since "2026-06-27" --until "2026-06-28"
Advanced Filtering with grep
# Find all database errors
grep "database" content/logs/*.log
# Find all 5xx errors
grep "ERROR" content/logs/*.log
# Find memory-related issues
grep -i "memory|heap|allocation" content/logs/*.log
# Count error types
grep -c "ERROR" content/logs/*.log
grep -c "WARN" content/logs/*.log
Log Analysis Script
#!/bin/bash
# analyze-ghost-logs.sh
LOG_DIR="/var/www/ghost/content/logs"
echo "=== Ghost Log Analysis ==="
echo "Date: $(date)"
echo ""
# Count log entries by level
echo "Log entries by level:"
grep -c "\[INFO\]" $LOG_DIR/*.log 2>/dev/null || echo " No INFO entries"
grep -c "\[WARN\]" $LOG_DIR/*.log 2>/dev/null || echo " No WARN entries"
grep -c "\[ERROR\]" $LOG_DIR/*.log 2>/dev/null || echo " No ERROR entries"
grep -c "\[FATAL\]" $LOG_DIR/*.log 2>/dev/null || echo " No FATAL entries"
# Find recent errors
echo ""
echo "Recent errors (last 24h):"
grep "ERROR" $LOG_DIR/*.log 2>/dev/null | tail -10
# Check for specific issues
echo ""
echo "Database issues:"
grep -i "database\|mysql\|sqlite\|connection" $LOG_DIR/*.log 2>/dev/null | tail -5
Uptime Monitoring
Using UptimeRobot
- Create a free UptimeRobot account
- Add a new monitor:
- Monitor Type: HTTP(S)
- URL:
https://yoursite.com - Interval: 5 minutes
- Alert Contacts: Email, Slack, or SMS
Using Pingdom
- Create a Pingdom account
- Add a new check:
- URL:
https://yoursite.com - Check frequency: 1 minute
- Alert when down for: 1 minute
- Integrations: Email, Slack, PagerDuty
- URL:
Self-Hosted Monitoring with Upptime
Upptime is an open-source uptime monitor that runs on GitHub Actions:
# .upptimerc.yml
sites:
- name: Ghost Production
url: https://yoursite.com
- name: Ghost Admin
url: https://yoursite.com/ghost/
status-website:
baseUrl: /status
logoUrl: https://yoursite.com/favicon.png
name: Ghost Site Status
Error Alerting
Email Alerts via Ghost Health Endpoint
Ghost provides a health check endpoint:
# Simple health check script
#!/bin/bash
URL="https://yoursite.com"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL)
if [ "$STATUS" != "200" ]; then
echo "Site is down! Status: $STATUS" | \
mail -s "ALERT: Ghost Site Down" admin@yoursite.com
fi
Slack Alerts
#!/bin/bash
# slack-alert.sh
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
URL="https://yoursite.com"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL)
if [ "$STATUS" != "200" ]; then
curl -X POST -H "Content-type: application/json" \
--data "{\"text\":\"ALERT: Ghost site ($URL) returned status $STATUS\"}" \
$SLACK_WEBHOOK
fi
Schedule with cron:
*/5 * * * * /home/ghost/scripts/slack-alert.sh
Webhook-Based Alerts
Use Ghost's own webhooks to trigger alerts on specific events:
- Go to Settings → Integrations → Add Custom Integration
- Create webhooks for:
post.added— notify when new content is publishedmember.added— track member growthsubscription.created— monitor revenue events
Performance Metrics Monitoring
Response Time Monitoring
#!/bin/bash
# monitor-response-time.sh
URL="https://yoursite.com"
LOG_FILE="/var/log/ghost/response-times.log"
TIME=$(curl -s -o /dev/null -w "%{time_total}" $URL)
echo "$(date +%Y-%m-%dT%H:%M:%S) $TIME" >> $LOG_FILE
# Alert if response time exceeds 2 seconds
if (( $(echo "$TIME > 2.0" | bc -l) )); then
echo "ALERT: Response time $TIME seconds exceeds threshold of 2s" | \
mail -s "Ghost Performance Alert" admin@yoursite.com
fi
Monitoring Memory and CPU
#!/bin/bash
# monitor-system.sh
LOG_FILE="/var/log/ghost/system-stats.log"
THRESHOLD_MEM=80 # Alert at 80% memory usage
THRESHOLD_CPU=90 # Alert at 90% CPU usage
MEM_USAGE=$(free | grep Mem | awk '{print int($3/$2 * 100)}')
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print int($2)}')
DISK_USAGE=$(df -h / | tail -1 | awk '{print int($5)}')
echo "$(date +%Y-%m-%dT%H:%M:%S) MEM:$MEM_USAGE% CPU:$CPU_USAGE% DISK:$DISK_USAGE%" \
>> $LOG_FILE
# Alert checks
if [ $MEM_USAGE -gt $THRESHOLD_MEM ]; then
echo "ALERT: Memory usage at $MEM_USAGE% exceeds threshold" | \
mail -s "Ghost Memory Alert" admin@yoursite.com
fi
if [ $DISK_USAGE -gt 90 ]; then
echo "ALERT: Disk usage at $DISK_USAGE% — action required!" | \
mail -s "Ghost Disk Alert" admin@yoursite.com
fi
PM2 Monitoring
If you run Ghost with PM2, use PM2's built-in monitoring:
# Monitor Ghost process
pm2 monit
# List all processes with resource usage
pm2 list
# Show detailed process info
pm2 show ghost
# Set up PM2 auto-restart on crash
pm2 start index.js --name ghost --max-memory-restart 512M
Ghost Health API
Ghost exposes a health-check endpoint:
curl https://yoursite.com/ghost/api/admin/site/
Response:
{
"site": {
"version": "5.80.0",
"status": "healthy"
}
}
You can also check the database status:
curl https://yoursite.com/ghost/api/admin/db/
Log Rotation
Without log rotation, log files grow indefinitely and fill the disk.
Configuring logrotate
Create /etc/logrotate.d/ghost:
/var/www/ghost/content/logs/*.log {
weekly
rotate 4
compress
delaycompress
missingok
notifempty
copytruncate
}
For Nginx logs:
/var/log/nginx/*.log {
weekly
rotate 12
compress
delaycompress
missingok
notifempty
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
Test logrotate configuration:
sudo logrotate -d /etc/logrotate.d/ghost
Creating a Monitoring Dashboard
Using Netdata
Netdata provides real-time monitoring with a web dashboard:
# Install Netdata
bash <(curl -Ss https://my-netdata.io/kickstart.sh)
# Access dashboard
# http://yoursite.com:19999/
Using Grafana + Prometheus
For advanced monitoring, set up Prometheus to collect metrics and Grafana for visualization:
- Install Prometheus Node Exporter on the server
- Configure Prometheus to scrape Ghost metrics
- Set up Grafana with a Ghost monitoring dashboard
- Configure alert rules in Grafana
Debugging Common Errors
Ghost Won't Start
Check logs:
ghost log errors --tail 20
Common causes:
| Error | Likely Cause | Fix |
|---|---|---|
EADDRINUSE |
Port 2368 already in use | Kill the process: sudo kill $(sudo lsof -t -i:2368) |
ECONNREFUSED |
MySQL not running | Start MySQL: sudo systemctl start mysql |
ENOENT |
Missing config file | Check config.production.json exists |
Module not found |
Broken npm packages | Reinstall: npm install --production |
Site Loading Slowly
# Check Ghost process resource usage
ps aux | grep ghost
# Check MySQL process list
mysql -e "SHOW FULL PROCESSLIST;"
# Check Nginx error log
tail -50 /var/log/nginx/error.log
# Check available memory
free -h
502 Bad Gateway
This means Nginx cannot reach the Ghost process:
# Check if Ghost is running
ghost status
# Check if Ghost is listening on correct port
ss -tlnp | grep 2368
# Check Nginx error log
tail -20 /var/log/nginx/error.log
Common Mistakes
Not monitoring at all: Many Ghost sites have no monitoring setup. The first sign of trouble is a user email or a tweet. Set up at least basic uptime monitoring with email alerts before going live.
Ignoring warning-level logs: WARN entries are often the first indicator of a developing problem. A slow query warning today becomes a timeout error next week. Investigate warnings before they become errors.
Not setting up log rotation: Ghost logs can grow to gigabytes over time. Without log rotation, logs fill the disk, which causes Ghost to crash because it cannot write new log entries.
Checking logs only during incidents: Logs are most useful when you know what normal looks like. Review logs regularly (weekly automation) so you recognize anomalies quickly when they appear.
Using only one monitoring tool: Uptime monitoring tells you the site is down, but not why. Combine uptime monitoring (is the site accessible?) with log monitoring (what errors are occurring?) and system monitoring (CPU, memory, disk).
Alert fatigue from poorly tuned thresholds: Setting alert thresholds too low generates false alarms. Setting them too high misses real issues. Tune thresholds based on baseline data collected during the first month of operation.
Practice Questions
Where does Ghost store its log files and what formats do they use? Answer: Ghost stores logs in
content/logs/with filenames like<timestamp>.log. The format is:[YYYY-MM-DD HH:MM:SS] LEVEL: Message. Levels include INFO (normal), WARN (potential issue), ERROR (operation failed), and FATAL (process stopping).How do you set up automated uptime monitoring for a Ghost site? Answer: Use an external monitoring service like UptimeRobot or Pingdom to check the site URL at regular intervals (e.g., every 5 minutes). Configure alerts via email, Slack, or SMS when the site returns a non-200 status code. Optionally add multi-location checks to verify global availability.
What is log rotation and why is it necessary for Ghost? Answer: Log rotation automatically archives and compresses old log files to prevent them from consuming unlimited disk space. Without it, Ghost logs can grow to gigabytes, fill the server disk, and cause Ghost to crash. Tools like logrotate handle this with weekly/daily rotation and retention policies.
Challenge: Build a complete Ghost monitoring system. Set up: uptime monitoring with UptimeRobot or similar, Slack/email alerts for downtime, a system resource monitor that checks CPU, memory, and disk usage every 5 minutes, logwatch-style daily log summary emailed to the admin, and a Grafana dashboard showing response time trends.
FAQ
Mini Project
Your task: Implement a complete monitoring and logging system for a Ghost production site.
- Set up uptime monitoring with email and Slack alerts using a free service (UptimeRobot or similar).
- Create a system resource monitor script that checks CPU, memory, and disk usage every 5 minutes.
- Configure logrotate for both Ghost logs and Nginx logs.
- Create a daily log summary script that emails key statistics (error count, unique errors, warnings).
- Set up a health check endpoint monitoring script.
- Create a simple monitoring dashboard with response time trends.
- Write a troubleshooting guide based on common error patterns in Ghost logs.
- Document the alert thresholds and escalation procedures.
This exercise gives you a production-grade monitoring and alerting system.
What's Next
Now that monitoring is in place, learn about production deployment:
Continue to Lesson 40: Production Deployment — Deploy Ghost for scale and reliability.
Related lessons:
- Security — Hardening and protection
- Advanced Configuration — Custom routes and redirects
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro