October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
VGSources
Blog

How to Speed Up a Ghost Blog on Ubuntu (Caching, Redis, NGINX and CDN Guide)

Learn how to speed up Ghost on Ubuntu by measuring the origin, enabling safe HTTP caching, deciding when Redis helps, configuring a CDN or reverse proxy, and avoiding unsupported clustering.
Length14 min Posted Quest giverVGSources Team
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The most reliable way to speed up a Ghost blog on Ubuntu is to keep Ghost on one supported origin server and put HTTP caching or a CDN in front of it. Start with Ubuntu 24, Node.js 22 LTS, MySQL 8.0, NGINX, systemd and at least 1 GB of RAM. Measure the uncached origin first, then enable suitable Ghost API caching, add Redis only when object-cache persistence or capacity is useful, and cache public pages at the edge. Do not try to create a Ghost cluster: Ghost states that clustering and sharding are unsupported and recommends one node with a cache layer.

The architecture that usually delivers the biggest speed gain

A Ghost site has two very different kinds of traffic. Public visitors request pages, images and Content API responses that can often be reused. Administrators and logged-in users need fresh, private responses. Treating both groups identically either wastes origin resources or risks serving private data from a public cache.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use this request path for a production blog:

  1. A visitor connects to a CDN or reverse-proxy cache.
  2. The cache serves a fresh public page, image or approved API response without contacting Ghost.
  3. On a miss, the cache forwards the request over TLS to NGINX on the Ubuntu server.
  4. NGINX passes the request to Ghost, which reads MySQL and renders the response.
  5. The cache stores only responses that you have explicitly marked as safe to reuse.

Ghost’s official scaling guidance describes a cache and/or CDN in front of the blog as the recommended approach for scale, performance and high availability. This reduces repeated work at the origin instead of multiplying Ghost processes across unsupported nodes.

Begin with a supported Ubuntu production stack

Before tuning individual directives, verify that the foundation is coherent. Ghost-CLI is the preferred baseline because it configures the database, NGINX, SSL, migrations, a low-privilege Ghost user and systemd. A manually assembled server should be compared with those components before you change cache settings.

Component Baseline for this guide Why it matters to speed
Operating system Ubuntu 24 Provides a current supported platform and predictable service packages.
Runtime Node.js 22 LTS Runs Ghost’s application process with a supported long-term runtime.
Database MySQL 8.0 Stores posts, settings and members; slow or saturated queries make every origin request slower.
Web server NGINX Terminates TLS, serves static content and can pass requests to a cache or Ghost.
Service manager systemd Keeps Ghost running, starts it after reboot and exposes resource and failure status.
Memory At least 1 GB RAM Leaves room for Ghost, MySQL, NGINX and the operating system; cache services need additional headroom.

Verify what is actually installed

Run these checks as an initial inventory. Version support can change, so compare the results with the Ghost release documentation that applies to your installation.

node --version
mysql --version
nginx -v
systemctl --version
free -h
df -h

Confirm that the database is local or reachable with low latency, that the disk has free space for logs and MySQL, and that swap activity is not hiding a memory shortage. A server with a fast CPU can still feel slow when it is repeatedly reclaiming memory or waiting on storage.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why Ghost-CLI is a useful reference point

Ghost-CLI does more than install the application. Its normal production setup creates the service account and systemd unit, configures NGINX and SSL, applies migrations and connects MySQL. If your installation predates Ghost-CLI or was copied from a development machine, missing one of those pieces can look like a caching problem. Compare the service ownership, reverse-proxy path, TLS termination, database connection and boot behavior before adding another daemon.

Find the bottleneck before changing configuration

“Ghost is slow” is not a diagnosis. The delay may be at the CDN, NGINX, Node.js, MySQL, disk or the visitor’s network. Reproduce one slow URL while watching the origin; otherwise a cache hit can make a broken origin appear healthy.

Check logs and resource pressure during a slow request

  • Review the Ghost service log and NGINX access and error logs for the same timestamp.
  • Watch CPU usage and load average to see whether Node.js or another process is saturated.
  • Watch memory and swap activity; a full memory budget can cause long pauses even when CPU is idle.
  • Check disk utilization and I/O wait. MySQL reads and log writes can queue behind a busy or nearly full volume.
  • Inspect MySQL status for connection exhaustion, long-running work or signs that the database is the bottleneck.

On a systemd installation, first discover the exact Ghost unit name, then inspect it rather than guessing a service identifier:

systemctl list-units --type=service | grep -i ghost
sudo systemctl status <the-unit-name-shown-above>
sudo journalctl -u <the-unit-name-shown-above> --since "15 minutes ago"
sudo tail -n 100 /var/log/nginx/error.log
sudo tail -n 100 /var/log/nginx/access.log

