Ghost is a sleek, lightning-fast, and modern alternative to WordPress that strips away the bulky plugins and focuses entirely on what matters most: creating incredible content, delivering high-performance SEO, and building a paid subscriber audience.
But while the software itself is beautifully streamlined, figuring out your ghost website hosting can be surprisingly confusing.
Because Ghost is built on a Node.js stack rather than traditional PHP, it requires a different server environment. This leaves many users torn between two frustrating extremes:
Pay a massive monthly premium for a fully managed service.
Work on the complex Linux command line to host it yourself.
You shouldn’t have to choose between emptying your wallet and becoming a system administrator.
In this guide, we will compare the true costs and technical requirements of managed plans versus unmanaged servers, and show you how to build the best ghost hosting setup.
Understanding Your Ghost CMS Hosting Options
If you’re coming from the WordPress ecosystem, your first instinct might be to look for a standard, cheap, shared hosting plan. However, Ghost hosting runs on a completely different server stack.
Unlike traditional platforms that rely on PHP and run easily on standard cPanel setups, Ghost is built on a modern, lightning-fast Node.js stack. Because of this, you simply cannot drop a Ghost installation into a standard $3/month shared hosting bucket. It requires a server environment capable of running Node.js applications, managing background processes, and handling modern database systems such as MySQL or SQLite3.
Because of these technical requirements, finding the right ghost blog hosting generally forces users down one of three distinct paths:
Fully Managed Ghost Hosting: You pay a premium price for a company to handle all the servers, updates, and security on your behalf.
DIY Self-Hosted (Unmanaged VPS): You rent a bare-metal server or VPS and use the command line (SSH) to build and maintain the environment yourself.
Managed Cloud Servers: You rent an affordable VPS from any cloud provider, but use a graphical dashboard to easily manage the server and deploy your apps without needing to be a Linux expert.
Let’s break down the pros, cons, and actual costs of these options.
1. Managed Ghost Hosting
If you don’t want any technical responsibility, you should choose managed ghosthosting, as it is the simplest option. With a managed host, you are essentially renting software-as-a-service. The hosting company provides the infrastructure, handles all core Ghost software updates, manages database backups, and configures your SSL certificates.
Ghost(Pro) is the most popular managed option, as it is the official hosting service from Ghost’s creators. Choosing Ghost (Pro) is a great way to support the open-source project, as revenue goes directly toward funding Ghost’s development.
Ghost(Pro) is incredibly easy to use, and its pricing is structured around audience size and features:
Starter: Suitable for solo blogs & newsletters ($15 USD/mo, billed annually). With this, you get your own website, a free custom domain, an email newsletter, Simple design settings, and 1,000 members.
Publisher: Recommended for custom publications ($29 USD/mo, billed annually). It provides 3 staff users, Custom themes, 8,000+ integrations, paid subscriptions, Advanced analytics, and 1,000 members.
Business: This plan is for teams scaling up ($199 USD/mo, billed yearly). It provides access to 15 staff users, Priority support, Higher usage limits, Early access to features, and 10,000 members.
Custom: This is a customizable plan for more complex needs. It provides unlimited staff users, Advanced configurations, a dedicated IP address, 99.9% uptime SLA, and unlimited members.
Third-Party Managed Options
Since Ghost is open-source, several third-party companies have stepped in to offer niche managed Ghost hosting alternatives at slightly lower price points. Providers like Midnight (starting around $12/month) and Magic Pages (starting around $15/month) offer fully managed setups that bypass some of Ghost(Pro)’s strict feature limits, catering to users who want managed convenience on a budget.
The Drawbacks of Managed Hosting
While managed hosting is highly convenient, it comes with two major compromises for developers, agencies, and growing creators:
The “Success Tax” (Cost Scaling): With managed hosting, your monthly bill scales aggressively as your email list grows, regardless of how much actual server traffic you receive. You are paying for audience size, not server compute power.
Strict Limitations: When you buy a managed Ghost plan, you only get Ghost. You’re paying for a single instance of the software. If you want to host a custom Laravel application, spin up a secondary WordPress site for a different project, or even launch a second Ghost blog, you can’t put them on the same plan. You have to purchase a completely separate hosting subscription, leaving you with multiple bills and fractured infrastructure.
2. Ghost VPS Hosting & DIY Self-Hosting
This is the recommended approach for tech-savvy users who want total control over their data and infrastructure. VPS hosting means renting a blank Linux server from cloud providers such as DigitalOcean, Hetzner, AWS, Vultr, or Linode and building the environment from scratch.
Unmanaged cloud servers start at $5 to $7 per month for a machine with 1GB to 2GB of RAM, offering incredible cost savings. However, the true cost is paid in your time and technical expertise.
Many users are lured into DIY hosting by offerings like the DigitalOcean Marketplace “1-Click Ghost Install.” While it sounds incredibly convenient, it is largely a myth for non-developers.
Yes, the initial installation is a one-click process. But from day two onward, you are acting as your own system administrator.
When you use an unmanaged VPS, the cloud provider gives you the hardware and steps away. 100% of the server management is your responsibility. This means you must manually handle:
Ubuntu OS security patches via the command line (apt-get update).
Renewing Let’s Encrypt SSL certificates manually before they expire.
Configuring and monitoring server firewalls (UFW).
Updating Ghost itself via the command line interface (ghost-cli) often requires careful database backups beforehand.
The Drawbacks of DIY Self-Hosting
The glaring drawback to self-hosting Ghost with Docker or using the CLI is the steep learning curve. If you don’t have advanced Linux expertise, DIY hosting is highly risky. A single botched command during a routine update, or an overlooked security patch, can take your website offline for hours, or result in permanent data loss if you haven’t manually configured remote backups.
3. The Best Ghost Hosting Solution: RunCloud
If Managed Hosting is too restrictive and expensive, and DIY VPS Hosting is too complicated and risky, where does that leave you?
The answer is RunCloud.
RunCloud sits directly in the “sweet spot” between these two extremes, providing the absolute best ghost hosting experience by combining the cost savings of a VPS with the automated ease of a managed platform.
Here is why developers, agencies, and publishers use RunCloud for their ghost website hosting:
Choose Your Own Cloud Infrastructure
With RunCloud, you aren’t locked into proprietary servers. You simply rent a bare-metal server from your favorite cloud provider, whether that’s a highly affordable $5/month Hetzner server, a DigitalOcean Droplet, or a robust AWS EC2 instance. You pay wholesale prices directly to the cloud provider, and RunCloud connects to it via our platform to handle the management.
Host More Than Just Ghost (Maximize Your Server)
This is RunCloud’s biggest advantage over official managed platforms. When you use RunCloud, the server is entirely yours. You’re not artificially limited to a single application.
Let’s say you rent a $12/month server with 4GB of RAM. With RunCloud, you can seamlessly host Ghostand WordPresson the same server. An agency could host a client’s primary WordPress e-commerce site, a custom Laravel backend API, and a sleek new Ghost blog all on the same VPS. By stacking multiple web applications on a single server, your actual hosting cost per website drops to pennies.
Zero Linux Expertise Required
RunCloud replaces the black SSH terminal screen with a beautiful, intuitive graphical dashboard. You get full server control without memorizing Linux commands. With a few clicks in the RunCloud dashboard, you can:
Deploy one-click Let’s Encrypt SSL certificates with auto-renewals.
You can get the cheapest ghost hosting by renting a budget-friendly VPS from providers like Hetzner or DigitalOcean for around $4-$6 per month. By connecting that unmanaged server to RunCloud, you can get premium, managed-like dashboard features without paying the high monthly subscription fees of dedicated hosting companies.
Can I use shared hosting for Ghost CMS?
You cannot use shared hosting for Ghost because it runs on a modern Node.js stack rather than traditional PHP. Most cheap shared hosting environments (like standard cPanel setups) do not support the persistent background processes required to run Node.js applications, which is why a dedicated VPS or cloud server is necessary.
What are the best Ghost hosting alternatives to Ghost Pro?
The most cost-effective alternative to Ghost Pro is self-hosting on your own cloud infrastructure using a server management panel like RunCloud. This gives you lightning-fast performance and security for a fraction of the cost, preventing your hosting bill from skyrocketing as your email subscriber list grows.
How much RAM do I need for a Ghost server?
To install and run a Ghost blog smoothly, you need a server with at least 1GB of RAM. However, upgrading to a server with 2GB or more is highly recommended to ensure stability during traffic spikes or if you plan to host additional web applications alongside your blog on the same server.
Wrapping Up
When you’re launching your website, choosing the right infrastructure shouldn’t be a trade-off. Fully managed plans are often too expensive and restrictive for growing creators, while DIY self-hosting on a blank VPS requires advanced Linux skills that are too risky and time-consuming for non-developers.
RunCloud is the perfect middle ground for Ghost hosting.
By bringing your own cloud server to RunCloud, you can get the best of both worlds: wholesale server pricing, the freedom to host multiple web applications on a single machine, and an intuitive dashboard that handles all the complex server management for you.
If you have tested your WordPress site with PageSpeed Insights, you have probably seen the warning: “Reduce initial server response time.”
This warning relates to your site’s Time to First Byte (TTFB), which measures how quickly your server responds before the page begins loading. A slow TTFB can hurt Core Web Vitals, SEO performance, and user experience.
In most cases, the problem is not WordPress itself. It is the server stack underneath it. Slow PHP processing, missing server-side caching, unoptimized databases, and overloaded hosting environments can all significantly increase response times.
In this guide, we will show you how to reduce TTFB in WordPress using practical server-level optimizations you can manage directly from your RunCloud dashboard.
What TTFB Actually Measures (And What Google Wants to See)
Time to First Byte (TTFB) is one of the most important metrics of your website’s performance. It measures the time it takes a user’s browser to receive the first byte of data from your server after an HTTP request.
This includes the time taken for the following three steps:
DNS lookup time
Server processing time (executing PHP and database queries in WordPress)
Network latency (how quickly data travels)
According to Google’s official Core Web Vitals guidelines, a TTFB of under 800 milliseconds is considered “Good” and is the absolute baseline you must hit to pass their lab tests. However, WordPress performance experts aim for a TTFB of under 200 milliseconds.
How to measure TTFB correctly
Measuring TTFB accurately requires looking at both “lab data” (controlled tests) and “field data” (real-world user experiences).
PageSpeed Insights: This tool provides Chrome User Experience Report (CrUX) field data, showing the actual TTFB your users experience over 28 days, alongside real-time Lighthouse lab data.
GTmetrix: This is excellent for visualizing server response times with detailed Waterfall charts. It allows you to see exactly how much time is spent on DNS resolution versus the time the server spends waiting (the actual processing).
KeyCDN Performance Test: Physical distance of the server impacts network latency. This multi-location tool simultaneously checks your TTFB from 10+ global servers. If your TTFB is 150ms in New York but 1,200ms in Sydney, then it’s not good for your SEO.
Why Is Your WordPress Server Response Time Slow?
If your TTFB is failing Google’s benchmarks, the problem almost always lies under the hood of your WordPress configuration or your hosting environment. WordPress is a dynamic CMS, which means pages aren’t just sitting there ready to be served. Whenever a user visits your website, the pages are specially built for them. However, if you don’t optimize this process, it can feel slow.
Reason 1: Uncached PHP execution is hitting MySQL on every request
The number one killer of WordPress TTFB is a lack of page caching. When a visitor requests an uncached page, the server must spin up PHP workers, compile the theme and plugin code, query the MySQL database for the content, and stitch it all together into an HTML document.
This heavy server processing can take anywhere from 1,000ms to over 3,000ms on an average server.
By implementing a modern page caching solution, you can bypass this entire process and drop your page load times significantly.
Reason 2: Missing or misconfigured OPcache and object cache
Even with page caching, dynamic requests (such as WooCommerce checkouts, admin dashboards, or for logged-in users) still require server processing. This is where advanced caching layers save your TTFB.
PHP OPcache stores precompiled script bytecode in the server’s memory, eliminating the need for PHP to load and parse scripts on every request, which data shows can reduce PHP execution time by up to 70%.
Object caching (using Redis or Memcached) stores the actual results of complex MySQL database queries in memory. Without object caching, a complex WooCommerce page might trigger 150+ database queries; with Redis enabled, those repeated queries are served from RAM almost immediately, without any processing.
Reason 3: Shared hosting resource limits and server location distance
Shared hosting environments cram hundreds of websites onto a single server. This forces you to share limited CPU cores and RAM. When traffic spikes on a neighbor’s site, your server’s response time will increase, affecting your users.
Additionally, physical distance adds latency; data traveling from a server in London to a user in Tokyo naturally takes longer (often adding 200ms+ to TTFB). To fix this, it is a good idea to migrate to a dedicated cloud VPS managed by an optimized stack like RunCloud. Combining a high-performance VPS with a global CDN ensures you have dedicated CPU power and edge servers positioned within milliseconds of your visitors.
How to Reduce Server Response Time in WordPress
Optimizing your WordPress server response time is a multi-step process that requires addressing both software inefficiencies and hardware limitations. Follow the steps below to speed up your WordPress site:
Step 1: Enable full-page caching (FastCGI or Redis page cache)
The simplest way to reduce TTFB in WordPress is by enabling full-page caching. Normally, WordPress dynamically generates every page by executing PHP and querying the database, which is a highly resource-intensive process. Full-page caching bypasses this entirely by saving a page’s fully rendered HTML and serving it to subsequent visitors.
While most WordPress users rely on WordPress caching plugins, server-level caching delivers significantly better performance. RunCache supports FastCGI caching that intercepts the user’s request before it ever reaches WordPress. This eliminates PHP overhead and reduces server response times from hundreds of milliseconds to 20-50ms.
If you are running a blog, portfolio, or corporate site where content doesn’t change every minute, aggressive full-page caching is strongly recommended. You can set cache expiration times to automatically clear when a new post is published, ensuring visitors always get the fastest, most up-to-date version of your site.
The full-page caching can handle static visitors, but dynamic sites like WooCommerce stores, membership portals, and active forums must bypass the page cache to serve personalized content.
For these dynamic requests, WordPress has to query the database repeatedly, which quickly spikes server response times. Object caching stores the results of complex, frequently run database queries in RAM. When a user triggers a dynamic request, the object cache serves the stored data instantly, avoiding the need to query MySQL again.
Many site owners dread the intimidating SSH commands required to install and configure Redis on a server. To make things easier, RunCache includes a one-click Redis activation feature that automatically configures everything.
Step 3: Update to the latest PHP version
The PHP version running on your server plays a major role in your WordPress site’s performance. Each new major release of PHP comes with significant engine optimizations. For example, upgrading from PHP 7.4 to PHP 8.1 or 8.3 can drastically increase the number of requests your server can handle per second while simultaneously reducing memory consumption and TTFB.
Despite the obvious speed benefits, many users hesitate to upgrade because of the potential for fatal errors if a legacy theme or plugin is incompatible with the newer PHP code. Upgrading safely requires a staging environment and the ability to revert if things go wrong easily.
With RunCloud, you are given total control to manage this process without fear. The platform lets you switch your PHP version for each web app (e.g., upgrading from 7.4 to 8.3) directly from the dashboard with zero downtime. If you spot any errors, you can instantly switch back to the previous version to troubleshoot plugin conflicts.
Step 4: Optimize and clean your WordPress database
WordPress relies completely on its MySQL or MariaDB database to function. Over time, databases inevitably bloat with unnecessary data, including hundreds of post revisions, auto-drafts, trashed comments, expired transients, and orphaned settings left behind by deleted plugins. A bloated database means the server has to sift through massive, unindexed tables to find the right data, directly inflating your TTFB.
The most important area to monitor is the wp_options table, specifically the “autoloaded” rows. WordPress automatically loads this data on every single page view. If a poorly coded plugin leaves behind megabytes of useless autoloaded data, your server will choke on the processing. Performance experts strongly recommend auditing this table and keeping autoloaded data well under 1MB.
You can regularly optimize your database using lightweight plugins such as WP-Optimize or Advanced Database Cleaner. By regularly deleting orphaned data, optimizing database tables, and adding missing indexes, you can keep your server response times incredibly low.
Step 5: Replace wp-cron with a real cron job
WordPress uses a built-in scheduling system called wp-cron to handle background tasks like publishing scheduled posts, checking for theme updates, and running backup plugins. This wp-cron job is triggered when a user visits your website. On high-traffic sites, it can cause random, severe spikes in server response times.
To fix this, you should disable the default WordPress cron behavior by adding define(‘DISABLE_WP_CRON’, true); to your wp-config.php file. Once disabled, you must replace it with a real system-level cron job that pings the wp-cron.php file on a set schedule (e.g., every 5 to 15 minutes), completely decoupling background tasks from your users’ live page loads.
For many admins, setting up a system cron requires digging into Linux crontab configurations. However, if you need a real server cron instead of wp-cron, RunCloud provides a built-in cron job manager that instantly replaces WordPress cron with a single click.
Step 6: Use a CDN with full-page caching and a nearby Points of Presence
No matter how optimized your server is, the laws of physics dictate that data takes time to travel across the globe. If your hosting server is located in London, but your visitor is in Sydney, the geographic distance alone will introduce hundreds of milliseconds of network latency, resulting in a poor TTFB.
In this case, you must use a CDN to solve this physical bottleneck. While traditional CDNs are great for caching heavy assets like images and CSS files, they still require the initial HTML document to be generated by your origin server. To dramatically improve server response times globally, you need an advanced CDN setup that supports full-page Edge caching, such as Cloudflare’s Automatic Platform Optimization for WordPress.
By caching your pages’ HTML at the CDN’s Edge servers, your visitors can receive cached content from CDN edge locations closer to their region. This bypasses your origin server entirely for static page requests, delivering near-instantaneous server response times no matter where the user is located in the world.
Step 7: Enable HTTP/3
Using a newer, more advanced network protocol can significantly improve your website’s performance, particularly during the initial connection phase. In our recent post about HTTP/2 vs HTTP/3, we explained that Older protocols like HTTP/1.1 suffer from “head-of-line blocking”, which requires the browser to open multiple, sequential connections to download site assets. In comparison, newer HTTP protocols support multiplexing, which allows multiple files to be downloaded concurrently over a single connection.
In addition to the HTTP protocol, your SSL/TLS encryption standard matters. Secure connections require an SSL “handshake” before data can be transmitted. Older TLS 1.2 requires multiple round-trips between the browser and server to establish this secure connection. Upgrading to TLS 1.3 optimizes this by requiring only a single round-trip (and sometimes zero round-trips for returning visitors), shaving precious milliseconds off the TTFB.
RunCloud supports HTTP/3 without requiring manual server configuration, but if you are not using RunCloud yet, you can refer to our post on How to Enable HTTP/3 on NGINX to learn how to optimize your server.
Step 8: Audit and remove resource-heavy plugins
Plugins and themes can significantly impact WordPress performance. Every activated plugin injects its own PHP code that must be executed, and many inject their own CSS and JavaScript files that must be downloaded. Poorly coded, outdated, or resource-intensive plugins (such as page builders, analytics tools, or backup solutions) can hog server CPU and drastically slow TTFB for every visitor.
If you want to speed up your WordPress site, you should audit your plugin stack. You can use RunCloud’s built-in diagnostic tools, such as Slow Query Monitoring or Slow Script Monitoring, to profile your website’s backend.
Once you identify the worst offenders, replace them with lightweight alternatives or remove them entirely if the functionality isn’t strictly necessary. Offloading tasks like analytics to Google Analytics or backups to an external server panel (rather than using a WordPress plugin) drastically reduces your backend load.
Does Your WordPress Host Set the TTFB Ceiling?
No matter how aggressively you optimize your WordPress website, the underlying hardware and network infrastructure establish a hard limit on your maximum possible speed. You can compress your images, minify your CSS, and install premium caching plugins. Still, if your server takes a full second to process a basic request, your server response time will never meet Google’s Core Web Vitals standards. Simply put, you cannot out-optimize a slow, underpowered server.
Shared hosts place strict caps on your resource consumption. You are restricted by low PHP memory limits, throttled CPU cores, and strict I/O (Input/Output) usage limits. Premium performance plugins like WP Rocket or LiteSpeed Cache are excellent at reducing the number of dynamic requests. Still, they cannot magically generate more CPU power to process the requests that do get through. If your host throttles your account to a fraction of a single CPU core, your dynamic WooCommerce checkouts or admin dashboard will always suffer from a TTFB well over 800ms.
Finally, shared hosting completely locks you out of the server environment. You do not have root access to install powerful, modern server-side software. You cannot fine-tune PHP-FPM worker pools, install the latest enterprise-grade versions of Redis or Memcached, or tweak NGINX configurations to prioritize your specific traffic. You are permanently stuck with a generic, one-size-fits-all server stack that prioritizes hosting company profits over your website’s performance.
Why VPS with a server panel changes the equation
When you provision a server from modern cloud providers like DigitalOcean, Vultr, or Hetzner, you are allocated a dedicated, isolated CPU and RAM. Your server resources belong exclusively to your WordPress website.
Historically, the massive barrier to entry for using a VPS was the steep technical learning curve; you had to be a skilled Linux system administrator to manage security, databases, and web servers via the command line. This is exactly where a modern server control panel changes the equation entirely.
By pairing your cloud VPS with RunCloud, you can get unrestricted power of dedicated cloud hardware, along with a centralized management dashboard that makes server management as easy as traditional shared hosting.
RunCloud provides a hyper-optimized, enterprise-grade tech stack (NGINX, modern PHP, MariaDB, and Redis) designed specifically for maximum WordPress speed. It eliminates the need for SSH or terminal commands, letting you configure server-level caching, manage databases, and deploy one-click SSL certificates directly from the UI. This gives you control over your server environment, lets you bypass restrictive shared hosting limits, and permanently improves your WordPress server response times.
Want to improve your WordPress server response times without managing everything manually? Try RunCloud for yourself.
FAQs
What is a good TTFB for WordPress?
A good Time to First Byte (TTFB) for WordPress is typically under 200 milliseconds for optimal performance, though anything under 500 milliseconds is generally acceptable for SEO.
Does TTFB affect Google rankings?
Yes, TTFB directly affects your Google rankings because it acts as the critical foundation for Core Web Vitals metrics like Largest Contentful Paint (LCP). Slow server response time delays the entire page load, negatively impacting user experience, increasing bounce rates, and lowering your search engine visibility.
Why is my server response time high even with a caching plugin?
Your server response time might remain high if your website relies heavily on dynamic uncached requests, bloated plugins, or an unoptimized database. Even the best caching plugins cannot fix an underpowered server, which is why upgrading to a highly optimized hosting environment like RunCloud is essential for a permanent fix.
How do I reduce TTFB on shared hosting?
To reduce TTFB on shared hosting, you should configure an aggressive page caching plugin, optimize your database tables, and route your DNS through a Content Delivery Network (CDN). However, shared servers always have inherent resource limits, so migrating to a dedicated VPS managed by a platform like RunCloud will yield the best long-term performance.
You’ve optimized your website’s frontend for visitors, and it passes all core web vitals checks, but when you open the WordPress admin dashboard, time seems to stand still, and you’re left waiting ages for it to fully load.
Have you ever wondered why your WordPress dashboard is crawling when your live site is flying? It all comes down to how your server handles data.
While your website visitors are served blazing-fast, static HTML files via page caching, those rules are intentionally bypassed the moment you log in.
In this guide, we will walk you through 8 proven backend-specific fixes (including optimizing PHP workers, stopping WP-Cron bloat, and enabling Redis object caching) to instantly speed up your WordPress admin.
Why WordPress Admin Loads Differently From Your Frontend
If your website loads instantly for visitors but is slow for you, it comes down to how caching works. The WordPress admin dashboard bypasses page caching entirely, meaning authenticated requests are never cached.
While public pages serve lightweight, static HTML files to your visitors, every single click inside the wp-admindashboard forces your server to generate the page from scratch. This triggers heavy PHP execution, dozens of database queries, and complex plugin hooks.
To speed up your dashboard, you need a completely different set of server and application-level fixes.
Fix 1: Increase the PHP Memory Limit
By default, WordPress allocates only a few MB of memory for single-site installations. This is far too low for a modern, plugin-heavy WordPress admin dashboard, and it often results in slow load times or “fatal memory exhausted” errors.
If you’re using RunCloud, then fortunately, you don’t need to touch any code. Simply log in to your RunCloud dashboard, select your Web Application, and navigate to Settings > PHP Settings. Edit the memory_limit setting to 256M (or 512M for WooCommerce sites).
If you prefer the manual route, use the RunCloud File Manager to open your wp-config.php file, then add the following line just before the “That’s all, stop editing!” line:
define( 'WP_MEMORY_LIMIT', '256M' );
Fix 2: Upgrade to PHP 8.2+ and Verify OPcache Is On
If your server is still running PHP 7.x, you’re missing out on major performance features, such as the Just-In-Time (JIT) compiler.
Upgrading to PHP 8.2 with OPcache enabled can drastically reduce admin response times by storing precompiled script bytecode in shared memory.
RunCloud lets you switch PHP versions directly from the dashboard:
Go to your Web Application
Click Settings
Select PHP 8.2 or higher from the dropdown menu
This ensures you are using the latest advancements and optimizations from updated PHP versions.
Want to learn more about the performance benefits? Check out our detailed guide on upgrading to PHP 8.
Fix 3: Throttle the WordPress Heartbeat API
The WordPress Heartbeat API is responsible for autosaving posts, tracking user sessions, and showing real-time plugin notifications. However, it does this by firing continuous admin-ajax.php requests every 15 seconds. If you have multiple tabs open, it effectively hammers your server and slows the admin area to a crawl.
You can throttle this activity to run every 60 seconds (or disable it entirely on non-essential pages). There are two ways to do this:
Using a Snippet: Add the following code to your theme’s functions.php file or a code snippets plugin:
Using a Plugin: Alternatively, install the free Heartbeat Controller plugin from the WordPress repository. Go to its settings and set the interval for the WordPress Dashboard, Frontend, and Post Editor to 60 seconds.
Fix 4: Audit and Cut Admin-Side Plugin Bloat
Many poorly coded plugins load their CSS and JavaScript on every admin page, even when those assets are only needed on a specific settings screen. This bloat creates massive bottlenecks when navigating the backend.
Follow the steps below to fix this:
Install the free Query Monitor plugin. Open your admin dashboard and look at the Query Monitor data in your admin bar. It will break down exactly which plugins are taking the longest to load, generating the most database queries, or consuming the most memory.
Install a plugin like Asset CleanUp or Perfmatters. These tools allow you to conditionally disable scripts and styles from loading on pages where they aren’t needed.
Deactivate and permanently delete any plugins that run background processes or analytics that you don’t actually need or use daily.
Fix 5: Clean Your Database (Revisions, Transients, Bloat)
Every time you hit “Save Draft” or let WordPress auto-save your work, it creates a new post revision in your database. On a site that’s a few years old, this can quickly result in 10,000+ orphaned revision rows, expired transients, and metadata bloat.
There are two ways to fix this:
The WP-CLI Method (For Advanced Users): If you are comfortable in the terminal, you can clean your database in just a few seconds. Run wp transient delete –all to clear expired cached data, and run wp post delete $(wp post list –post_type=revision –format=ids) to purge old revisions.
The GUI Method: Install a free optimization plugin, such as WP-Optimize. Use its dashboard-based tools to clean up database tables, remove spam comments, and delete post revisions.
Fix 6: Replace WP-Cron With a Real Server Cron Job
By default, WordPress handles scheduled tasks (like publishing scheduled posts, checking for updates, or sending emails) using Cron Jobs. However, WordPress Cron doesn’t use a real system scheduler. Whenever a user or admin visits a page, WP-Cron checks for pending tasks, which can hit the admin dashboard hard and cause random, massive spikes in load times.
It is highly recommended to enable a real server-based cron for your WordPress website using the following steps:
Disable WP-Cron: Open your wp-config.php file and add the following line to stop WordPress from executing cron on page loads:
define('DISABLE_WP_CRON', true);
Add a Server Cron: In your RunCloud dashboard, select the server where your site is hosted, and click on the Cron Job tab in the left menu. On this screen, add a new job with the following command to run every 5 minutes (*/5 * * * *):
If you are using RunCloud, you can replace WordPress cron jobs with real cron jobs directly from the RunCloud dashboard by selecting a checkbox during WordPress installation:
Fix 7: Right-Size Your Server Stack (CPU, RAM, and NGINX)
The WordPress admin dashboard bypasses the cache entirely, making the dashboard CPU-bound. A 1-core VPS will always feel sluggish in the backend, regardless of how many caching plugins you install.
Your web server software also plays a massive role. The older Apache + mod_php stack spawns a brand-new PHP process for every single request. In contrast, NGINX paired with PHP-FPM reuses worker pools, which is far more efficient for heavy admin operations.
RunCloud deploys NGINX + PHP-FPM by default: the fastest stack for WordPress admin performance. If your current host is still running Apache and your dashboard is lagging, then you should migrate to a modern WordPress host and ensure your server has at least 2 CPU cores and 2GB+ of RAM to give PHP-FPM the breathing room it needs to process dashboard requests instantly.
Every single time you load a page in wp-admin, WordPress runs anywhere from 30 to 80 database queries. Without an object cache, every single one of those queries hits your MySQL database. These heavy database queries are the main reason the WordPress backend (especially WooCommerce) feels slow.
You can improve this by enabling Object caching for your WordPress site. Object caching stores the results of repeated database queries directly in your server’s RAM. By serving these queries from your memory instead of the hard disk, you can significantly speed up the load times of your WordPress admin page.
Implementing this manually requires installing a Redis server and manually tweaking configuration files, but we’ve made it effortless with RunCache, which includes Redis object caching.
After installing RunCache, you can enable object caching with a single toggle in your WordPress admin dashboard, without fiddling with configuration files or SSHing into the server.
Troubleshooting a slow WordPress admin doesn’t have to be a guessing game. Here is a quick diagnostic cheat sheet to help you pinpoint exactly which fix will deliver the fastest results, depending on when and where you experience the lag:
Frontend fast, admin slow: Your server needs help handling raw queries. Start with OPcache, upgrading your Server Stack, and enabling Redis Object Cache.
Admin slow after a new plugin install: You are likely dealing with heavy asset bloat or conflicting background processes.
Admin slow after heavy content publishing: Your database is bogged down by thousands of auto-saves, revisions, and expired transients. Clean your database to restore speed.
Admin is slow only in the post editor: The Gutenberg editor and the WordPress Heartbeat API are hammering your server with constant AJAX requests. You can throttle the Heartbeat API to gain some performance.
Admin is slow across everything, always: Your server is fundamentally starved for basic PHP resources. You should start by increasing the PHP Memory Limit and upgrading to PHP 8.2+.
Ready to Stop Waiting on Your WordPress Admin?
Stop wasting hours battling manual server configurations, editing php.ini files, or staring at a loading spinner inside wp-admin.
With RunCloud, you don’t need to be a Linux system administrator to get enterprise-grade performance.
We provide a highly optimized NGINX and PHP-FPM server stack engineered specifically to make WordPress fly. From 1-click PHP version upgrades to instant deployment of Redis object cache via RunCache, RunCloud puts powerful, server-level optimizations right at your fingertips (no SSH or command-line experience required).
Why is WordPress admin slow, but the site loads fast?
Your front-end website loads rapidly because traditional page caching serves static HTML files to visitors, completely bypassing heavy server processing. However, these page caches are disabled for logged-in admin requests, meaning your WordPress dashboard must load dynamically every single time. As a result, your backend speed relies entirely on raw server resources, database performance, and your specific PHP configuration.
Does caching help speed up WordPress admin?
Standard page caching will not speed up your WordPress admin since it is bypassed for logged-in users to ensure dynamic content remains accurate. However, implementing a Redis object cache is highly effective for accelerating your backend performance.
How do I enable Redis object cache in WordPress?
To enable this manually, you must install a Redis server on your VPS and configure an object cache drop-in plugin within your WordPress files. For a much easier approach, you can simply install RunCache for your WordPress site. RunCache automatically provisions the Redis server and seamlessly configures the required WordPress drop-in, instantly optimizing your database queries.
Is the WooCommerce admin slower than the regular WordPress admin?
Yes, the WooCommerce admin is often slower than a standard WordPress backend because e-commerce platforms run significantly more database queries per page. Tasks like processing orders, checking inventory, and calculating analytics put a heavy, dynamic strain on your server’s database.
If you’re running NGINX on a modern server, you’re likely leaving performance on the table by sticking with HTTP/2.
HTTP/3 changes how browsers connect to your server. It reduces latency, improves performance on unstable networks, and can noticeably speed up real-world page loads – especially for mobile users.
The problem is that enabling HTTP/3 on NGINX isn’t straightforward. It requires the right version, specific modules, firewall changes, and careful configuration. One small mistake can stop NGINX from restarting.
In this guide, you’ll learn exactly how to enable HTTP/3 on NGINX step by step – from checking compatibility to verifying that it’s working correctly.
Step-by-Step Instructions for Enabling HTTP/3 on NGINX
Use the steps below to enable and verify HTTP/3 on your Ubuntu server.
Step 1: Ensure You Meet Prerequisites for HTTP/3
Before enabling HTTP/3 (QUIC) on your Ubuntu server, ensure your environment meets the prerequisites. Since HTTP/3 works over UDP rather than TCP, your underlying web server, network firewall, and encryption standards must support it.
NGINX Version Supports HTTP/3
The most important requirement for enabling HTTP/3 is having a compatible NGINX version. According to the official NGINX QUIC documentation, support for QUIC and HTTP/3 was officially introduced in NGINX version 1.25.0. In these newer releases, the required ngx_http_v3_module is included in the official Linux binary packages by default.
How to Check Your Current Version: Run the following command to check your NGINX version and its compiled modules:
Look for nginx version: nginx/1.25.0 (or higher) and ensure that --with-http_v3_module is present in the configure arguments.
If your Ubuntu repository ships older “stable” releases (like 1.18.x or 1.24.x) that do not include HTTP/3 support out of the box. Then you can install the Mainline version from the official NGINX repositories.
Run the following commands to install the necessary dependencies:
SSL Certificates are Configured (HTTP/3 Requires TLS 1.3)
Unlike older HTTP versions, where HTTPS was a secondary layer, HTTP/3 inherently requires encryption via QUIC. You cannot run HTTP/3 over unencrypted http:// connections. Additionally, the QUIC protocol mandates the use of TLS 1.3 to enable faster 0-RTT (Zero Round Trip Time) handshakes and better security.
Before proceeding, you must ensure:
You have a valid domain name pointing to your Ubuntu server’s IP address.
An SSL/TLS Certificate is configured. A free certificate from Let’s Encrypt (using Certbot) is perfect for this.
TLS 1.3 is enabled in your config. Verify that your existing NGINX server block contains TLSv1.3 in the ssl_protocols directive.
Your current HTTPS block should look something like this before adding HTTP/3:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS 1.3 MUST be included for QUIC/HTTP/3 to function
ssl_protocols TLSv1.2 TLSv1.3;
}
Root or Sudo Access to Edit NGINX Config
Finally, you will need root or sudo access to your Ubuntu server. Upgrading to HTTP/3 requires modifying core NGINX configuration files, tweaking firewall rules, and restarting system services.
Step 2: Open UDP Port 443 on Your Firewall
Unlike HTTP/1.1 and HTTP/2 which rely on TCP, HTTP/3 uses the QUIC protocol, which operates entirely over UDP. If you don’t explicitly open UDP port 443 on your firewall, client requests will never reach your NGINX HTTP/3 listener, and browsers will silently downgrade back to HTTP/2 over TCP.
UFW (Ubuntu)
If you are using Uncomplicated Firewall (UFW), which comes standard on Ubuntu, simply run:
sudo ufw allow 443/udp
sudo ufw reload
iptables
If you manage your firewall directly using iptables, run the following to append the UDP rule:
After making the changes, you need to save your iptables rules using netfilter-persistent save or iptables-save, depending on your server setup
Cloud Firewall (Hetzner, GCP, DigitalOcean)
If your server is hosted on a cloud provider, local firewall rules (UFW/iptables) are often overridden or supplemented by cloud-level security groups. The exact steps will vary depending on your cloud provider:
Hetzner Cloud: Go to your server’s “Firewalls” tab and add an Inbound rule for Protocol: UDP, Port: 443.
Google Cloud Platform (GCP): Go to VPC Network > Firewall. Create a new ingress rule targeting your instance, select UDP, and specify port 443.
DigitalOcean: Navigate to Networking > Firewalls. Add an Inbound Rule for Custom UDP on port 443.
Pro Tip: If you are using RunCloud to manage your infrastructure, our official server setup guides for providers like Hetznerand GCPcover this firewall step in great detail.
Step 3: Add the QUIC Listener and HTTP/3 Directives to Your Server Block
Now it’s time to tell NGINX to actually listen for QUIC traffic and advertise HTTP/3 capabilities to the browser.
Open your website’s NGINX configuration file (e.g., sudo nano /etc/nginx/conf.d/example.com.conf or /etc/nginx/sites-available/default).
Here is a complete, copy-paste-ready server block configured for HTTP/3:
server {
# 1. Standard TCP listener for HTTP/1.1 and HTTP/2 (Fallback)
listen 443 ssl;
# 2. UDP listener for QUIC and HTTP/3
listen 443 quic reuseport;
server_name example.com www.example.com;
# 3. SSL/TLS Certificates
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 4. Enable TLS 1.3 (Required for HTTP/3)
ssl_protocols TLSv1.2 TLSv1.3;
# 5. Core HTTP/3 Directives
http3 on;
quic_retry on;
ssl_early_data on;
# 6. Advertise HTTP/3 to clients via the Alt-Svc header
add_header Alt-Svc 'h3=":443"; ma=86400' always;
# The rest of your location blocks go here...
location / {
try_files $uri $uri/ =404;
}
}
Each directive below controls a specific part of how HTTP/3 works in NGINX. Here’s what each one does and why it matters.
listen 443 quic reuseport; Tells NGINX to listen for UDP traffic on port 443 and distributes the processing load across multiple worker processes.
http3 on; enables the HTTP/3 protocol decoding for the current server block.
ssl_protocols TLSv1.3; Configures the use of TLS 1.3, the strict encryption standard required by the QUIC protocol.
quic_retry on; Defends against UDP spoofing attacks by requiring clients to validate their IP address during the handshake.
ssl_early_data on; Enables 0-RTT (Zero Round Trip Time), allowing returning clients to resume encrypted connections instantly without handshake delays.
add_header Alt-Svc 'h3=":443"; ma=86400' always; Tells connecting web browsers, “Hey! I support HTTP/3 on port 443, remember this for the next 86,400 seconds (1 day).”
If you host multiple websites (virtual hosts) on the same NGINX server, you need to be careful with the reuseport parameter. You can only define reuseport once per IP and port combination.
For your primary website, use: listen 443 quic reuseport;
For all other websites on the same server, omit reuseport: listen 443 quic; If you put reuseport in multiple server blocks, NGINX will throw an error and refuse to start.
Whenever you alter NGINX configurations, you must test the syntax before applying the changes to prevent your live server from crashing.
Run a configuration test to confirm your changes are valid before reloading NGINX:
sudo nginx -t
If the output says nginx: configuration file /etc/nginx/nginx.conf test is successful, apply the changes instantly without dropping active connections by reloading NGINX:
sudo nginx -s reload
Step 5: Verify HTTP/3 Is Active
You can use a web-based testing tool like http3check.net to check your setup is working as expected. Simply type your website’s domain name into the search bar and click “Check”. The tool will attempt a QUIC connection from its own servers and confirm whether UDP port 443 is open, TLS 1.3 is functioning, and your NGINX instance is successfully serving HTTP/3.
Enable HTTP/3 Without Touching Config via RunCloud
Managing NGINX configurations manually can quickly become a headache, especially as your server scales. One typo in your nginx.conf, forgetting to open a UDP port, or accidentally duplicating the reuseport directive across multiple server blocks can crash your entire web server.
If you have just completed all the manual steps above, you might be wondering: Is there an easier way to do this for my next server?
The answer is ‘yes’, and the solution is RunCloud.
With RunCloud, you can skip the command line entirely, instead enabling HTTP/3 for each web application directly from your dashboard with a single toggle.
Here’s how RunCloud simplifies the process:
No SSH Required: You never have to log in to your server’s terminal to edit configuration files.
No reuseport Management: RunCloud’s automated NGINX stack intelligently handles the listen 443 quic reuseport rule across multiple domains. You never have to worry about conflicting server blocks.
One-Click Toggles: Simply navigate to your Web Application settings, toggle HTTP/3 on, and RunCloud safely reloads your NGINX server in the background.
In this post, we have discussed the steps required to enable HTTP/3 on an NGINX server. As you can see, the manual process requires several intricate steps: checking NGINX versions, configuring firewalls for UDP port 443, and carefully modifying server block directives.
While the benefits of HTTP/3 are worth the effort, manual configuration is tedious and prone to human error. You don’t have to do it this way.
You can completely skip the command line and complex configuration files by using RunCloud.
RunCloud is a server management dashboard for PHP and web applications. It provides a visual interface for configuring firewalls, managing databases, deploying code via Git, and enabling features like HTTP/3 without editing configuration files.
If you want to avoid manual setup and reduce the risk of configuration errors, sign up for RunCloudand enable HTTP/3 in a few clicks.
FAQs
Does enabling HTTP/3 break HTTP/2 or HTTP/1.1?
No, enabling HTTP/3 does not break older protocols because it runs on UDP port 443, while HTTP/2 and HTTP/1.1 operate over TCP. Modern web servers and browsers use a “fallback” mechanism that ensures that if a client doesn’t support QUIC (the foundation of HTTP/3), the connection seamlessly reverts to HTTP/2 without the user noticing.
Why does curl –http3 work but Chrome still shows HTTP/2?
Command-line tools like curl can be forced to use a specific protocol, but Chrome requires the server first to send an Alt-Svc (Alternative Services) header to “discover” that HTTP/3 is available. Because HTTP/3 runs over UDP, Chrome often completes the initial handshake over TCP (HTTP/2) and switches to HTTP/3 only for subsequent requests or after the protocol is cached in the browser’s memory.
Is HTTP/3 on NGINX production-safe?
Yes, HTTP/3 is considered production-safe and is officially supported in the NGINX mainline releases, though you should monitor your server’s CPU usage closely. Because QUIC handles encryption and packet loss at the application level rather than the kernel level, it can be more CPU-intensive than HTTP/2, especially during high-traffic spikes.
How do I disable HTTP/3 on NGINX if needed?
To disable HTTP/3, simply remove the quic and reuseport parameters from your listen 443 directives, and delete the add_header Alt-Svc line from your configuration file. Once you run nginx -s reload, the server will stop advertising QUIC capabilities and will no longer accept connections over UDP port 443, forcing all traffic back to standard TCP.
Do I need a special SSL certificate for HTTP/3?
No, your standard SSL/TLS certificate (such as a free Let’s Encrypt certificate) will work perfectly. However, the QUIC protocol explicitly requires TLS 1.3, so your NGINX configuration must enable TLS 1.3.
Most modern websites use the HTTP/2 protocol, which uses multiplexing to send multiple files over a single connection.
This works quite well for people who surf the internet using high-speed fiber or broadband. However, if you’re using an unreliable network, such as a mobile connection, then the story is quite different.
Why HTTP/2 Has a TCP Problem
HTTP/2 uses TCP, which was designed in the 1970s with strict requirements that needed reliability and ordered delivery. If a single data packet is lost in transit, TCP halts the entire connection, asks the server to resend the missing packet, and waits for it to arrive before processing anything else.
Because HTTP/2 pushes every asset (HTML, CSS, JS, Images) over a single TCP connection, a single dropped packet stalls the delivery of all other assets.
This strict sequential ordering creates “Head-of-Line (HoL) Blocking.” If you’re serving a page to a desktop user on a gigabit connection, then their packet loss is near zero, and HoL blocking is irrelevant.
However, if your traffic skews heavily toward mobile, HoL blocking has a measurable negative impact on your Core Web Vitals.
In environments with just a 2% packet loss (typical for a user on a crowded 4G network or a commuter train), HTTP/2’s HoL blocking can delay rendering by hundreds of milliseconds.
Your CSS payload might be received correctly, but the browser can’t parse it because TCP is waiting for a dropped packet from an unrelated background image.
HTTP/3 was engineered specifically to address the structural limitations of TCP that degrade performance on mobile devices, in high-latency connections, and in lossy networks.
HTTP/2 vs HTTP/3 Side by Side
HTTP/3 abandons TCP entirely. Instead, it runs on QUIC (Quick UDP Internet Connections), a protocol built on top of UDP. Let’s see what the differences are between the two protocols:
Transport Protocol: TCP vs QUIC over UDP
UDP is fundamentally different from TCP as it sends data packets without waiting for acknowledgments. It’s fast but inherently unreliable. QUIC solves this by building reliability on top of UDP.
QUIC handles packet loss recovery natively. It retains the speed and lightweight nature of UDP while intelligently managing congestion.
This shift from UDP to QUIC offers massive performance gains for mobile networks with fluctuating signal strength, but adds negligible differences for users hardwired to a corporate LAN.
TCP and TLS 1.2/1.3 require separate handshakes to establish a connection. An HTTP/2 connection requires 2 to 3 round-trip times (RTT), i.e., several messages are sent back and forth between your browser and the server before you can start seeing the actual data for your website.
HTTP/3 bakes the cryptographic handshake directly into the transport layer. This works differently in different cases:
First visits: When a user visits the website, the server establishes a connection in a single round-trip.
Returning visitors: For all the subsequent requests to the same server, QUIC enables 0-RTT (Zero Round Trip Time). The browser remembers the server and sends HTTP requests in the very first packet.
The Data: On a high-latency 3G/4G connection (e.g., 100ms ping), moving from 3-RTT to 0-RTT shaves up to 300ms off your Time to First Byte (TTFB).
Independent Streams vs Shared Connection
While HTTP/2 uses logical multiplexing within a single TCP tunnel, HTTP/3 uses cryptographic multiplexing via QUIC.
This means that in HTTP/3, streams are truly independent. If packet #44 (containing a chunk of an image) is lost on a spotty Wi-Fi network, only the stream for that specific image is paused for retransmission. The streams carrying your CSS, JavaScript, and HTML continue rendering without interruption.
This significantly improves Largest Contentful Paint (LCP) and First Contentful Paint (FCP), especially under poor network conditions.
Mandatory TLS 1.3 in HTTP/3
With HTTP/2, encryption was technically optional (though practically enforced by browsers). In a standard TCP connection, the payload (your website data) is encrypted, but the transport headers (packet numbers, sequence details, flags) are sent in clear text.
In contrast, QUIC uses TLS 1.3 directly during its own connection establishment. When a client connects to a server via HTTP/3, the transport handshake (saying “hello, let’s connect”) and the cryptographic handshake (exchanging TLS 1.3 keys) occur simultaneously in the very first packet. If the client doesn’t support or provide TLS 1.3 key negotiation, the QUIC connection can’t be established. There is no mechanism in the protocol to complete a connection first and secure it later.
This prevents middleboxes (such as ISP routers or corporate firewalls) from inspecting or manipulating transport-layer data, reducing the likelihood of network-level interference that often causes TCP connections to drop.
A frequent issue for mobile users is switching networks, as may happen when walking out of a building and dropping from Wi-Fi to a 5G cellular network, for example.
HTTP/2 (TCP): Connections are tied to the user’s IP address. When the IP changes from Wi-Fi to 5G, the TCP connection breaks. The server and browser must negotiate a completely new connection from scratch, stalling the page load.
HTTP/3 (QUIC): Connections use a unique “Connection ID” rather than an IP address. When the user’s IP address changes, QUIC seamlessly migrates the existing connection to the new IP address.
This delivers a flawless, uninterrupted user experience for mobile users on the go. It has no impact on stationary desktop users.
Is HTTP/3 Supported on Your Stack?
Before you begin modifying configuration files or adjusting firewall rules, verify that the layers of your hosting are fully prepared to handle QUIC traffic over UDP. The transition to the HTTP3 protocol has picked up pace in 2026, and it’s highly likely that your audience’s devices are already using it.
According to recent data from Cloudflare Radar, HTTP/3 now accounts for an impressive 31.2% of all human web traffic worldwide, while HTTP/2 maintains the majority share at 59.1%, and legacy HTTP/1.x traffic has steadily declined to just 9.6%.
When analyzing the distribution of secure network connections, Cloudflare Radar reports that QUIC directly handles 31.7% of all encrypted traffic, operating efficiently alongside traditional TLS 1.3, which handles 65.7%, while outdated TLS 1.2 connections have dwindled to a mere 2.6%.
This rapid, widespread adoption proves that the global infrastructure is ready, but your individual server stack still dictates how seamlessly you can implement it.
Browser Support: Chrome, Firefox, Safari, Edge
From the client-side perspective, compatibility is essentially solved because the development teams behind Chrome, Firefox, Safari, and Edge have deeply integrated native HTTP/3 support into their modern browser releases.
When a modern browser receives the Alt-Svc header from your server advertising that HTTP/3 is available, it will attempt to negotiate a QUIC connection in the background. However, if the browser discovers that UDP port 443 is blocked or heavily throttled on the user’s local network, it will silently and instantaneously revert the connection to standard HTTP/2 over TCP without ever surfacing a timeout error or disrupting the end user’s browsing experience.
Web Server Support: NGINX, Caddy, LiteSpeed, Apache
While client-side support is essentially universal, the server-side support is somewhat fragmented, meaning your specific web server software will entirely dictate your architectural approach and implementation strategy.
NGINX: If you are running NGINX, native HTTP/3 support is now fully available and highly stable, but using it requires updating your environment to version 1.25.0 and ensuring that your binary was explicitly compiled with the official ngx_http_v3_module enabled.
Caddy & LiteSpeed: If your backend infrastructure relies on modern, aggressively performance-focused web servers like Caddy or LiteSpeed, you will benefit from a much smoother deployment process, as both platforms feature highly mature, out-of-the-box HTTP/3 integration that requires practically zero manual configuration to activate.
Apache & Apache APISIX: The traditional Apache HTTP Server (httpd) still significantly lags behind its modern competitors. However, if your infrastructure uses Apache APISIX, you can enable HTTP/3 for downstream client connections by modifying the config.yaml file.
While this configuration allows you to use QUIC’s 0-RTT, the official Apache documentation strictly warns that this functionality is currently considered experimental and explicitly advises administrators against deploying it in live production environments.
Until these native experimental features are released as stable versions, placing your classic Apache server behind an HTTP/3-capable CDN (as discussed below) is the only feasible solution.
The web is constantly evolving, and at RunCloud, we want to help you stay on the leading edge with the latest protocols.
You might be apprehensive about upgrading your production server to a brand-new protocol, and you’d be right to be cautious.
However, unlike previous major protocol shifts, adopting HTTP/3 is a zero-risk move. It is explicitly designed to work in parallel with HTTP/2 and HTTP/1.1, rather than replacing them. Modern browsers will simply use HTTP/3 (h3) if the server offers it and the network allows it. If not, they instantly fall back to HTTP/2 (h2) without interrupting the user experience.
Let’s see how we can enable HTTP/3 without adding unnecessary architectural complexity.
Method 1: Use CDN (Recommended for Immediate Deployment)
By using a modern CDN, server administrators can bypass the complexities of modifying origin server configurations, compiling experimental web server modules, or reconfiguring restrictive cloud firewalls to accept UDP traffic.
The CDN handles the computationally heavy QUIC connection termination at the edge nodes located closest to the end user, and then seamlessly proxies that traffic back to your origin server over a standard, thoroughly tested HTTP/2 TCP connection.
Because dashboard interfaces and underlying infrastructure architectures vary significantly across edge providers, the exact procedural steps to enable this protocol will differ by vendor, but the fundamental deployment logic remains the same.
How to Enable HTTP/3 Using Cloudflare
Cloudflare makes upgrading to HTTP/3 incredibly easy for beginners. You don’t need to configure complex UDP ports on your server or manually install TLS 1.3 security certificates. Cloudflare automatically handles all the heavy technical lifting on its global edge network. When you turn this feature on, Cloudflare instantly starts offering the faster QUIC protocol to your mobile and desktop visitors.
Follow these steps to enable the protocol from your dashboard:
Log in to your Cloudflare dashboard and click the domain you want to speed up.
In the left-hand sidebar menu, click on Speed and go to the Settings tab.
Scroll down the page until you find the section labeled Protocol. Here, you will see a list of network-layer optimization options.
Find the HTTP/3 option and toggle the switch to ON.
Right below the HTTP/3 toggle, find the 0-RTT Connection Resumption option and turn it ON. This feature works perfectly with HTTP/3 to make your website load almost instantly for returning visitors by skipping the initial security handshake.
Once you save your settings, Cloudflare will automatically serve all web requests using the best-supported protocol for your visitors.
How to Enable HTTP/3 Using AWS CloudFront
If you’re using AWS CloudFront (Amazon’s Content Delivery Network) to intercept and speed up the traffic at the edge of the network. This approach completely protects your underlying EC2 instances and load balancers from any risky configuration mistakes.
Follow these steps to update your AWS distribution to use the newest web protocols:
Log in to the AWS Management Console and open the CloudFront dashboard.
Look at your list of delivery networks, then click your target Distribution to open its details.
On the main General settings panel, click the Edit button to begin making changes.
Scroll down the edit page until you reach the section titled “Supported HTTP versions.”
You will notice that AWS selects HTTP/1.0 and HTTP/1.1 by default, so older web browsers can still access your site. To modernize your setup, explicitly check the boxes next to both HTTP/2 and HTTP/3.
Click the Save changes button at the bottom of the screen.
AWS will take a few minutes to update its global network. Once the deployment finishes, CloudFront will automatically start terminating QUIC connections at the edge to give your visitors a faster browsing experience.
Method 2: The Origin Server Method (NGINX)
If you manage your own bare-metal or VPS and want HTTP/3 at the origin, you need NGINX version 1.25.0 or the mainline branch (which includes the official QUIC module).
Step 1: Open UDP Port 443.
HTTP/3 requires UDP traffic. Your firewall (ufw, iptables, or AWS Security Groups) must allow UDP on port 443.
sudo ufw allow 443/udp
Step 2: Update NGINX Configuration
Edit your server block to listen for both TCP (HTTP/2) and UDP (HTTP/3), and add the Alt-Svc header so browsers know HTTP/3 is available.
server {
# Listen on TCP for HTTP/1.1 and HTTP/2
listen 443 ssl;
http2 on;
# Listen on UDP for HTTP/3 (QUIC)
listen 443 quic reuseport;
server_name yourdomain.com;
# TLS 1.3 is strictly required
ssl_protocols TLSv1.3;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# Broadcast to browsers that HTTP/3 is available
add_header Alt-Svc 'h3=":443"; ma=86400';
location / {
# Your standard proxy or root directives
}
}
Step 3: Test and Validate
Restart NGINX (systemctl restart nginx). Open Chrome DevTools, navigate to the Network tab, right-click the column headers, and check Protocol. Reload the page a few times. You should see h3 appear instead of h2 for your primary document and assets.
Method 3: Enabling HTTP/3 with RunCloud
If you manage your own servers, manually compiling experimental modules or editing NGINX configuration files via SSH introduces unnecessary risk and leaves significant room for human error. A single typo in your server block can instantly break your production site.
RunCloud offers a vastly superior, fully automated alternative, with an intuitive dashboard to manage everything.
RunCloud deploys a custom NGINX stack that is already optimized for modern protocols, allowing you to modernize your infrastructure with zero technical friction.
With RunCloud, you never have to touch a configuration file to get QUIC running. The platform handles the complex port binding and header injections for you.
Open your Web Application: Log in to your RunCloud dashboard and navigate to the specific Web Application you want to optimize.
Navigate to SSL/TLS Settings: Open the settings panel where you manage your domains and security certificates.
Enable the Protocol: Simply click the checkbox next to Use HTTP/3.
That’s the entire process! Because HTTP/3 requires TLS 1.3, RunCloud automatically generates, installs, and manages the lifecycle of your SSL certificates behind the scenes. You get all the performance benefits of an enterprise-grade setup without the administrative headache of rotating certificates or debugging connection failures.
Important Firewall Note: Before you check the HTTP/3 box in RunCloud, ensure your infrastructure allows the traffic. If you’re hosting on providers such as Hetzner or Google Cloud Platform (GCP), their external network firewalls block UDP traffic by default. You will need to open UDP port 443 at the cloud provider level first. If you’re spinning up a new server, our server setup guides for Hetzner and Google Cloud Platform cover this firewall step. Once the port is open, RunCloud handles the rest of the web server configuration automatically.
HTTP/2 or HTTP/3: Which One is Better?
If your site traffic is predominantly desktop users on reliable broadband connections, HTTP/3 won’t significantly alter your performance metrics. In environments with near-zero packet loss, the data shows HTTP/2 and HTTP/3 perform almost identically.
However, if your audience includes a large percentage of mobile users, spans across multiple continents, or frequently accesses your application from lossy network environments, HTTP/3 is a low-risk, high-reward upgrade.
Real-world telemetry shows that switching to QUIC under a 2% packet-loss scenario can reduce Largest Contentful Paint (LCP) delays by hundreds of milliseconds. Because modern clients gracefully fall back to HTTP/2 when UDP fails, there is zero downside to enabling it.
Yes, HTTP/3 is significantly faster than HTTP/2 because it uses the QUIC protocol instead of TCP, effectively eliminating head-of-line blocking. This architectural upgrade allows web pages to load much more quickly and maintain highly stable connections, especially on unreliable mobile networks.
Do I need to disable HTTP/2 to use HTTP/3?
No, you do not need to disable HTTP/2 because modern web browsers and servers automatically negotiate the highest supported protocol. Keeping both protocols enabled ensures backward compatibility with older devices while delivering the maximum HTTP/3 speeds to updated browsers.
Does HTTP/3 affect SEO or Core Web Vitals?
Implementing HTTP/3 positively impacts SEO by directly improving crucial Core Web Vitals metrics, such as Largest Contentful Paint (LCP) and Interaction to Next Paint (INP). Because Google uses page load speeds as a ranking factor, this enhanced technical performance signals a superior user experience and can boost your organic search visibility.
Does HTTP/3 require TLS?
Yes, HTTP/3 strictly requires TLS 1.3 encryption, which is built into the QUIC transport protocol. This mandatory cryptographic standard ensures that all data connections are established much faster while remaining inherently secure against modern cyber threats.
Is HTTP/3 safe to enable in production?
HTTP/3 is widely considered safe, highly stable, and strongly recommended for live production environments by web performance experts. Because top-tier tech platforms and global CDNs already use it by default, you can confidently enable it to enhance your website’s speed and security reliably.
Is your WordPress website loading quickly for local users, but frustratingly slow for visitors on the other side of the world?
In modern SEO, website speed is a key ranking factor. If your site takes too long to load, frustrated visitors will simply leave, costing you both traffic and sales.
In this beginner-friendly guide, we will break down exactly what edge caching means and why it drastically lowers your Time to First Byte (and what that is!).
You’ll learn how modern Content Delivery Networks cache full HTML pages and how to do it safely without breaking dynamic pages like WooCommerce.
Why Edge Caching Speeds Up WordPress
If your main WordPress hosting server is located in New York, a visitor from London will naturally experience a slower loading time than a visitor from Brooklyn. This happens because data has to physically travel across the ocean.
Edge caching solves this distance problem by ensuring your website loads instantly for everyone, no matter where they live.
What Edge Caching Means for WordPress
To understand edge caching, think of a massive central warehouse (your web host) and dozens of small, local retail stores (the “edge” servers).
Normally, whenever a user visits your website, their browser must request the website files directly from your main web host. Edge caching changes this by saving a copy of your WordPress site on a global network of servers (a Content Delivery Network, or CDN).
When someone visits your website, the server closest to them (the “edge”) serves it. Because the data travels a much shorter distance, your website appears on their screen in the blink of an eye.
How Caching HTML at the Edge Cuts TTFB for Global Visitors
TTFB stands for Time to First Byte. It’s a metric that measures exactly how long it takes a user’s browser to receive the very first data from your website. A lower TTFB means a faster website.
In the past, CDNs only saved “static” files like images or fonts. Your main server still had to do the heavy lifting of building the actual web page (the HTML) for every single visitor. Today, modern edge caching stores the entire, fully built HTML page directly on edge servers.
Here is why caching HTML is a game-changer for your SEO and speed:
Zero Database Queries: WordPress doesn’t have to waste time searching its database to build the page.
No PHP Processing: The server doesn’t have to run complex code. It just hands the pre-built page to the visitor.
Instant Delivery: Because the fully built page is waiting right next door to the user, your TTFB drops from over a second to just milliseconds.
While edge caching is incredibly powerful, it’s not a magic fix for everything. Because edge caching is designed to serve static copies of pages to the public, it automatically turns off in a few specific situations.
Edge caching will not speed up your site in these scenarios:
Logged-In Traffic: If a user is logged in to your site (e.g., a member or WordPress administrator), they need to see personalized, live content. The edge cache is bypassed, so they don’t see an old, cached version of the dashboard.
Uncached Dynamic Pages: E-commerce pages, such as WooCommerce Shopping Cart or Checkout pages, cannot be cached. If they were, shoppers might see other people’s items!
A Slow Backend Server: Edge caching hides a slow server from your public readers. However, anytime a visitor needs to do something dynamic (like submit a contact form, use a search bar, or process a payment), the request must go back to your original WordPress host. If your hosting provider is slow or your database is bloated, these actions will still feel slow.
Configuring edge caching for WordPress might sound highly technical, but the steps are quite simple. Here is the exact step-by-step process for implementing edge caching in WordPress.
Step 1: Pick your edge caching approach
Before changing any settings, you must decide how you want your CDN to interact with your WordPress host. There are two primary approaches:
Origin Page Cache + CDN (Traditional Method): Your WordPress server (the origin) generates and caches the HTML page locally. The CDN is used only to deliver static assets such as images, CSS, and JavaScript. While this is easy to set up, global visitors still have to wait for the HTML document to travel from your main server, keeping your Time to First Byte (TTFB) higher than ideal.
CDN HTML Cache (Full Page Edge Caching): The CDN stores a complete copy of the HTML document on its global edge servers. This is the preferred method for maximum speed worldwide. When a user requests a page, the edge server delivers the HTML instantly without ever contacting your WordPress host.
RunCache (All-in-one): For most users, Cloudflare Automatic Platform Optimization is the gold standard for CDN HTML caching. Cloudflare’s data shows that APO can improve TTFB by up to 72% globally. To get the absolute best results, we highly recommend using the RunCache Cloudflare Integration.
This integration seamlessly bridges your local WordPress cache with Cloudflare’s global edge network. It also ensures that whenever you update a post or change a product, the edge cache is purged and rebuilt instantly, giving you blazing-fast global speeds without the headache of showing outdated content.
Step 2: Enable Edge Caching on WordPress
For this tutorial, we will be using RunCache with Cloudflare’s global CDN to serve your entire website from edge locations closer to your visitors. Follow these steps to generate a secure API token and connect your site.
Step 2.1: Generate a Custom Cloudflare API Token
To maintain high security, we recommend creating a “Custom Token” with limited permissions rather than using your Global API Key.
In the left menu, click on Manage Account and select Account API tokens.
Click Create Token, then locate Create Custom Token at the bottom and click Get Started.
Token Name: Enter a name like RunCache – [Your Site Name].
Permissions: Add the following three permissions:
Zone: Cache Rules: Edit
Zone: Cache Purge: Purge
Zone: Zone: Read
Zone Resources: Under “Include,” select Specific zone and choose the domain you are currently configuring.
Click Continue to Summary, then Create Token.
After creating the token, copy it immediately and store it in a safe place – Cloudflare will not show it to you again.
Step 2.2: Ensure Your Domain is Proxied
Cloudflare caching only works if your traffic is flowing through their network.
In your Cloudflare Dashboard, go to the DNS tab for your domain.
Locate your A or CNAME records (usually for your root domain and the www subdomain).
Ensure the Proxy status toggle is set to Proxied (the cloud icon should be Orange). If it is “DNS Only” (Grey), Cloudflare’s cache will not be active.
Step 2.3: Enable Cloudflare in the RunCache Plugin
Now that you have your token and your DNS is ready, connect the plugin to Cloudflare.
Log in to your WordPress Admin Dashboard.
Navigate to RunCache in the sidebar and click on the Full Page Cache tab.
Enable Cloudflare from the list of cache providers.
Paste your newly created token into the API Token field.
Click Save Settings.
Once connected, RunCache will automatically communicate with Cloudflare to manage your cache, purge outdated content when you update posts, and ensure your visitors receive the fastest possible delivery via the Cloudflare edge network.
Step 2: Set the right cache headers for HTML and assets
Note: if you are using RunCache, all HTTP headers are handled intelligently by RunCache, and you don’t need to configure them manually.
CDNs don’t just guess what to cache – they follow strict instructions sent by your server, called HTTP Headers. To make edge caching work perfectly, you need to configure the following directives in Cache-Control headers correctly:
max-age: This tells the visitor’s local web browser how long to store the file. For edge-cached HTML, you usually want this set to a low value (e.g., max-age=3600) so browsers always request the latest version from the CDN.
s-maxage (Shared Max-Age): The “s” stands for shared cache (your CDN). This tells the edge server how long to hold onto the HTML file. A good rule for WordPress posts is s-maxage=604800 (7 days).
stale-while-revalidate: If an edge-cached page expires after 7 days, this directive tells the CDN to immediately serve the “stale” (expired) page to subsequent visitors so they don’t have to wait. In the background, the CDN quietly fetches the latest version from your WordPress server for future visitors. Setting stale-while-revalidate=86400 (24 hours) keeps your site feeling instantly fast 100% of the time.
Step 3: Add bypass rules for logged-in users, WooCommerce, and dynamic cookies
Note: if you are using RunCache, this step is handled automatically.
The biggest risk of edge caching is caching private or dynamic information by accident. If an edge server caches a page while you are logged in, it might show your WordPress admin bar to regular visitors. To prevent this, you must set up Bypass Rules (also known as Cache Exclusions) in your CDN dashboard or via your caching plugin.
If you’re using RunCache, you can manage these settings under the Rules tab.
Important Bypass Rules for WordPress:
Logged-in Users: Tell the CDN to completely bypass the cache if the browser contains the wordpress_logged_in_* cookie.
WooCommerce Cookies: Exclude caching for any user carrying the woocommerce_items_in_cart or wp_woocommerce_session_* cookies.
Dynamic URLs: Force the CDN to bypass the cache for specific URL paths, including:
/wp-admin/*
/cart/
/checkout/
/my-account/
By setting these rules, your public blog posts and landing pages will load from the edge instantly, while your secure, dynamic pages will safely load directly from your origin server.
Step 4: Verify edge caching is working using response headers and DevTools
Once you’ve configured your setup, you should test it to ensure the HTML is actually being served from the edge. You don’t need any fancy software to do this – just your web browser.
Open your website in an Incognito/Private window (to ensure you aren’t logged in).
Right-click on the page and select “Inspect” to open Developer Tools.
Click the “Network” tab, then refresh the page (press F5).
Then click the network request that you want to inspect.
Look at the “Response Headers” section on the right side.
In the response section, you need to look for the following response headers x-cache: HIT or x-runcache-status: HIT. If it says “MISS”, refresh the page one more time to prime the cache. Once it says “HIT”, your HTML is successfully loading from the edge.
Edge caching is the best strategy for delivering a lightning-fast WordPress experience to visitors worldwide. However, maximizing these speed benefits requires careful management to avoid common pitfalls.
Edge caching significantly reduces the daily workload on your origin server, but you still need a clean, conflict-free setup to keep your backend fast under heavy load. Running multiple overlapping caching layers often leads to messy system conflicts, which is why RunCloud built Runcache.
Runcache is a modern WordPress caching plugin that consolidates all caches (local page cache, Redis object cache, and edge network) into one streamlined layer.
And the best part is that RunCache works with any WordPress site on any host, not just those hosted on RunCloud.
Edge caching in WordPress stores a copy of your website on servers located very close to your visitors. These servers are part of a global Content Delivery Network (CDN) with hundreds of worldwide locations. When a user visits your site, the closest edge server delivers the content instead of your primary web host.
Does edge caching cache HTML or only static files?
Traditional CDNs only cache static files, such as images, CSS, and JavaScript. However, modern edge caching also caches your fully generated WordPress HTML pages. This advanced process is known as full-page edge caching. By caching HTML at the edge, your site can handle thousands of concurrent visitors without crashing. Only dynamic requests, such as form submissions, bypass the cache and reach your origin server.
What WooCommerce pages should never be cached?
You must never cache dynamic WooCommerce pages that contain personal user data. The three main pages to absolutely exclude from caching are the Cart, Checkout, and My Account pages. If you cache these pages, a customer might accidentally see another shopper’s private billing information.
Why do I still see old content after a purge?
You usually see old content because of local browser caching. You can easily fix this by performing a hard refresh using Ctrl+F5 on Windows or Cmd+Shift+R on a Mac. Another common reason is multiple active caching layers. You might have cleared your CDN edge cache, but your WordPress caching plugin or server object cache still holds the old data.
Should I use edge caching with a WordPress caching plugin?
Yes, you should absolutely use edge caching alongside a high-quality WordPress caching plugin. Edge caching excels at delivering your website files globally at lightning speeds. Meanwhile, a local caching plugin handles critical on-site performance optimizations.
If your WordPress site feels sluggish despite having a great theme and high-quality hosting, the bottleneck is likely your database.
Every time a visitor loads a page, WordPress performs dozens of queries to fetch settings, menu structures, and widget content from your MySQL database.
Object caching changes this by storing repetitive results in RAM and serving them instantly to your visitors.
But which caching backend should you choose: Redis or Memcached?
In this guide, we will discuss the differences between these two high-performance solutions. We’ll explore why Redis has become the industry standard for complex, data-heavy sites, when Memcached might still be the smarter choice for a resource-constrained VPS. By the end of this post, you will understand which of these services is right for you.
What are Memcached and Redis?
Memcached and Redis are both high-performance, open-source, in-memory data stores, but they were designed with different architectural philosophies.
Memcached is a distributed memory object caching system designed specifically for simplicity, serving as a “pure” cache to speed up dynamic web applications by alleviating database load.
Redis, by contrast, is an advanced in-memory data structure store that functions as a cache, a primary database, and a message broker, offering a much richer feature set than a traditional key-value cache.
Performance: Speed, Throughput, and Multi-Threading
In raw read/write operations for simple key-value pairs, both systems deliver sub-millisecond latency and incredibly high throughput. Memcached uses a multi-threaded, non-blocking architecture, which makes it exceptionally efficient at handling thousands of concurrent connections on multi-core servers without significant locking contention.
While early versions of Redis were single-threaded, modern Redis supports multi-threaded I/O to improve performance on high-end hardware, while maintaining a single-threaded execution model for command processing to avoid the complexities of data locking.
For the vast majority of WordPress use cases, both systems are more than capable of handling high traffic; however, Memcached’s architectural simplicity often provides a slight edge in pure throughput for static, high-frequency key-value lookups.
Memcached and Redis differ in how they handle data and the level of persistence they offer. Let’s see how
Memcached: strings only, no persistence
Memcached is strictly a key-value store where the values are treated as unstructured blobs of data (strings). It doesn’t understand the content of the data it stores, meaning if you need to update a single element within a large object, your application must retrieve the entire object, modify it in application memory, and write the whole blob back to the cache.
Memcached is designed to be volatile; it offers no mechanism to save data to disk, meaning all cached items are lost instantly if the service restarts.
Redis data structures (hashes, sets, lists, sorted sets)
Redis provides a powerful set of native data structures that enable developers to perform operations directly on the server. With Hashes (ideal for storing objects like user profiles), Lists, Sets, and Sorted Sets (perfect for leaderboards or queueing), you can perform granular tasks, such as pushing a new item to a list or incrementing a counter, without fetching and replacing the entire dataset.
This reduces network bandwidth and CPU overhead, making Redis significantly more flexible for complex applications that require more than just simple caching.
A key differentiator for Redis is its ability to persist data, which is achieved through two primary mechanisms: RDB (Redis Database Backup) and AOF (Append Only File).
RDB Snapshots: This performs point-in-time snapshots of your dataset at specified intervals (e.g., every 60 minutes if 1,000 keys changed). It is highly efficient for backups and recovery, though it carries a small risk of losing data created between the last snapshot and a crash.
AOF Logging: This logs every write operation received by the server into a file, which is then replayed upon startup to reconstruct the original dataset. AOF provides much higher data durability than RDB, as it can be configured to sync to disk after every write operation, effectively turning Redis into a reliable, persistent database rather than just a transient cache.
How WordPress object caching works (WP_CACHE, drop-in)
WordPress has a built-in object caching system that prevents redundant database queries. By default, this cache is non-persistent, meaning it exists only for a single page load. To make this persistent, meaning the cache stays alive across different page visits, you must enable the WP_CACHE constant in your wp-config.php file.
In WordPress, a drop-in is a special type of file that WordPress core checks during its initialization. If WordPress finds a file named object-cache.php inside your /wp-content/ directory, it automatically loads it instead of using its default (non-persistent) caching mechanism.
Here is the breakdown of how this process works, the standard implementation steps, and the conceptual bridge it creates:
Default Behavior: Without a drop-in, WordPress uses its internal WP_Object_Cache class. This class stores data in PHP memory, but that memory is wiped clean at the exact moment a page finishes loading. The next time a user visits, WordPress must query the database again.
The Interception: When the object-cache.php file exists, WordPress skips the default WP_Object_Cache class and use the code defined inside that drop-in file instead.
The Persistent Connection: The drop-in file contains the logic to connect to an external, memory-based storage server (like Redis or Memcached). Because this storage server exists outside the scope of a single PHP request, the data persists between page loads. Now, when WordPress needs a database result, it asks the drop-in file, which fetches it from RAM (the cache server) instead of triggering a slow MySQL query.
Choosing between Redis and Memcached for WordPress object caching can be confusing, but understanding how they interact with your database is key to unlocking faster page load times.
Memcached with W3 Total Cache or Object Cache Pro
Memcached is the “classic” choice for WordPress performance. It’s extremely lightweight and focuses on a single task: storing simple key-value pairs in memory. When using plugins like W3 Total Cache, Memcached is often the default choice because of its simplicity and low resource requirements.
If you’re using a managed WordPress host or a performance-heavy plugin such as Object Cache Pro, you may find that Memcached performs exceptionally well for basic site speed. Because it’s multi-threaded and doesn’t handle disk writes, it can handle massive bursts of read requests with very little CPU overhead, making it ideal for standard, content-heavy websites.
Redis with WP Redis / Object Cache Pro
Redis has become the industry standard and the modern “default” for most high-performance WordPress hosts. Plugins such as WP Redis or the enterprise-grade Object Cache Pro allow WordPress to use Redis’s advanced data structures.
Unlike Memcached, Redis can handle complex data structures, allowing WordPress to store related data together in “hashes” or “sets”. This means that when WordPress needs to update a piece of information, it can talk to Redis more intelligently, reducing the need to constantly delete and rewrite large chunks of data.
Which performs better for WP transients and session data?
When comparing performance for transients (temporary database entries including plugin data, API responses, or WooCommerce cart items) and session data, Redis is the clear winner.
Why for Transients: WordPress transients often need to be expired or searched based on specific criteria. Because Redis supports sorted sets and hashes, it can manage these transient expirations more efficiently than Memcached.
Why for Sessions: Because Redis supports persistence, your user session data remains intact even if you restart your server or clear the cache. Memcached would wipe all active user sessions if the server restarts, forcing your visitors to log in again.
Wrapping Up: Which Object Caching Tool Should You Use – Memcached Or Redis?
Deciding between Memcached and Redis ultimately comes down to your server resources and the complexity of your WordPress site.
If you’re running a lightweight site on a resource-constrained VPS, Memcached’s minimal memory footprint makes it an excellent choice for basic query acceleration.
However, for most modern WordPress environments, especially those using WooCommerce, complex page builders, or high-volume transient data, Redis is the superior option.
Manually managing caching services via SSH can be tricky, especially when configuring PHP-FPM worker pools or adjusting php.ini settings.
RunCachehas simplified this process by providing native, one-click toggles to enable caching for your WordPress web application.
This approach ensures you don’t need to manually touch configuration files, reducing the risk of downtime while optimizing cache performance.
Whether you choose the lean profile of Memcached or the feature-rich capabilities of Redis, RunCloud ensures your site remains lightning-fast, secure, and easy to maintain.
While both provide excellent performance, Redis is often considered superior for complex WordPress environments because it supports advanced data structures and atomic operations. However, for simple key-value caching, the speed difference is usually negligible, meaning the “faster” choice often depends more on your specific server configuration and plugin implementation than the software itself.
Can Memcached persist data across server restarts?
No, Memcached is a purely volatile, in-memory key-value store, and it doesn’t have native support for persisting data to disk. If your server restarts or the Memcached service is stopped, all cached data is permanently cleared and must be rebuilt by your application.
Does WordPress support Memcached as an object cache backend?
Yes, WordPress has native support for Memcached as an object cache backend through the use of a persistent object cache plugin. By dropping an object-cache.php file into your wp-content directory, WordPress can efficiently store and retrieve database query results in RAM rather than querying your MySQL database repeatedly.
What is the difference between Redis and Memcached for PHP sessions?
The primary difference is that Redis provides persistence, allowing PHP sessions to survive server reboots, whereas Memcached loses all session data upon restart. Additionally, Redis offers better reliability for high-traffic sites due to its ability to handle more complex data types and provide snapshots of session states.
Should I use Redis or Memcached on a VPS with limited RAM?
Memcached is generally the better choice for a VPS with extremely limited RAM because it has a smaller memory footprint and lower overhead than Redis. Redis includes more features, such as data persistence and complex data structures, which consume more memory resources even when idle.
What is Valkey and does it replace Redis for WordPress caching?
Valkey is an open-source, community-driven fork of Redis created to ensure the project remains under a permissive license following changes to Redis’s licensing model. It’s fully compatible with existing Redis implementations, making it an excellent drop-in replacement that works seamlessly with WordPress caching plugins that support Redis.
DNS translates domain names into IP addresses so your system knows where to connect. In this guide, you will learn exactly how to check DNS server settings in Linux across all major distributions, including Ubuntu, Debian, CentOS, and RHEL.
You’ll learn the difference between static configuration files and dynamic network managers so you can accurately list DNS servers for troubleshooting or security audits.
Whether you’re a system administrator working via SSH or a desktop user navigating the GNOME interface, this comprehensive walkthrough ensures you never have to wonder “which DNS am I using” again.
How to Find the Current DNS Server in Linux
There are four common ways to view the DNS server settings in Linux:
Method 1: Check Your DNS Server with the Terminal
The Linux terminal is an incredibly powerful tool, and for tasks like this, it’s often the fastest way to get the information you need. You can get this information quickly with a single command. Follow the steps below to get started:
Step 1: Open the Terminal
First, open the terminal application. You can find it in your applications menu, or use the common keyboard shortcut: Ctrl + Alt + T.
This will open up a new window, where you can enter your commands. If you are connected to the server via SSH, then you don’t need to take any additional steps. You can type your commands in this shell, as it’s the terminal itself.
Step 2: Check the resolv.conf File
For this step, you will use the cat command, which simply reads a file and displays its contents on the screen.
In your terminal, type the following command and press Enter:
cat /etc/resolv.conf
You will see an output similar to the image below:
Look for the line that starts with nameserver. The IP address immediately following it is the DNS server your system is configured to use. In the example above, the DNS server is 192.168.0.1.
If you see an address like 192.168.0.1, your system is using your router for DNS, which then forwards the request to your ISP. This is a very common and default setup.
If you have explicitly defined the DNS servers in your network configuration, then you might get an output similar to the following image:
In the above example, the computer is using three different DNS servers with the following IP addresses: 1.1.1.1, 8.8.8.8, and 9.9.9.9, which belong to Cloudflare, Google, and Quad9, respectively.
systemd-resolved vs /etc/resolv.conf
If you run cat /etc/resolv.conf on modern Linux distributions (like Ubuntu 18.04 and later), you will see a nameserver entry for 127.0.0.53. This doesn’t mean your actual DNS server is on your own machine.
On these systems, /etc/resolv.conf is often a symbolic link to a “stub” file managed by systemd-resolved. The 127.0.0.53 address is a local DNS stub listener that forwards your requests to the actual upstream DNS servers.
While this file is technically “accurate” for the OS, it doesn’t list the external DNS providers (like Google or Cloudflare) you’re actually using. To see the true upstream nameservers on these systems, you must use Method 3 (resolvectl) or Method 4 (nmcli).
Method 2: Find The DNS Server in Linux Using The GNOME Graphical Interface
If you prefer clicking over typing, Linux desktop environments such as GNOME provide a user-friendly way to see your network settings.
Step 1: Open Your System Settings
Click on the system tray area in the top-right corner of your screen, where you see the icons for Wi-Fi, volume, and power. In the menu that appears, click the gear icon (⚙️) to open the Settings window.
Step 2: Go to Network Settings
In the Settings window, look at the menu on the left-hand side. Click on either Wi-Fi or Wired, depending on your connection method.
Step 3: Open Your Active Connection’s Details
You will now see a list of available networks. Find the network you are currently connected to (it will be the one that’s toggled on). To the right of its name, click the gear icon (⚙️) to open its specific settings.
Step 4: Find Your DNS Entry
A new window will pop up with several tabs. It will open on the Details tab by default. Here, you can immediately see a summary of your connection. Look for the DNS entry to find your server’s IP address.
As you can see, the DNS is listed as 192.168.0.1, which matches what we found in the terminal.
Step 5: Understanding the “Automatic” Setting
To see why you have this DNS server, click on the IPv4 tab at the top of this same window.
Notice that the DNS setting has a switch toggled to Automatic. This setting, along with the Automatic (DHCP) option for IPv4 Method, instructs your computer to automatically accept the network settings provided by your router.
Most systems use DNS settings provided automatically by the router (via DHCP). Switching to Manual lets you specify your own DNS server. If you want to manually set a different DNS server (such as Google’s 8.8.8.8), toggle this switch off, then enter the new IP address in the field.
Method 3: Use resolvectl
On Linux distributions that use systemd-resolved, the resolvectl command is the recommended way to check your DNS status. This tool provides a detailed breakdown of which DNS servers are assigned to specific network interfaces.
To use this method, you first need to connect to your remote server via SSH as described in Method 1. Once you are logged in to the terminal, run the following command:
resolvectl status
Look for the “DNS Servers” and “Current DNS Server” lines under your active network interface. This will show the actual IP addresses of the DNS providers your system is querying, bypassing the local stub address.
Method 4: Use nmcli (NetworkManager Systems)
If your server uses NetworkManager to handle connections (common in RHEL, CentOS, and most Desktop environments), the nmcli tool is the most efficient way to query DNS settings directly from the networking stack.
Use the following command to display your network details:
nmcli device show | grep IP4.DNS
This command filters the output to show only the IPv4 DNS servers assigned to your active devices. It displays the DNS servers exactly as they were received from DHCP or manually configured in the NetworkManager profile.
Bonus: Query a Site Using Any DNS Server
After identifying your DNS server, you may not be completely satisfied with it. If you are facing network issues, you can bypass your local settings entirely and request a website’s IP address from any public DNS server worldwide.
Why would you do this?
If a site loads for others but not for you, your DNS server might be outdated, overloaded, or applying filters. Querying a public DNS server gives you a clean comparison.
dig @<DNS-SERVER-IP> <WEBSITE-TO-LOOKUP>
Let’s break that down:
dig: The command to run the tool.
@<DNS-SERVER-IP>: The @ symbol tells dig, “direct your question to this specific server.” Replace <DNS-SERVER-IP> with the IP address of the server you want to query, such as @8.8.8.8 for Google.
<WEBSITE-TO-LOOKUP>: The domain name you want the IP address for, such as runcloud.io.
Let’s ask Google’s public DNS server (8.8.8.8) for the IP address of runcloud.io. Open your terminal and run this command:
dig @8.8.8.8 runcloud.io
The terminal will print a block of text that might look a little intimidating at first, but don’t worry! You only need to concern yourself with one specific part.
Scroll down until you find the ;; ANSWER SECTION:. This is the response from the DNS server
runcloud.io. 300 IN A 104.26.10.235 runcloud.io. 300 IN A 104.26.11.235 runcloud.io. 300 IN A 172.67.68.114
This tells us that, according to Google’s DNS, runcloud.io has three IP addresses: 104.26.10.235, 104.26.11.235, and 172.67.68.114. It’s that simple!
If you prefer a graphical interface, Google offers a simple web tool that performs the same function. You can visit https://dns.google/ to see the same query we just ran, but in your browser.
This will display the raw DNS information in a format that computers prefer (called JSON), making it easy to spot the IP address in the “data” field. It’s a great alternative if you’re not in front of a terminal.
When Applications Bypass Your System DNS
The IP address you found using the methods above is the default DNS server for your system. However, it’s essential to note that some applications may opt to disregard it and use their own. Before you spend hours troubleshooting, be aware of these common overrides:
DNS-over-HTTPS (DoH): Modern browsers can use DNS-over-HTTPS, which bypasses your system DNS for privacy. VPNs also override DNS to keep traffic secure.
Virtual Private Networks (VPNs): When you connect to a VPN, it almost always forces your computer to use its own private DNS servers. This is a critical security feature. If your computer uses your regular DNS while connected to a VPN, your internet service provider may still be able to see which websites you’re trying to visit, defeating a key purpose of the VPN.
Next Steps for DNS Management
You now know how to check your DNS server from both the terminal and GNOME, as well as how to test any DNS provider using the dig command.
DNS checks are only one part of managing a server. RunCloud provides an easy and reliable way to deploy and manage Linux servers without manual configuration. It handles security, updates, monitoring, and performance tuning, so you can focus on your applications.
If you want a simpler way to manage Linux servers and avoid repetitive configuration work, RunCloud gives you a clean dashboard for deployments, updates, backups, and security.
How do I check which DNS server my Linux system is using?
You can check your active DNS servers by running the resolvectl status command.
Why does /etc/resolv.conf show 127.0.0.53 instead of my real DNS?
The IP address 127.0.0.53 indicates that your system is using a local DNS stub listener managed by systemd-resolved. This local service acts as an intermediary, receiving your queries and forwarding them to the actual upstream DNS servers, which you can identify using the resolvectl status command.
How do I set DNS to 8.8.8.8 in Linux?
You can set your DNS to Google’s public DNS by running nmcli connection modify [connection-name] ipv4.dns “8.8.8.8”. For persistent changes on Ubuntu servers, you must add 8.8.8.8 to the nameservers section of your configuration file in /etc/netplan/ and run sudo netplan apply.
Almost as soon as you deploy a server on the internet, it is under attack.
Within seconds, automated bots begin scanning your ports and hammering your SSH login. If you’re using the default settings on your server, then you are more likely to get compromised.
While most cloud providers offer a clean slate, those default configurations are built for convenience, not combat. To truly protect your data, you need to follow industry-standard Linux server security best practices.
Through this guide, you will have a detailed roadmap to secure your VPS with enterprise-grade security.
Why a Fresh Linux VPS Is a Target for Hackers
As soon as your cloud provider assigns a public IPv4 address to your server, the clock starts. Security researchers and malicious botnets continuously scan the entire IPv4 address space using tools such as Shodan, Censys, and Zmap.
Honeypot data consistently shows that a new, exposed Linux server will experience its first automated SSH login attempt within 3 to 5 minutes of going live.
If you leave default settings intact, it isn’t a matter of if you get breached, but when. If you don’t protect your server, an automated script will root your server, deploy a crypto-mining payload, and potentially leave you with a thousand-dollar cloud compute bill overnight.
What Does the “Attack Surface” Mean?
The “attack surface” is the exact combination of open ports, default configurations, and predictable patterns your server exposes to the internet. A fresh VPS usually has:
Port 22 open to the world: The universal beacon for SSH brute-force scripts.
Root login enabled: Giving attackers the ultimate username; they only need to guess the password.
Password authentication is enabled, allowing unlimited dictionary attacks against your login prompt.
If you provision your servers through a control panel like RunCloud, much of this attack surface is already minimized for you. But if you are managing a bare-metal VPS yourself, run the commands below to manually lock it down.
However, any one single measure won’t be enough to protect your server; that’s why we recommend following the “Swiss Cheese Model of Security”.
This model is built on the principle that security should never rely on a single control, as even the best defense has holes, or “slices” of weakness.
In this model, each layer of security (like disabling root login, configuring UFW, enabling Fail2Ban, etc.) is represented by a slice of Swiss cheese. Each slice has holes representing vulnerabilities, misconfigurations, or human error.
A single slice (one defense) is easily penetrated if an attacker’s exploit aligns with the hole in that single layer.
Multiple slices stacked together provide defense-in-depth. While the holes in the first slice (e.g., a custom SSH port) might align with the threat, the second slice (e.g., SSH key authentication) or the third slice (e.g., Fail2Ban) is highly unlikely to have a hole in the exact same spot.
By stacking all 11 steps in this guide, we can ensure that even if one defense fails, the next layer (or the layer after that) will stop the threat, preventing it from reaching your core application.
Follow the steps below to protect your Linux server on the internet:
Step 1: Disable Root Login and Create a Sudo User
Performing regular maintenance activities on your server as the root user is dangerous – a single typo can destroy your system.
To protect your system, we recommend creating an unprivileged user and granting it administrative rights via sudo.
Connect to your VPS as root, then run:
# Replace 'sysadmin' with your preferred username
adduser sysadmin
You will be prompted to set a password. Make it strong, even though we will disable password logins shortly. Skip the contact information prompts by hitting Enter.
Next, add your new user to the sudo group so you can execute administrative commands:
usermod -aG sudo sysadmin
Verify it works before logging out. Switch to your new user and test sudo:
su - sysadmin
sudo ls -la /root
If you are prompted for your password and can successfully see the contents of the root directory, your sudo user is ready.
With RunCloud, you can manage users and permissions for your Linux server directly from the web dashboard, without SSHing into the server.
Step 2: Switch to SSH Key Authentication and Disable Password Login
A secure password is hard to remember, and a weak password can be cracked immediately. That’s why all cybersecurity experts agree that cryptographic keys are a better replacement for your username/password based logins.
In this step, we are going to replace password authentication with an ed25519 SSH key pair (which is faster and more secure than older RSA keys).
Generate your key pair locally
Do not run this on your VPS. Open a new terminal on your local computer (your Mac, Windows, or local Linux machine):
ssh-keygen -t ed25519 -C "your_email@example.com"
Hit Enter to save the key to the default location (~/.ssh/id_ed25519). When prompted, you can set a strong passphrase to encrypt the key on your local disk or leave it blank if you don’t want to encrypt it.
Copy the public key and lock down the sshd_config
Still on your local computer, copy the public key to your VPS, targeting your new sudo user:
ssh-copy-id sysadmin@YOUR_VPS_IP
Now, go back to the terminal window connected to your VPS. It’s time to edit the SSH daemon configuration to disable password logins and root access permanently.
sudo nano /etc/ssh/sshd_config
Find the following lines, uncomment them (remove the #), and change their values to match these exactly:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Save and exit (CTRL+O, Enter, CTRL+X). Do not restart the SSH service just yet; we are going to change the port in the next step.
Note: RunCloud users can add SSH keys to their servers simply by pasting their public key into the RunCloud dashboard, no nano or config editing required.
Step 3: Change the Default SSH Port
Most automated scripts scan for and try to exploit port 22. Moving SSH to a non-standard high port (between 1024 and 65535) won’t stop a targeted attack, but it drops botnet noise by 99%, keeping your auth logs clean and saving CPU cycles.
Open the SSH config file again:
sudo nano /etc/ssh/sshd_config
Find the line that says #Port 22. Uncomment it and change it to your desired port. For this example, we will use 52222:
Port 52222
Save and exit.
Warning: DO NOT restart SSH until we configure the firewall in Step 4, or you will permanently lock yourself out.
Step 4: Configure UFW to Allow Only What You Need
Ubuntu and Debian servers use UFW (Uncomplicated Firewall) to manage network connections. To protect your server, we recommend setting a default-deny policy for incoming traffic, allowing outgoing traffic, and explicitly opening only the ports we need.
Run the following commands on your VPS:
# Deny all incoming traffic by default
sudo ufw default deny incoming
# Allow all outgoing traffic by default
sudo ufw default allow outgoing
# Allow your NEW custom SSH port (crucial!)
sudo ufw allow 52222/tcp
# Allow HTTP and HTTPS if you are hosting web apps
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Review your staged rules:
sudo ufw show added
If everything looks correct, you can enable the firewall by running the following command:
sudo ufw enable
Once the firewall is enabled, any new traffic entering or leaving your server will be inspected and filtered according to the rules we configured above. If any application has already established a connection, it won’t be terminated, but if the application attempts to establish a new connection, it will be blocked by the firewall.
Now that the firewall allows traffic on your custom port, we can safely apply the SSH changes by running the following command:
sudo systemctl restart ssh
Testing phase: DO NOT CLOSE your current terminal session. Open a new terminal on your local machine and test your new setup:
ssh -p 52222 sysadmin@YOUR_VPS_IP
If you successfully connect using your SSH key, you can close the original root session.
Note: If configuring firewalls over CLI makes you nervous, RunCloud’s Firewall Manager lets you set, preview, and deploy port rules and IP whitelists directly from the dashboard without touching the terminal.
Step 5: Install Fail2Ban to Block Brute-Force Attacks
Now that we have changed the SSH port and disabled password authentication, the server is relatively secure, but automated bots will still try to break in by sending random login attempts with incorrect credentials.
Fail2Ban monitors your log files and dynamically updates your firewall to block IP addresses that show malicious behavior.
To configure this on your Linux server, you can install the Fail2Ban package using the following command:
sudo apt update && sudo apt install fail2ban -y
After installing it, you need to create a set of rules (called “jails”) for your server. We strongly recommend that you don’t edit the default jail.conf file, as package updates will overwrite it. Instead, you should copy it to create a new file called jail.local. You can do this on a Linux server using the following command:
After creating the file, you can edit your local configuration:
sudo nano /etc/fail2ban/jail.local
Scroll down to the [sshd] block. You need to tell Fail2Ban that you are using a custom port, and explicitly enable the jail. Modify the block to look like this:
After creating the service, you can verify that your SSH jail is active using the following command:
sudo fail2ban-client status sshd
In the screenshot above, we can see the list of IP addresses that Fail2Ban has banned from accessing our server.
By completing these 5 steps, you have eliminated the low-hanging fruit that compromises 95% of fresh Linux setups.
Note: Getting Fail2Ban thresholds wrong in jail.local often results in banning yourself or failing to trigger on real attacks. That’s why RunCloud ships with Fail2Ban pre-configured for web and SSH traffic.
A hardened server is only secure until the next CVE is published. If you are managing more than one server, you should not want to manually run apt upgrade whenever a vulnerability is discovered in OpenSSL or your kernel. Enable unattended-upgrades to automatically install critical security patches in the background.
To do this, first you need to install the necessary packages using the following command:
After installing the services, you can enable the service via the interactive prompt:
sudo dpkg-reconfigure -plow unattended-upgrades
Select Yes when prompted to automatically download and install stable updates.
After configuring it, check the configuration file to verify that it has been activated successfully using the following command:
cat /etc/apt/apt.conf.d/20auto-upgrades
When you run the above command, you should see APT::Periodic::Unattended-Upgrade "1"; in the output.
Step 7: Remove Unused Packages and Disable Unnecessary Services
Every service running on your server is a potential entry point for hackers. If you aren’t using a service or application, you can turn it off to protect your server and conserve resources.
To do this, first, we will audit what is actively listening on your server’s network interfaces by using the following command:
sudo ss -tulpn
If you see any services that you don’t want, then you can stop and disable them so they don’t start on reboot:
In the above commands, replace the <name> with the actual name of the service that you want to disable.
Next, purge any orphaned packages and dependencies that came pre-installed on your provider’s OS image but which aren’t needed anymore:
sudo apt autoremove --purge -y
Step 8: Harden Kernel Parameters with sysctl
By default, the Linux kernel uses networking parameters optimized for broad compatibility rather than strict security. When you deploy your server on the internet, it will be constantly bombarded with hundreds of attacks that try to exploit these compatibility features.
But you can mitigate several types of network attacks (like SYN floods and IP spoofing) by tweaking sysctl.conf. To do this, you can open the configuration file using the following command:
sudo nano /etc/sysctl.conf
In this file, we will disable certain features by appending the following lines to the bottom of the file:
After editing the file, you can save and exit the file editor (CTRL+O, Enter, CTRL+X). After that, you can apply the changes immediately without rebooting by running the following command:
Step 9: Set Strict File Permissions and Audit User Accounts
If an attacker compromises a system, they will try to either create hidden backdoor users, or leave files with wide-open permissions. There are several steps you can take to ensure this isn’t the case on your server. First, you can audit your user accounts to ensure only root has a User ID (UID) of 0. Run this command to print any user with root-level privileges:
awk -F: '($3 == "0") {print}' /etc/passwd
This should output exactly one line: root:x:0:0:root:/root:/bin/bash. If you see any other user here, then it is possible that your server is compromised.
Next, verify that no users have empty passwords:
sudo awk -F: '($2 == "") {print}' /etc/shadow
This should return no output.
Finally, find and review any world-writable directories (directories anyone can write to) that don’t have the “sticky bit” set (which prevents users from deleting each other’s files):
sudo find / -type d -perm -0002 -a ! -perm -1000 -print 2>/dev/null
If your server is serving multiple websites, then the above command will probably return a long list of directories. You need to review this list and, if you find any rogue directories, investigate them immediately and restrict their permissions using chmod 755.
Step 10: Review Mandatory Access Control (AppArmor and SELinux)
AppArmor (on Ubuntu/Debian) and SELinux (on RHEL/AlmaLinux) are Mandatory Access Control (MAC) systems. They act as a high-level security guard built directly into the Linux kernel. While standard file permissions (chmod) control who can see a file, MAC systems control which specific programs are allowed to do what.
In a standard setup, if a hacker exploits a vulnerability in a web server such as NGINX and gains “root” access, they can theoretically access every file on your server.
With AppArmor or SELinux active, the program is confined to a “sandbox.” Even if NGINX is compromised, the MAC system detects that NGINX is attempting to access sensitive system files (such as/etc/shadow) or execute unauthorized commands. Because that behavior isn’t in the program’s predefined “security profile,” the kernel blocks the action instantly, even if the attacker has root privileges. It effectively limits the “blast radius” of any potential hack.
You can run the following commands to check the configuration of these systems on your server:
On Ubuntu/Debian (AppArmor):
sudo aa-status
On RHEL/Alma/Rocky:
sestatus
Manually configuring MAC systems is tricky, and beyond the scope of this article. It requires writing deep-level security profiles that define every single file, port, and network socket a program is allowed to touch. One small mistake in a profile can cause your database to crash or prevent your website from loading, leading to hours of frustrating troubleshooting.
The good news is that if you are using RunCloud, you don’t need to lift a finger.
RunCloud servers are engineered to be secure out of the box. The platform automatically configures and optimizes these security layers during server provisioning. Your server is hardened the moment it connects to the RunCloud panel, allowing you to focus on your applications while RunCloud handles the complex kernel security in the background.
Step 11: Configure Off-Server Backups
Hardening your server reduces the risk of a hack, but it cannot protect you against hardware failure, a data center fire, or an accidental rm -rf / command. Off-server backups ensure that even if your entire VPS is deleted, your business can be restored in minutes.
There are several ways to handle backups, each with its own pros and cons:
Disk-Level Snapshots: Taking a full image of your server via your provider (like DigitalOcean or AWS). These are easy but often expensive, and they’re hard to move between providers.
Application Plugins: Using WordPress plugins like UpdraftPlus. These are user-friendly, but they can slow down your site because they use your server’s PHP resources to compress files.
Manual Scripting: Using Linux tools to manually move data. If you choose to do this manually, you must manage three distinct parts: the database, the files, and the transport.
Security: Manual rclone or script configs often store your Cloud API keys or Database passwords in plaintext on the server. If a hacker gets in, they now have your backup keys too.
Resource-Heavy: Compressing large folders (tar) and dumping databases every night causes high CPU and Disk I/O spikes, which can make your website sluggish during the backup window.
Reliability: If the script fails, you won’t know until you try to restore and find out that the files are empty.
If you are using RunCloud, you don’t need to deal with any of this.
RunCloud uses Incremental Backups, which is a far superior technology. Instead of zipping your entire site every night (which is slow and uses a lot of disk space), RunCloud only identifies the specific data that changed – and syncs just that.
Fast & Efficient: Because it only moves “changes,” backups finish in seconds rather than minutes.
Zero Resource Lag: It doesn’t put a heavy load on your server, keeping your website fast even during a backup.
Encrypted & Secure: Your S3 or Backblaze credentials are stored in RunCloud’s encrypted vault.
Backup Notifications: You can configure the Backup script to notify you via Slack/Email/Discord if the backup fails for any reason.
One-Click Restore: If something goes wrong, you don’t have to remember complex Linux commands. You just click “Restore” in the dashboard, and RunCloud puts everything back exactly where it belongs.
After Action Report
If you have followed all the steps in this article, your server is now locked down and can withstand a variety of internet attacks. But a hardened server isn’t very useful if it doesn’t host anything. The next step is installing your web stack (NGINX/Apache, PHP, MySQL) and provisioning SSL certificates.
Doing this manually means diving right back into the terminal. After hardening, managing NGINX, PHP-FPM, and SSL still requires SSH for every single configuration change, virtual host creation, and certificate renewal.
RunCloud manages your NGINX configuration, PHP-FPM tuning, and Let’s Encrypt SSL deployments entirely from a UI, while fully respecting the hardened SSH and firewall configurations you just put in place.
While RunCloud simplifies complex server management tasks, it is designed for developers, agencies, and power users who need more than just a basic cPanel replacement. Once your servers are hardened, RunCloud enables you to scale your operations by offering tools for advanced management:
Multi-Server Management: Easily oversee, update, and manage dozens or hundreds of hardened Linux servers from a single dashboard.
Team & Role-Based Permissions: Delegate server access to team members or clients without sharing SSH keys or root passwords, thanks to granular control over who can manage applications, databases, or backups.
API-Driven Control: Integrate server and application management into your custom workflows using the RunCloud API, allowing for automated server provisioning and deployment.
Linux server hardening is the process of reducing a system’s attack surface by patching vulnerabilities, disabling unused services, and implementing strict access controls. Common hardening steps include disabling root SSH access, configuring firewalls like UFW, and enforcing cryptographic key-based authentication.
How long does it take to harden a Linux server?
Manually executing a basic Linux hardening checklist on a fresh VPS typically takes an experienced sysadmin about 30 minutes. However, advanced hardening procedures like configuring SELinux, setting up intrusion detection systems, and passing compliance audits can take several hours to properly tune.
Should I run hardening on an existing server or only on fresh ones?
You should ideally harden a fresh Linux server before it is ever exposed to public internet traffic or connected to your production application stack. Applying strict firewall rules, altering permissions, and modifying SSH configurations on an existing server carries a high risk of breaking active application dependencies or accidentally locking yourself out. If you must harden an existing production server, thoroughly test the new security policies in a staging environment and ensure you have recent, verified off-site backups first.
Does changing the SSH port actually improve security?
Changing the default SSH port from 22 to a non-standard high port is a security-through-obscurity tactic that will not stop a determined, targeted attacker running a full port scan. However, it is still highly recommended because it drops automated botnet brute-force attempts by over 99 percent. This drastically cleans up your system authentication logs, reduces wasted CPU cycles, and prevents tools like Fail2Ban from being overwhelmed by background internet noise.
If you want to build a completely custom frontend UI without giving up the powerful, built-in WordPress ecosystem, a headless setup is exactly what you need.
A headless WordPress architecture lets you use the WordPress CMS for content management while using the framework of your choice for the frontend. In this tutorial, we will use Astro, a modern framework built for speed that lets you fetch data from WordPress and render it as static HTML.
This combination provides the ultimate developer experience: you keep the familiar WordPress dashboard and plugin ecosystem while building a completely custom, high-performance frontend free from the limitations of legacy themes.
Benefits of Headless WordPress
Decoupling content creation and frontend development is a major benefit. Content teams use the familiar WordPress dashboard for posts and SEO without touching the Astro codebase, speeding up the content pipeline. Simultaneously, frontend developers focus purely on UX, features, and design optimization without interrupting content work.
Here are the primary advantages you can expect from this headless architecture:
Performance: Because Astro builds statically by default, it fetches your data from the WordPress REST API at build time and generates static HTML files, making your site incredibly fast.
Security: Your WordPress backend is not directly exposed through the frontend, reducing your attack surface while still allowing you to apply standard security controls where needed.
Flexibility: You have full developer control over the frontend code while still using WordPress as a robust CMS.
SEO: Static pages are easily crawled and indexed by search engines.
By the end of this tutorial, you will know exactly how to connect these two powerful tools. We will focus on producing static pages that are generated entirely at build time.
Once you are comfortable with this workflow, you can later customize how Astro behaves. For example, you can eventually change your category pages to dynamically fetch all pages via the API on the client side, rather than generating them during the build process.
Prerequisites
Before starting, you need a live WordPress site with the REST API accessible (at /wp-json/wp/v2/).
In this guide, we will not teach you how to install WordPress, as we have already covered this topic extensively in our previous blog posts. If you need help setting up your initial WordPress site, please refer to one of these guides:
Once your WordPress site is live on the internet, the built-in WordPress REST API will already be active. We just need to make sure it is properly formatted and accessible to Astro.
Set your Permalinks: The WordPress REST API relies on clean URLs to work properly.
Log in to your WordPress admin dashboard.
Navigate to Settings > Permalinks.
Select “Post name” (or any other clean URL structure).
Click Save Changes.
Verify the REST API is working
Open a new browser tab.
Visit your WordPress site’s API endpoint at https://[YOUR-WP-DOMAIN]/wp-json/wp/v2/ (replace the bracketed text with your actual domain name).
Check the screen for a JSON response containing the site data containing your posts. If you see this data, your headless backend is ready.
Set up Custom Post Types (Optional)
If you use Custom Post Types such as “Portfolios” or “Testimonials”, they are hidden from the REST API by default (unless a plugin actively enables show_in_rest). To use a CPT in your headless setup alongside standard posts and pages, you must configure them in your WordPress dashboard to allow REST API support.
Note: The upcoming examples will fetch data from a WordPress site whose content types have already been configured and exposed to the REST API.
Configure Authentication and Fetching Strategy (optional)
By default, the REST API is open to the public for reading content. If you are building a private application, you can configure your WordPress site to require authentication by following the official REST API Handbook.
Phase 2: Create WordPress Frontend with Astro
With your WordPress backend configured and its REST API ready to serve content, the next step is to build a fast frontend to display your posts. We’ll use Astro to fetch content from the API at build time, generating static HTML pages for maximum performance and security.
Step 1: Create a New Astro Project
With your WordPress site ready, create a new Astro project using the official starter template:
npm create astro@latest my-astro-wp
Select the following options when prompted:
Use A basic, helpful starter project: Yes
Install dependencies: Yes
Initialize git: Yes
Navigate to your project folder:
cd my-astro-wp
Step 2: Configure Environment Variables
Create a .env file in the project root to store your WordPress URL:
A note on pagination: The WordPress REST API limits the number of posts that can be returned in a single request. While per_page=20 works for small sites, larger sites will need pagination to fetch all posts.
The maximum value for per_page is typically 100. If you exceed this, the API will silently limit the results.
For production use, you should either:
Fetch multiple pages using the page parameter
Implement a loop to retrieve all posts during the build process
Step 4: Create Dynamic Post Pages
Create src/pages/posts/[slug].astro to handle individual post pages:
Visit http://localhost:4321 to see your headless WordPress blog in action. You should see all your WordPress posts displayed on the homepage, and clicking on any post will take you to its full article page.
Step 6: Build for Production
When ready to deploy, build your static site:
npm run build
The output will be in the dist/ folder, ready to deploy to any hosting provider, such as Netlify, GitHub Pages, or RunCloud.
Step 7: Keep Your Content in Sync with Rebuilds
The Astro project in the above example generates static pages at build time by default; any new or updated content published in WordPress will not appear on your live site immediately. To display the latest content, you must trigger a new build so Astro can fetch the fresh data from your REST API.
Depending on your publishing schedule and team size, you have a few ways to manage these rebuilds.
Option A: Manual Rebuilds (Simple)
If you only publish content occasionally, the simplest approach is to manually trigger a deployment from your RunCloud dashboard whenever you publish a new post.
Log in to your RunCloud dashboard.
Navigate to Atomic Deployment > your Astro project.
Click Force Deploy to force a manual rebuild.
RunCloud will run your deployment script, fetch the newest WordPress data, and update your live site using atomic deployment.
Option B: Automated API Triggers (Advanced)
By default, RunCloud automatically builds your site whenever new code changes are pushed to GitHub. However, publishing a post in WordPress does not push code to GitHub. To automate deployments based on content updates, you can use the RunCloud API to trigger a build programmatically.
You might be tempted to add a custom PHP function to your WordPress site that pings the RunCloud API every time a post is saved. However, if you have a team of writers constantly saving drafts and making simultaneous revisions, this can result in dozens of unnecessary deployments running back-to-back, which can consume server resources and cause conflicts.
Scheduled Deployments (Cron Jobs)
To avoid overwhelming your deployment pipeline, the best practice is to set up a cron job. Instead of deploying on every single save, you can configure a server cron job to ping the RunCloud deployment API on a predictable schedule.
Decide on a publishing schedule (for example, once every 12 hours or once a day at midnight).
Create a server-level cron job that sends a POST request to your RunCloud Webhook URL at that specific interval.
Instruct your content team that new posts will go live at those designated times.
Note: The need to constantly rebuild your application depends entirely on your Astro project architecture. The steps above apply to Static Site Generation (SSG), Astro’s default behavior that offers the best performance. However, if you configure Astro to use Server-Side Rendering (SSR), your application will dynamically fetch data from the WordPress API at runtime. In an SSR setup, any content changes saved in WordPress will appear on your frontend instantly, completely eliminating the need to rebuild your site after each post.
Phase 3: Deploy Astro Project to RunCloud
Now that your local Astro project is successfully fetching data from your headless WordPress setup, it is time to share it with the world.
In this phase, we will push your code to GitHub and set up a deployment pipeline on RunCloud.
We are going to configure an “atomic deployment.” The major benefit of this setup is that after you commit and push your code, it becomes available to users worldwide in often less than a minute. Furthermore, if a build fails for any reason, your old code will continue running smoothly with zero downtime.
Here is how to set up your professional deployment workflow.
Step 1: Push your Astro project to GitHub
First, we need to host your code in a repository so RunCloud can access it.
Open your web browser and log in to your GitHub account (or any supported Git provider).
Navigate to your dashboard, then click the New button to create a repository.
Give your repository a name.
Leave the option to add a README file unchecked. It is very important that the repository is completely empty.
Click Create repository.
GitHub will now show you a page with instructions for pushing an existing repository from the command line. Open your computer’s terminal, make sure you are in your Astro project folder, and copy and paste those specific commands to commit your code and push it to GitHub.
Step 2: Create a new RunCloud Web Application
Now, let’s tell RunCloud where to find your code.
Log in to your RunCloud dashboard.
Navigate to your server, then click Deploy New Web App.
Choose the option to install from a Git repository and select your Git provider.
Enter a suitable name for your application.
Locate the “Web Application Owner” section and uncheck the “Use existing system user” checkbox.
Enter a new name, such as astrowp.
Configure the domain name for your website. (You can use a test domain name for now and update it later manually or by using the RunCloud DNS manager.)
Enter the details for your new project into the “Repository name” and “Branch name” fields.
Copy the deployment key generated by RunCloud.
Open your GitHub repository and navigate to Settings > Deploy keys.
Click Add deploy key, paste the key provided by RunCloud, and save your changes.
Return to RunCloud and leave all other settings at their defaults.
Click Add Web Application.
Note: Steps for adding deployment keys can vary by provider. For exact steps, screenshots, and a detailed guide, check out your supported provider in the RunCloud documentation.
Step 3: Convert to Atomic Deployment and set Webhooks
Atomic deployments keep your site up while Astro builds your new pages.
Inside your RunCloud dashboard, click on Atomic Deployment in the left menu.
Follow the on-screen instructions to copy the provided webhook URL.
Go back to your GitHub repository, navigate to Settings > Webhooks, and click Add webhook.
Paste the RunCloud URL into the “Payload URL” field and save. This ensures that GitHub tells RunCloud to update your site whenever you push new code.
Step 4: Add your Environment Variables
Because your code is now on a live server, it needs your “.env” file to know where your WordPress API lives. RunCloud’s atomic deployment uses a shared folder so your environment variables persist across deployments.
In your RunCloud Web Application dashboard, navigate to Atomic Deployment > Your Project > Symlink.
Click Add New Symlink.
Set the “Symlink Type” to “Config”.
Enter “.env” in both the “Link From” and “Link To” fields.
Add your PUBLIC_WP_URL variable exactly as you did on your local machine.
Set a password for encryption. Remember this password if you want to edit this file again.
Click Save.
Step 5: Install NVM via SSH
RunCloud servers ship with a default version of Node.js, but Astro often requires a specific, modern LTS (Long-Term Support) version. We will install Node Version Manager to handle this safely.
Open your terminal and log in to your server via SSH using your new system user account (for example, “astrowp”). For step-by-step instructions and a detailed guide on connecting to your server via SSH, refer to the RunCloud documentation on How to Connect to Your Server via SSH.
Run the following command to download and install NVM:
Close your terminal completely and open a new SSH session so the system recognizes the new software.
Run nvm install –lts to install the latest long-term support version of Node.js.
Note: This is the only time you need to log in via SSH; all other processes will be handled automatically by the Git deployment pipeline.
Step 6: Create the Deployment Script
Now we will write the instructions that RunCloud follows every time it receives new code from GitHub.
In your RunCloud dashboard, navigate to Atomic Deployment > Your Project > Deployment Script.
Scroll down to the Activate Latest Release section and click “Add Script”.
Give this script a suitable name, and under the “When to Run This Script”, select “Before Activate latest release” from the dropdown menu.
Delete the default text and paste the following script:
# 1. Navigate to the current release directory
cd {RELEASEPATH}
# 2. Load NVM into the script environment
export NVM_DIR="/home/$USER/.nvm"[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# 3. Tell the system to use the LTS version of Node.js
nvm use --lts
# 4. Install your Astro project dependencies
npm install
# 5. Build the static files using an absolute path to avoid version conflicts
npm run build
Note:By using the NVM in step 3, you ensure the system will not accidentally revert to RunCloud’s built-in Node version, preventing unexpected version conflicts.
Make sure to check the box next to “Run on Web Application” and then click Save to apply your new script.
After that, open the Settings tab for this atomic deployment project to configure the deployment configuration options.
Auto deploy on git push: Triggers a deployment every time you push code to the configured branch.
Install Composer dependencies: Ensure this is UNCHECKED. For this Astro project, we use npm install in the custom script, not Composer.
Install Dev Dependencies: Installs development-related PHP dependencies. (Not applicable to this Node.js/Astro project).
You can optionally configure notification channels such as Slack, Discord, Telegram, or Webhooks for both successful and failed deployments in the Notifications section of your RunCloud Web Application.
Step 7: Run your First Deployment
You are fully configured and ready to go.
Still inside the Atomic Deployment menu on RunCloud, locate the option to manually run a deployment on the top right.
Click Force Deploy.
Watch the deployment log. You will see RunCloud fetch your code, install dependencies, and build your Astro HTML files using your WordPress data.
Once the build passes, your headless website is officially live. Now, if you visit the URL configured in Step 2 for your frontend web application on RunCloud, you will be able to view your newly deployed, fast, headless WordPress site powered by Astro.
Phase 4: Advanced Steps (optional)
Now that your headless WordPress and Astro website is live, you can explore a few optional advanced steps to optimize your workflow, improve performance, and expand your site features.
Create a Staging Environment
To take complete advantage of the RunCloud environment, it is highly recommended to build a staging environment.
A staging environment is a private replica of your website where you can test WordPress plugins, Astro code updates, or new designs without breaking your live production site.
Because your backend (WordPress) and frontend (Astro) are separated, you will manage their staging environments separately. You can deploy two different branches of your Astro Git repository for this purpose.
Update the PUBLIC_WP_URL variable to match your new staging WordPress domain name.
Run your local development server to safely test your new WordPress plugins against your Astro frontend.
Create a cloud staging environment for your team:
Optionally, you can create a second project on the cloud so your entire team can test changes under load or for longer durations.
Open your GitHub repository and create a new branch named “staging”.
Log in to your RunCloud dashboard and navigate to Web Application.
Click Create Web App.
Follow the standard deployment steps, but enter “staging” into the “Branch name” field.
Assign a test domain name to this new web application and click Add Web Application.
Install RunCache
To make your headless website build even faster, you should pair it with an object caching plugin. Object caching saves the results of complex database queries and returns data instantly. This significantly speeds up your WordPress REST API responses.
RunCache is a free tool built for this exact purpose. While it is highly optimized for RunCloud servers, it can be used on any WordPress backend site.
Make More Pages and Endpoints
Your website is currently fetching blog posts, but you are only limited by your imagination. You can create custom views, pages, and features using the pre-built WordPress REST APIs. Astro can generate pages for any data that WordPress outputs.
Here are a few examples of what you can build next:
Author Pages: Fetch data from the /wp-json/wp/v2/users endpoint to create a directory of your blog authors and their biographies.
Category Pages: Fetch data from the /wp-json/wp/v2/categories endpoint to generate dynamic landing pages that group your posts by specific topics.
Custom Post Types: If you use a plugin to create a “Portfolio” or “Testimonials” post type, you can fetch them just like regular posts and design unique Astro layouts for them.
If you know a little PHP, you can even write your own WordPress plugins to create completely custom REST API endpoints tailored to your exact business needs.
To discover everything you can fetch and build, review the official WordPress API documentation:
Building a headless architecture with WordPress and Astro offers the best of both worlds: you get the unmatched content management experience of WordPress alongside Astro’s high-performance, developer-first environment.
While you are now free from the constraints of pre-built themes, a custom stack demands a fast server environment to handle deployments, security, and consistent uptime.
RunCloud bridges this gap by turning complex server administration into a streamlined, automated workflow. Once your site is deployed, RunCloud handles the “heavy lifting” (including server-level security, SSH access, system backups, and automated continuous deployments) so you can focus entirely on your work rather than managing your OS.
If you are looking for a professional-grade way to host and manage your headless infrastructure, RunCloud provides the stability and ease of use your project deserves.