A year ago last week, I finalized my migration of this site from the cloud. The site now runs on a self-hosted cluster of NUCs on my desk. I couldn’t be happier!
This is all part of my ongoing project to build a disruptive new approach to launching and maintaining infrastructure. I eat my own dog food, so I’ve already been personally leveraging this approach for a year.1I say personally because I’ve professionally leveraged a near identical approach for my employers for nearly a decade! The thing is, many in the industry are skeptical about hosting a website from home. They doubt whether it can handle any level of traffic.
Let me dispel that myth.
Detailing the Stack
My current blog stack is held together by duct tape and chewing gum. But it works:
- The blog itself runs on a stock WordPress container image, which itself bundles Apache and PHP running in CGI mode.
- Data storage is MySQL for WordPress itself and Memcached for objects, HTML fragments, and options.
- To enhance performance, I’m running Batcache for full page caching.
- Finally the entire stack sits behind Varnish to ensure WordPress is only invoked when absolutely necessary.
For better or for worse, WordPress is being treated as an over engineered GUI for a static site generator. Visitors don’t interact with PHP in any way; the overwhelming majority of requests are served from Varnish.
Since I don’t want to expose my home IP address to the world, this machine isn’t visible to the public. I route traffic in over a secure tunnel powered by Cloudflare.
The remote cache is where things get really powerful.
Request Servicing at Edge
In an ideal world, the overwhelming majority of my traffic would be serviced at the edge by Cloudflare. Up til recently, though, the service was only handling DNS and a handful of static assets. Roughly 0.5%-2% of my traffic would be served from the cache and even static page requests would flow through the tunnel to my server.
Varnish caught most of those. The few that it failed to serve were automatically cached by Batcache to prevent resource contention on the server.
Through some clever debugging, I finally figured out what the issue was – I needed some additional caching rules!
The first rule I added was for the sake of security. Anyone other than me should never be able to get to the WordPress admin interface. Any requests to either /wp-admin
or even /wp-login.php
from an IP other than my home network should be refused.

Once that was in place, I chose to block all of the bots trying to scrape my site with XML-RPC. Any request to that interface would be redirected to the homepage.2There are ways within WordPress to disable XML-RPC directly. But I wanted to kill these requests at the edge in Cloudflare rather than allowing unnecessary traffic to the server.

Finally, I wanted to ensure any request for static content was cached as aggressively as possible. Anything without a query string or outside of a /wp-
directory should be cached for at least 2 hours.3I have an additional page rule where anything in /wp-content/themes/*/assets
is cached aggressively as well. This rule is specific to the theme I’m currently using, though, so you’ll want to fine tune things for your own installation. I want to ensure my requests still make it through when I’m logged in, so Cloudflare should pivot based on my auth cookie as well.

Practical Results
Once these changes were in place, the results were immediate.
Whereas previously I had been caching < 2% of my traffic, the new rules meant I was now caching > 30% of requests. This is monumental, and saves a huge amount of bandwidth on my local network.
There is much more I can do. However, I plan to wait for the final rollout of my new cluster before I tread down that path. Cloudflare will still be involved, but so will be a Caddy-based proxy server to my local cluster. This will provide a second level of defense against needless (or malicious) traffic making it into my network.
Want to keep up as I take that journey? Join my mailing list today!
- 1I say personally because I’ve professionally leveraged a near identical approach for my employers for nearly a decade!
- 2There are ways within WordPress to disable XML-RPC directly. But I wanted to kill these requests at the edge in Cloudflare rather than allowing unnecessary traffic to the server.
- 3I have an additional page rule where anything in
/wp-content/themes/*/assets
is cached aggressively as well. This rule is specific to the theme I’m currently using, though, so you’ll want to fine tune things for your own installation.