The angle-bracket values in these commands must be replaced with the unit name returned by the first command. Keep the substitution inside the shell command; do not create a second, guessed unit.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Measure the origin and the cache separately

Record at least time to first byte (TTFB) and total response time for one public page and one representative Content API request. Measure a direct origin path from a trusted network, then measure the public hostname through the CDN or reverse proxy. Repeat each measurement several times, discard the first request if it is a cold start, and keep the test conditions the same. The useful comparison is not a single “fast” number; it is whether cache hits remove origin work and whether misses remain acceptably quick.

export BLOG_URL='https://blog.your-domain.tld'
curl -s -o /dev/null -w 'status=%{http_code} ttfb=%{time_starttransfer}s total=%{time_total}sn' "$BLOG_URL/"

Run the command against your real public URL and, where your network design permits, against the origin endpoint. Do not send authenticated cookies while testing a public cache. Record response headers such as Age, Cache-Control and any provider-specific cache-status header so you can distinguish a hit from a miss.

Make Ghost’s own HTTP caching intentional

Ghost documents a caching configuration with maxAge values for Content API responses. A nonzero lifetime tells an intermediary how long an approved response may be reused. The correct value depends on how quickly your content must appear after publishing; there is no universal number that is safe for every blog.

Choose cacheable responses

  • Cache stable, public Content API responses that are requested frequently.
  • Keep administrative, member-specific and authenticated responses private or bypassed.
  • Use a shorter lifetime when editors need changes to appear quickly, or use a cache with an explicit purge mechanism.
  • Document which endpoint classes are cached so a future theme or integration does not accidentally broaden the policy.

Apply the documented Ghost configuration for your installed version, validate the file syntax, restart or reload Ghost as required by that version, and then inspect the resulting headers. Do not copy a maxAge value from an unrelated example without checking whether it applies to your Content API response and editorial workflow.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Invalidate deliberately

Every cache needs an invalidation plan. A long lifetime without purge controls can leave an old navigation menu or article list visible after a publish. A very short lifetime reduces the benefit and sends the same work back to MySQL. Choose one of these explicit policies:

  • Short time-to-live: acceptable when a small delay after publishing is harmless and you want simple operations.
  • Purge on publish: preferable when the cache or reverse proxy can reliably remove affected URLs after an editorial change.
  • Versioned assets: useful for files whose names change when their contents change, while page and API invalidation are handled separately.

After changing policy, publish a harmless update and confirm which URLs change, which headers are returned and whether a logged-in browser is bypassing the public cache.

Decide whether Redis is worth adding

Redis is not a prerequisite for a fast Ghost blog. Ghost documents a Redis adapter for cache data that benefits from persistence across restarts or from capacity beyond the Ghost process’s memory. Its examples include caching image sizes and the tags Content API endpoint. That is a narrower role than a CDN: Redis is an object-cache layer inside your infrastructure, not a substitute for public page caching at the edge.

Use Redis when these conditions are true

  • The same expensive objects are requested repeatedly by the origin.
  • Restarting Ghost and losing its in-process cache causes a noticeable warm-up period.
  • You need cache capacity that should not compete directly with Ghost’s Node.js process memory.
  • You can monitor Redis memory, persistence and eviction behavior as another production service.

Skip Redis when it would only add administration

  • The measured delay is caused by uncached public pages, TLS or network distance; Redis will not remove that work from visitors.
  • MySQL is saturated and the requested data is not among the objects you plan to cache.
  • The server has barely enough memory for Ghost and MySQL; adding a daemon can increase swapping.
  • Traffic is small enough that a simple in-process cache and a front-end CDN meet the target.
Layer Typical scope Survives Ghost restart? Origin-load reduction Operational cost
Ghost process memory Objects handled by Ghost’s own cache Usually no Targeted; limited by process memory Lowest
Redis adapter Selected object data, such as image sizes or a tags API response Depends on Redis persistence settings Targeted; useful for repeated origin lookups Requires another service, memory policy and eviction monitoring
Reverse-proxy cache HTTP responses at the origin boundary Depends on proxy storage High for repeat public requests Moderate; requires safe cache rules and purging
CDN Public pages and assets at edge locations Usually yes, subject to provider cache policy Highest for geographically distributed public traffic Usually the lowest-effort scale layer, with a recurring service cost

Operate Redis as a bounded cache

Set a memory ceiling appropriate to the server, choose an eviction policy deliberately, and alert before the process reaches the limit. Persistence can help warm the cache after a restart, but it also creates disk I/O; decide whether that trade-off is useful for your workload. Watch hit rate, memory use, evictions and latency. If adding Redis does not reduce measured MySQL work or origin response time, remove the complexity rather than keeping it by default.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Put a CDN or reverse-proxy cache in front of Ghost

