Skip to content

Ghost Performance Optimization — Caching, Image Optimization and CDN

DodaTech Updated 2026-06-28 9 min read

In this tutorial, you'll learn how to optimize Ghost for performance — configuring caching at the Nginx reverse proxy level, optimizing images with Ghost's built-in sharp pipeline, setting up a CDN, and tuning server settings for high traffic.

What You'll Learn

  • Performance bottlenecks in Ghost sites
  • Nginx caching configuration
  • Image optimization with Ghost's sharp library
  • CDN setup for static assets
  • Database query optimization
  • Node.js process tuning
  • Caching strategies: browser, server, CDN
  • Performance monitoring and testing
  • Ghost(Pro) built-in performance features

Why It Matters

Speed directly impacts user experience, SEO rankings, and conversion rates. A one-second delay in page load time can reduce conversions by 7%. Ghost is already fast out of the box — server-rendered, minimal JavaScript, clean HTML. But as your site grows, you need caching, image optimization, and CDN distribution to maintain speed under load. Performance optimization is not optional for a professional site.

Real-World Use

A news site using Ghost gets featured on a popular newsletter, driving 10x normal traffic. Without caching, the Node.js server struggles and some requests time out. The team had previously configured Nginx caching with a 5-minute TTL and set up Cloudflare CDN. When the traffic spike hits, 90% of requests are served from cache or CDN, the Node.js server handles the remaining 10% easily, and the site stays fast.

Learning Path

flowchart LR
  A["Structured Data"] --> B["Performance Optimization
You are here"]:::current B --> C["Advanced Configuration"] C --> D["Database Management"] classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px

Performance Architecture

A well-optimized Ghost site has multiple caching layers:

flowchart LR
  A["Visitor"] --> B["CDN (Cloudflare/Fastly)"]
  B --> C["Nginx Reverse Proxy"]
  C --> D["Ghost Node.js"]
  D --> E["MySQL Database"]

  B -.->|"Cache hit"| A
  C -.->|"Cache hit"| A

  style B fill:#4ade80,color:#0f172a
  style C fill:#38bdf8,color:#0f172a

Layer 1: Image Optimization

Images are typically the largest assets on a page. Ghost uses the sharp library to process images.

What Ghost Does Automatically

  • Compresses JPEG and PNG on upload
  • Generates multiple size variants (xs, s, m, l, xl)
  • Strips EXIF metadata
  • Supports WebP output

Optimizing Images Before Upload

Practice Impact
Resize to max 2000px width Reduces file size 50-80%
Compress JPEG to 80-85% quality Minimal visual loss, 50% smaller
Use PNG only for screenshots with text Photos should always be JPEG
Convert to WebP 25-35% smaller than JPEG
Use descriptive filenames Helps CDN caching

Using Image Sizes in Themes

<!-- Use smallest appropriate size -->
<img src="{{img_url feature_image size="s"}}" alt="{{title}}">
<img src="{{img_url feature_image size="m"}}" alt="{{title}}">

<!-- WebP format -->
<img src="{{img_url feature_image format="webp"}}" alt="{{title}}">

Image CDN

Move image storage to an S3-compatible service and serve via CDN:

{
  "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"
    }
  }
}

Layer 2: Nginx Caching

The Ghost CLI sets up Nginx as a reverse proxy. Configure caching to serve repeat requests without hitting the Node.js process.

Basic Nginx Cache Configuration

# In /etc/nginx/sites-available/yoursite.com

# Define cache zone
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=ghost_cache:10m max_size=1g inactive=60m;

server {
    listen 443 ssl http2;
    server_name yoursite.com;

    # SSL config...

    location / {
        proxy_cache ghost_cache;
        proxy_cache_key "$scheme$request_method$host$request_uri";
        proxy_cache_valid 200 5m;
        proxy_cache_valid 404 1m;
        proxy_cache_use_stale error timeout updating;

        add_header X-Cache-Status $upstream_cache_status;

        proxy_pass http://127.0.0.1:2368;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # Cache static assets aggressively
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        proxy_pass http://127.0.0.1:2368;
    }
}

Cache Headers

Check if caching works by looking for X-Cache-Status in the response headers:

  • HIT — Served from cache
  • MISS — Not in cache, fetched from Ghost
  • EXPIRED — Was in cache but expired, refetched

Cache Invalidation

When content is updated in Ghost admin, the cache is not automatically invalidated. You need to:

  1. Restart Nginx to clear its cache:
sudo nginx -s reload
  1. Or purge the cache directory:
