Back to articles
Technology Insight

Scaling to Millions: Self-Hosting Ghost CMS with Advanced Caddy Caching on a $5 VPS

June 3, 2026

The Myth of the Expensive Tech Stack

In the modern publishing landscape, conventional wisdom suggests that scaling a blog to millions of page views requires an enterprise-level infrastructure budget. Publishers routinely flock to high-tier managed hosting providers or complex cloud architectures involving load balancers, multi-zone databases, and premium content delivery networks (CDNs). While these solutions are robust, they often introduce prohibitive costs and unnecessary operational complexity.

What if you could achieve the exact same performance, sub-second page load times, and rock-solid stability on a single $5 per month Virtual Private Server (VPS)? By pairing the lightweight, modern publishing architecture of Ghost CMS with the advanced, high-performance caching capabilities of Caddy Server, you can build a self-hosted platform capable of absorbing traffic spikes that would normally crush a standard database-driven website.

Why Ghost CMS and Caddy Server are a Power Couple

To understand why this architecture works so efficiently, we must look at the specific strengths of both technologies when handling high-volume traffic.

  • Ghost CMS: Built on Node.js, Ghost is inherently faster and less resource-intensive than traditional PHP-based platforms like WordPress. It decouples the content management administration from the front-end presentation layer, making it highly efficient at rendering pages.
  • Caddy Server: Caddy is an enterprise-grade, open-source web server written in Go. Beyond its famous automatic SSL generation via Let's Encrypt, Caddy features a highly optimized proxy and a powerful caching module (souin) that allows it to serve pre-rendered HTML directly from memory or disk, completely bypassing the Node.js application layer for anonymous visitors.
By shifting the heavy lifting from Ghost (Node.js/MySQL) to Caddy (Go-based caching compiled to native binaries), your $5 VPS transforms into an immutable content-delivery powerhouse. The application layer only wakes up when content changes or when a user logs into the dashboard.

Architectural Overview: How it Handles Millions of Views

When a reader visits your blog, the request follows a highly optimized execution path designed to minimize CPU cycles and memory usage:

  1. The Client Request: The browser requests a webpage via HTTPS.
  2. Caddy Edge Interception: Caddy intercepts the request and instantly checks its advanced cache storage.
  3. Cache Hit (The Fast Path): If the page has been requested before and hasn't expired, Caddy serves the cached HTML instantly. This process consumes negligible CPU and finishes in under 10 milliseconds. Ghost and the underlying MySQL database are never touched.
  4. Cache Miss (The Build Path): If the page is new or expired, Caddy proxies the request to Ghost. Ghost fetches the data from the local MySQL database, renders the page, and hands it back to Caddy. Caddy stores it in the cache for subsequent visitors and delivers it to the initial user.

Step-by-Step Deployment Guide

1. Server Preparation

First, provision a basic VPS (1 GB RAM, 1 vCPU) running Ubuntu 24.04 LTS from a provider like DigitalOcean, Linode, or Vultr. Update the system packages and configure a basic firewall:

sudo apt update && sudo apt upgrade -y
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

2. Installing Ghost CMS

Ghost requires Node.js, MySQL, and the Ghost-CLI tool. Install the official dependencies and initialize your blog using the official documentation guidelines. Ensure that Ghost is configured to run locally on port 2368 (binding to 127.0.0.1) so it is not publicly exposed to the internet. This ensures that all public traffic must pass through Caddy's caching layer first.

3. Compiling Caddy with the Cache Module

Standard distributions of Caddy do not come with the advanced HTTP cache module pre-installed. We will use xcaddy, Caddy's official builder tool, to compile a custom binary that includes the Souin cache module.

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf '[https://dl.cloudsmith.io/public/caddy/stable/gpg.key](https://dl.cloudsmith.io/public/caddy/stable/gpg.key)' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-archive-keyring.gpg
curl -1sLf '[https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt](https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt)' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

# Install xcaddy and build with cache module
sudo apt install go-golang -y
go install [github.com/caddyserver/xcaddy/cmd/xcaddy@latest](https://github.com/caddyserver/xcaddy/cmd/xcaddy@latest)
~/go/bin/xcaddy build --with [github.com/darkweak/souin/plugins/caddy](https://github.com/darkweak/souin/plugins/caddy)
sudo mv caddy /usr/bin/caddy
sudo systemctl restart caddy

Advanced Caddy Configuration for Ghost

Now, let's configure the Caddyfile to enable aggressive caching while completely excluding sensitive areas like the Ghost admin panel (/ghost/) and webhooks. Edit your configuration file at /etc/caddy/Caddyfile:

{
    order cache before reverse_proxy
    cache {
        ttl 3600s
        stale 60s
        key {
            method
            host
            uri
        }
    }
}

blog.yourdomain.com {
    # Exclude admin dashboard and previews from cache
    @noCache {
        path /ghost/*
        path /p/*
    }

    handle @noCache {
        reverse_proxy 127.0.0.1:2368
    }

    # Enable cache for everything else
    handle {
        cache {
            ttl 86400s
            badger {
                path /var/lib/caddy/cache
            }
        }
        reverse_proxy 127.0.0.1:2368
    }
}

This advanced configuration accomplishes several critical performance milestones:

  • Global Order definition: Instructs Caddy to evaluate caching rules before initiating a reverse proxy connection, saving valuable I/O cycles.
  • Targeted Bypassing: The @noCache block safely ensures that writers editing content or users interacting with administrative panels always see live, real-time data.
  • Persistent Storage: The badger storage engine saves the cached HTML directly to disk, preserving your cache even if the server reboots unexpectedly.

Cache Invalidation and Maintenance

One challenge with aggressive caching is ensuring that readers see updates immediately when you publish a new article. To solve this, you can utilize Ghost's native Webhooks feature. Navigate to your Ghost Settings -> Integrations -> Custom Integration, and set up a webhook to ping a cache-clear endpoint on your Caddy server whenever content is published or updated, triggering an automated cache purge.

Conclusion: Enterprise Performance on a Shoestring Budget

By leveraging Caddy Server as a reverse proxy with built-in micro-caching in front of Ghost CMS, you successfully eliminate the hardware bottlenecks associated with traditional dynamic content management systems. Your database sits comfortably idle, and the Node.js runtime is spared from concurrent connection exhaustions during viral traffic spikes.

For just $5 a month, this elegant, self-hosted stack gives independent creators and business publishers the infrastructure resilience required to scale to millions of page views effortlessly, keeping your blog fast, secure, and infinitely scalable.

Scaling to Millions: Self-Hosting Ghost CMS with Advanced Caddy Caching on a $5 VPS | DPTCloud