For most growing blogs, this is the highest-leverage change. The front layer can terminate visitor TLS, serve cached HTML and assets close to readers, absorb bursts and shield the Ubuntu server from repeated requests. A managed CDN is generally less operational work than building and maintaining a second cache service yourself; a self-hosted reverse proxy offers more control but makes you responsible for storage, purging, TLS and failure handling.

Define public and private paths

Cache only responses that are identical for all visitors. Public article pages, public feeds and selected Content API responses are candidates. Bypass or mark private:

  • The Ghost admin interface and sign-in pages.
  • Requests carrying member or administrator authentication cookies.
  • Preview, draft and personalization endpoints.
  • Any response containing private account, membership or form data.

Strip or avoid forwarding unnecessary cookies on public cache keys, but do not remove a cookie that Ghost needs to enforce authentication. A cache key that varies on every tracking parameter can destroy hit rate; normalize only parameters that you have verified are irrelevant to content.

Handle TLS and the origin safely

Keep HTTPS from visitors to the edge and from the edge to NGINX unless your threat model and network isolation explicitly allow otherwise. Restrict direct origin access where your provider supports it, and make sure Ghost sees the correct host and scheme through the proxy. Test redirects, canonical URLs, image URLs and webhooks after enabling the layer. A cache that serves fast but creates redirect loops or mixed-content warnings is not a successful optimization.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Control freshness and purging

Use the cache-control policy that matches the Ghost maxAge settings and your editorial SLA. Confirm how the chosen layer purges a single URL, a path and the entire cache, and who is authorized to trigger each operation. Prefer a narrow purge after publishing over clearing every object for a one-page edit. Test a purge with a non-critical article before relying on it during an incident.

Keep NGINX focused on reliable request handling

NGINX is valuable even when a CDN is present: it terminates or re-encrypts TLS, serves static files, forwards cache misses and provides access logs. Avoid copying a large “performance” configuration without understanding whether it changes Ghost’s routing or authentication.

  • Validate every configuration change with sudo nginx -t before applying it.
  • Use sudo systemctl reload nginx for a reload when the test passes; reserve a restart for cases that require it.
  • Verify that the proxy forwards the original host, protocol and client information needed by Ghost.
  • Keep WebSocket or upgrade handling only where an installed Ghost integration requires it.
  • Rotate and monitor access logs so logging does not fill the disk or create avoidable I/O pressure.

If NGINX access logs show most requests are cache misses, fix cache eligibility and keys before tuning worker counts. If requests are hits but TTFB remains high for distant users, the edge location or network path is the likely improvement area, not another Ghost worker.

Do not scale Ghost by clustering unsupported nodes

Ghost’s official scaling FAQ says clustering and sharding are not supported and recommends reducing the infrastructure to one node with caching. Running multiple independent Ghost instances behind a load balancer can create inconsistent local state, difficult cache invalidation and unsupported failure modes. It also multiplies migrations, upgrades, logs and database connections.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When traffic grows, first increase cache hit rate and move public delivery to the edge. Then measure whether the single origin is constrained by CPU, memory, storage or MySQL. If the origin still needs more capacity, resize that supported node and its database deliberately, keeping the cache boundary in front. Do not interpret “more servers” as an automatic speed improvement when the application architecture does not support that arrangement.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A repeatable troubleshooting sequence

Use this order so that each change answers a specific question. Change one variable at a time and keep the before-and-after measurements.

  1. Confirm versions and services. Verify Ubuntu 24, Node.js 22 LTS, MySQL 8.0, NGINX and systemd, then confirm Ghost starts cleanly under its service account.
  2. Reproduce the delay. Capture the URL, timestamp, response status, TTFB and total time while watching Ghost, NGINX, CPU, memory, disk I/O and MySQL.
  3. Separate origin from edge. Measure a direct origin request and a public request through the cache. Confirm whether the public response is a hit or miss.
  4. Fix the largest bottleneck. Resolve errors, memory pressure, disk saturation or database contention before introducing a new cache layer.
  5. Enable suitable HTTP caching. Apply Ghost’s documented caching and maxAge settings to stable, public Content API responses; bypass private paths.
  6. Introduce Redis selectively. Add the adapter only for repeated objects that benefit from persistence or larger capacity. Set limits and observe evictions.
  7. Add or refine the CDN/reverse proxy. Cache public pages, bypass admin and authenticated traffic, configure TLS and test purge behavior.
  8. Re-measure after each change. Compare hit rate, origin requests, TTFB, total time, memory use and database load under the same conditions.

Symptoms and likely next checks

Symptom Likely area Next check
Every visitor is slow, including cache hits Edge location, network path or TLS handling Compare edge TTFB with direct origin TTFB and inspect cache-status headers.
Only the first request after a restart is slow Cold application or object cache Check Ghost startup logs and whether Redis persistence would materially help.
Public pages are fast but admin is slow Origin, MySQL or admin integrations Measure authenticated requests separately; never cache them merely to improve a number.
Cache hit rate is unexpectedly low Cookies, query strings, varying headers or short TTL Inspect the cache key and response headers, then normalize only safe variations.
Pages show old content after publishing TTL or purge policy Test targeted invalidation and shorten freshness only if the editorial requirement demands it.
Performance worsened after Redis Memory pressure, evictions or network overhead Check Redis memory, eviction count, hit rate and host swap activity; remove it if it adds no measured benefit.
Intermittent 502 or 504 responses Ghost process, NGINX upstream or resource exhaustion Correlate NGINX errors with the Ghost journal and system resource graphs before adjusting timeouts.

Memory, database and disk checks that prevent false fixes

At least 1 GB of RAM is a starting requirement, not a guarantee that every theme, integration and traffic pattern will fit. If free -h shows little available memory and swap is active during requests, adding Redis can make the problem worse. Resize the server or remove unnecessary services before increasing cache capacity.

MySQL saturation also requires measurement rather than assumptions. Check connection counts, slow operations and disk waits during the same window as the slow request. A CDN can eliminate many repeated reads, but it cannot make a cache miss cheap when the underlying query or storage is overloaded. Keep enough free disk for MySQL, Ghost logs and NGINX logs; a full volume can turn a performance issue into an outage.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How to compare your options

Use the following decision framework rather than selecting a product by feature count.

Situation First choice Reason Trade-off
Readers are distributed geographically and repeat public pages CDN in front of the single Ghost origin Moves delivery closer to readers and removes repeated origin requests. Requires correct private-path bypasses, TLS setup and purge rules.
Readers are nearby but the origin repeats expensive public responses Reverse-proxy cache Reduces work before requests reach Ghost while keeping control on the server. You administer storage, invalidation and cache failures.
Ghost repeatedly calculates selected objects Redis adapter Targets object data such as image sizes or the tags Content API response. Adds memory, monitoring and another service to operate.
Traffic is low and no bottleneck is measured Keep the supported baseline Avoids complexity that has no demonstrated benefit. Less headroom for sudden traffic spikes.
Considering several Ghost application servers Do not cluster; improve caching or resize the supported origin Ghost documents clustering and sharding as unsupported. A single origin remains a capacity boundary, so measure and plan upgrades carefully.

What Ghost’s published performance figure does—and does not—tell you

The Ghost Foundation’s Ghost 5.0 changelog in 2022 reported aggregate release-era changes: 20% more requests per second, 15% less memory usage at boot, 22% less at peak and 16% faster boot time. Those figures describe the release measurements reported by Ghost; they are not a promise for a particular Ubuntu server, theme, database, integration or traffic pattern. Use them as context for keeping Ghost current, not as a substitute for measuring your own origin and cache.

Production checklist

  • Ubuntu 24, Node.js 22 LTS, MySQL 8.0, NGINX and systemd versions are verified against the applicable Ghost support information.
  • Ghost-CLI’s database, SSL, NGINX, migrations, service account and systemd responsibilities are present or intentionally reproduced.
  • Ghost, NGINX, MySQL, CPU, memory, disk I/O and swap are observable during a slow request.
  • Baseline TTFB and total response time are recorded for an uncached origin request and a public cache request.
  • Content API maxAge values are set only for responses that are safe and useful to cache.
  • Admin, member, preview, draft and authenticated paths bypass public caching.
  • Redis is installed only when measured object-cache needs justify its memory and maintenance cost.
  • Redis memory limits, persistence choice, hit rate and eviction behavior are monitored.
  • The CDN or reverse proxy has tested TLS, origin protection, cache keys, purge controls and failure behavior.
  • There is one supported Ghost origin; no unsupported clustering or sharding is being used.
  • Every optimization is re-measured independently so a regression can be identified and reversed.

Bottom line

Speed up a Ghost blog on Ubuntu from the outside in: establish the supported single-server stack, measure the real bottleneck, cache safe HTTP responses and put a CDN or reverse-proxy cache in front of public traffic. Redis is an optional, targeted object cache—not a replacement for edge caching—and adding Ghost nodes is not the supported scaling path. The fastest configuration is the one whose cache rules preserve private data, whose invalidation matches your publishing needs and whose resource impact you can verify with measurements.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More quests from Patch Notes

  1. How to Set Up a RedM (RDR2) Server in 2026: License Key, txAdmin and server.cfg, Step by StepBlog11min
  2. Best RedM (RDR2) Server Hosting in 2026: Comparing Four Hosts on Slots, Memory and PriceBlog10min
  3. How to Host a Mindustry Server in 2026: server-release.jar, Port 6567 and the Commands That MatterBlog7min
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.