Reverse Proxying WordPress from a Home Server

Caveats

Home internet is the bottleneck. Your uplink speed and latency to the VPS determine how fast dynamic requests complete. On fiber with 100 Mbps upload and sub-20ms latency to the VPS, PHP responses arrive in under 50ms including WireGuard overhead — faster than most shared hosting. On cable with 10 Mbps upload, every uncached dynamic request pays 80–100ms just to transfer the response body. The static mirror absorbs the bulk of the page weight — CSS, JS, images, fonts all come from the VPS disk — but time-to-first-byte for PHP is gated by your home uplink.

Rule of thumb: if your home upload is 20 Mbps or higher and latency to the VPS is under 40ms, this architecture is viable for production. Below that, it's fine for development and staging but not for public traffic. Test your actual latency with a ping from the VPS to the home server's Tailscale IP — WireGuard adds about 1–2ms overhead on modern hardware.

The rsync lag. Media uploaded through the WordPress admin isn't served from the VPS disk until the next cron run. The first visitor after an upload gets the slower proxied path. For a site where images are uploaded once a week, this is invisible. For a news site with hourly photo galleries, reduce the cron interval or trigger the sync from a WordPress hook on wp_handle_upload — but that adds complexity. Start with the cron approach and tighten it only if you actually feel the lag.

Bot noise on the VPS. A small VPS acting as a proxy still receives every bot, scanner, and credential-stuffer that probes its public IP. Each blocked request — the 403 for /.env, the 444 for a bogus hostname — consumes a small amount of nginx worker time. On a 1 GB Nanode where every megabyte of RAM and every CPU cycle counts, silencing that noise at the firewall level keeps resources free for actual proxying. The fail2ban + nftables guide covers the full setup — SSH and Nginx jails, crowd-sourced blacklists, and a daily cron job that drops known bad actors before they reach nginx. On a lean proxy, that's the difference between a machine that spends its day responding to bots and one that spends it serving your traffic.

Dual server maintenance. You now maintain two nginx configurations and two sets of snippets. The modular approach — drop.conf, static_caching.conf, reusable includes — keeps the divergence manageable, but it's still two machines to patch, monitor, and troubleshoot. If the VPS is a dedicated proxy with no PHP or MariaDB installed, the split is cleaner: the VPS runs nginx and rsync, the home server runs the full stack. If you host production sites on the VPS alongside the proxy — as I do — you're maintaining two PHP installs, two MariaDB instances, and two sets of monitoring rules. Either way, when you change a security rule on one machine, check whether it applies to the other.

Home ISP, power, and hardware are single points of failure. Your VPS has redundant power, multiple network uplinks, and a provider SLA. Your basement has one circuit breaker, one ISP, and one power supply. If uptime matters — a business site, a client project — host everything on the VPS or a second cloud instance. If a few hours of downtime during a power outage is acceptable — a personal blog, a side project — the architecture works. Cloudflare's Always On feature won't save you here: it only kicks in when the origin is completely unreachable, and a VPS that's humming along but unable to reach the backend still looks healthy from the outside. If you're crafty enough to write a monitoring script on the VPS that detects the backend is down and swaps in a static maintenance page at the proxy level, you've earned the uptime you get. The rest of us just accept that the basement is not a data center.


When this makes sense

You have a powerful home server and a cheap VPS
Maximize hardware ROI. The home machine does the heavy lifting. The VPS does what it's good at — SSL, caching, DDoS absorption.
You want to keep your database at home
Privacy or data sovereignty concerns. The database never leaves your network. The VPS never sees a query.
Your home internet is fast and stable
Fiber with low jitter. The WAN hop is invisible to visitors. Static mirroring handles the heavy assets.
You want full control without managed hosting pricing
Dedicated hardware, your kernel, your config, zero per-site markup. The VPS is $5/month. The home server is hardware you already own.

If your home internet is slow, metered, or unreliable, or if you need five-nines uptime, this architecture isn't the right fit — host everything on the VPS or add a second cloud instance. For everyone else: the home hardware does the work, the VPS does the networking, and Cloudflare does the edge. Every layer does its job and stays out of the way.

Technical Audit Summary

This guide documents a reverse proxy architecture that serves a WordPress site from a home server through a lightweight VPS proxy, with static assets mirrored to the VPS disk and dynamic requests proxied over Tailscale's WireGuard mesh.

Last Audit: May 2026
Environment: Debian Trixie (13)
Nginx: 1.31.2
PHP-FPM: 8.5.6

Compatibility: The proxy architecture works on any Nginx 1.18+ build with the standard ngx_http_proxy_module. Tailscale is available for Linux, macOS, Windows, and FreeBSD. The rsync mirror pattern is filesystem-agnostic. The home server's stack — nginx, PHP-FPM, MariaDB — follows the same configuration patterns as the standalone WordPress on Nginx guide.

2026-05-29: Initial publication — reverse proxy architecture for serving WordPress from a home server through a VPS proxy. Covers Tailscale network setup, static asset mirroring with rsync, proxy nginx configuration with HSTS-aware location blocks, backend WordPress HTTPS awareness, Cloudflare transparent edge integration, and a decision matrix for when the architecture makes sense. Cross-linked to Cloudflare Edge Configuration, WordPress on Nginx, WP-CLI, Securing Nginx and PHP, and fail2ban guides.