sudo rm -rf /var/cache/nginx/*

For automatic invalidation, use a webhook that triggers cache purge.

Layer 3: CDN

A CDN (Content Delivery Network) distributes your site to servers worldwide, reducing latency for international visitors.

Cloudflare Setup

  1. Add your site to Cloudflare.
  2. Update your domain's nameservers to Cloudflare.
  3. Configure SSL to Full (Strict).
  4. Enable Auto Minify for HTML, CSS, and JS.
  5. Enable Brotli compression.
  6. Set caching level to "Standard."

Fastly (Ghost(Pro))

Ghost(Pro) uses Fastly as its CDN. It is pre-configured for optimal Ghost performance.

Custom CDN for Images

If you use S3 storage, you can serve images from a CDN:

{
  "storage": {
    "active": "ghost-s3",
    "ghost-s3": {
      "assetHost": "https://d1abc2def3gh4.cloudfront.net"
    }
  }
}

Layer 4: Database Optimization

MySQL Performance

-- Check slow queries
SHOW FULL PROCESSLIST;

-- Optimize tables
OPTIMIZE TABLE posts;
OPTIMIZE TABLE members;

-- Add indexes for common queries
ALTER TABLE posts ADD INDEX idx_published_at (published_at);

Connection Pool

{
  "database": {
    "client": "mysql",
    "connection": { ... },
    "pool": {
      "min": 2,
      "max": 10
    }
  }
}

Query Caching

Ghost uses knex.js for database queries. Enable query caching in MySQL:

# /etc/mysql/conf.d/ghost.cnf
[mysqld]
query_cache_type = 1
query_cache_size = 64M
query_cache_limit = 2M

Layer 5: Node.js Tuning

Memory

Ensure your server has enough RAM. Ghost with Node.js typically needs:

Traffic RAM
Low (< 1K visits/day) 1 GB
Medium (1K-10K visits/day) 2 GB
High (10K-100K visits/day) 4 GB+

Clustering with PM2

For multi-core servers, run Ghost in cluster mode:

pm2 start index.js -i max

This creates one Node.js process per CPU core.

Performance Monitoring

Tools

Tool Purpose
Google PageSpeed Insights Overall performance score
WebPageTest Detailed Waterfall analysis
Lighthouse Performance, Accessibility, SEO audit
GTmetrix Performance grading
Ghost logs content/logs/ for server errors

Key Metrics

Metric Target
First Contentful Paint (FCP) < 1.5s
Largest Contentful Paint (LCP) < 2.5s
First Input Delay (FID) < 100ms
Cumulative Layout Shift (CLS) < 0.1
Time to Interactive (TTI) < 3.5s

Ghost(Pro) Performance

If you use Ghost(Pro), many performance optimizations are handled for you:

  • Fastly CDN pre-configured
  • Image optimization on upload
  • Automatic caching
  • Server scaling
  • Built-in monitoring

Common Mistakes

  1. Not configuring Nginx caching: Default Ghost installation has Nginx as a reverse proxy but no caching configured. Every request hits the Node.js process. Enable proxy_cache for 10x performance improvement.

  2. Uploading unoptimized images: A 5 MB photo uploaded directly from a camera slows down every page load. Resize to 2000px max width and compress before uploading. Ghost does compress images, but pre-optimization saves bandwidth and processing time.

  3. Skipping CDN setup: Without a CDN, visitors far from your server experience high latency. Cloudflare offers a free tier that provides CDN, SSL, and DDoS protection.

  4. Using too many external scripts: Each analytics script, font loader, chat widget, and tracking pixel adds HTTP requests and JavaScript execution time. Audit third-party scripts regularly.

  5. Not testing under load: Performance under normal traffic is easy. Performance under peak traffic (launch day, viral post) requires load testing. Use tools like k6 or siege to simulate traffic spikes.

Practice Questions

  1. What are the main caching layers in an optimized Ghost setup? Answer: CDN (Cloudflare/Fastly), Nginx reverse proxy cache, browser caching (via Cache-Control headers), and database query cache. Each layer serves cached content before the request reaches the Node.js process.

  2. How does Ghost's image processing (sharp) optimize images? Answer: Ghost uses the sharp library to: compress JPEG and PNG images on upload, generate multiple resolution variants (xs through xl), strip EXIF metadata, and optionally convert to WebP format. Images can be served at the exact size needed using the img_url helper.

  3. What is the recommended Nginx proxy_cache configuration for Ghost? Answer: Set up a cache zone with proxy_cache_path, enable caching for the location block, set proxy_cache_valid 200 5m for 5-minute cache TTL, add proxy_cache_use_stale error timeout updating for serving stale content during errors, and include add_header X-Cache-Status for monitoring.

  4. Challenge: Run a full performance audit on a Ghost site. Use Google PageSpeed Insights and WebPageTest to measure current performance. Identify the top 3 performance issues. Implement fixes: configure Nginx caching, optimize the largest images, set up Cloudflare or another CDN. Re-test and document the improvement.

FAQ

Does Ghost support HTTP/2?

Yes. Ghost with Nginx supports HTTP/2, which enables multiplexed requests, header compression, and server push. HTTP/2 is enabled by the Ghost CLI's Nginx configuration when Ghost 5+ is installed.

How do I purge the Ghost cache?

Ghost does not have a built-in cache purge mechanism. Clear Nginx cache by restarting Nginx: sudo systemctl reload nginx. Clear CDN cache from your CDN dashboard (Cloudflare: Purge Cache).

Can I use Redis with Ghost?

Ghost does not use Redis for caching. Caching is handled at the Nginx and CDN level. For session storage or worker queues, you can configure Redis but it is not required for standard Ghost operation.

How many concurrent visitors can a Ghost site handle?

A well-optimized Ghost site on a 2 GB VPS with Nginx caching and a CDN can handle 10,000+ concurrent visitors. Without caching, the same server may struggle with 200 concurrent users.

Does Ghost(Pro) handle performance optimization automatically?

Yes. Ghost(Pro) includes Fastly CDN, image optimization, automatic caching, and server scaling. If performance is critical and you do not want to manage infrastructure, Ghost(Pro) is the recommended choice.

Mini Project

Your task: Optimize a Ghost site for maximum performance.

  1. Run a baseline performance audit using Google PageSpeed Insights.
  2. Configure Nginx caching with a 5-minute TTL.
  3. Resize and compress all images that are over 500 KB.
  4. Set up Cloudflare CDN and configure SSL, Minification, and caching.
  5. Verify caching headers are correct using browser developer tools.
  6. Run a load test using k6 or a similar tool.
  7. Re-run the PageSpeed audit and document all improvements.

This exercise gives you a production-ready performance optimization workflow.

What's Next

Now that performance is optimized, explore advanced configuration:

Continue to Lesson 35: Advanced Configuration — Custom routes.yaml, redirects, and collections.

Related lessons:

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro