Reverse Proxy and WordPress – Nginx, Apache, SSL Termination, and Cache

Published: April 14, 2026 · Author: Marcin Szewczyk-Wilgan

A reverse proxy sits in front of WordPress and handles client connections on its behalf. This architecture unlocks capabilities that a direct web server setup cannot provide: serving multiple applications on a single IP, SSL termination with certificate centralization, full-page caching independent of WordPress, load balancing across multiple PHP backends, and blue-green deployments without downtime. At the same time, it introduces a set of WordPress-specific pitfalls – broken HTTPS detection, wrong visitor IPs, cached cart pages, redirect loops – that this guide addresses in detail.

Forward Proxy vs Reverse Proxy vs CDN

These three concepts are frequently confused. Understanding the difference clarifies when a reverse proxy makes sense for WordPress.

Forward proxySits between clients and the internet. Clients configure it explicitly and traffic flows through it outbound. Used for corporate internet filtering, anonymization, and caching outbound requests. Has nothing to do with serving a WordPress site.
Reverse proxySits in front of one or more backend servers. Clients connect to the proxy; the proxy forwards requests to the appropriate backend and returns the response. Clients do not know (or need to know) about the backend servers. This is the architecture relevant to WordPress hosting.
CDNA globally distributed reverse proxy network. CDN edge nodes cache responses close to users and forward cache misses to the origin server. Cloudflare, BunnyCDN, and Fastly are all reverse proxies at global scale. For WordPress, a CDN can serve as the only reverse proxy needed for most sites.

Use Cases for a Reverse Proxy with WordPress

A reverse proxy makes sense in these scenarios:

Multiple apps

Multiple services, one IP

A single server running WordPress on / and a Node.js API on /api/, or two separate WordPress installations on different subdomains, all sharing one public IP. The proxy routes requests to the appropriate backend based on Host header or URL path.

SSL termination

Centralizing certificate management

The proxy handles all SSL/TLS, including certificate renewal, cipher selection, and HTTP/2. Backend servers receive plain HTTP, eliminating the need to configure SSL on each application server. Simplifies certificate management on multi-app servers.

Caching

Full-page cache at the proxy layer

Nginx proxy_cache or Varnish in front of WordPress can serve cached responses far more efficiently than WordPress's own page cache plugins. The proxy serves cached pages at near-static speed while WordPress handles only cache misses and authenticated requests.

Load balancing

Multiple PHP backends

For high-traffic sites, distribute PHP requests across multiple backend servers. The proxy load balances across the pool, detects backend failures with health checks, and drains connections gracefully during deployments – enabling zero-downtime updates.

Critical WordPress Pitfalls Behind a Proxy

Several things break predictably when WordPress runs behind a reverse proxy. Address all of these before the site goes live.

HTTPS detectionThe proxy terminates SSL; WordPress sees an HTTP connection. WordPress generates HTTP URLs, canonical tags, redirects, and asset URLs – which cause mixed content warnings and broken HTTPS enforcement. Fix: have the proxy send X-Forwarded-Proto: https, then add to wp-config.php: if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; }
Real visitor IPThe proxy's IP appears as REMOTE_ADDR in every WordPress request. This breaks security plugins (rate limiting, ban lists), logging, analytics, and WooCommerce fraud checks – all the proxy's IP. Fix: configure the proxy to send the real IP in X-Forwarded-For, then use Nginx's set_real_ip_from and real_ip_header X-Forwarded-For (or Apache's mod_remoteip) so WordPress sees the real client IP in REMOTE_ADDR.
WooCommerce cache bypassServing cached pages to users with items in their cart causes incorrect totals and broken checkout. The proxy cache must bypass for any request with the woocommerce_items_in_cart cookie, the wordpress_logged_in_* cookie, on POST requests, and for /cart/, /checkout/, and /my-account/ URLs unconditionally.
Redirect loopsA common failure: WordPress redirects HTTP to HTTPS (because HTTPS is set), but the proxy also redirects HTTP to HTTPS, creating an infinite loop. Ensure only one layer (usually the proxy) handles HTTP→HTTPS redirects. WordPress's site URL should already use https://, so WordPress itself should not generate further HTTP→HTTPS redirects.
WebSocket supportWordPress 7.0's Real-Time Collaboration and some membership plugins use WebSockets. Proxies must forward WebSocket upgrade headers: proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; in Nginx. Without this, WebSocket connections fail silently.
Trailing slash consistencyMismatched trailing slash handling between proxy and WordPress generates redirect chains: proxy strips trailing slash, WordPress adds it back, proxy strips it again. Set proxy_pass http://backend (no trailing slash) in Nginx to pass the URL unmodified, then let WordPress handle its own permalink normalization.

Nginx Proxy Configuration

A complete Nginx reverse proxy configuration for WordPress with caching, cache bypass, and rate limiting:

Cache zoneproxy_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=WP_CACHE:100m inactive=60m max_size=5g use_temp_path=off;
Define in the http {} block. A 5 GB disk cache handles large WordPress media sites; for content-only sites 1–2 GB is sufficient. The key zone in RAM (100m) stores cache keys for fast lookup.
Cache bypass rulesset $skip_cache 0; if ($request_method = POST) { set $skip_cache 1; } if ($query_string != "") { set $skip_cache 1; } if ($request_uri ~* "/wp-(admin|login|cron)|/cart|/checkout|/my-account") { set $skip_cache 1; } if ($http_cookie ~* "comment_author|wordpress_logged_in|woocommerce") { set $skip_cache 1; }
Proxy directivesproxy_cache WP_CACHE; proxy_cache_bypass $skip_cache; proxy_no_cache $skip_cache; proxy_cache_valid 200 301 302 60m; proxy_cache_use_stale error timeout updating; add_header X-Cache-Status $upstream_cache_status;
The X-Cache-Status header in responses lets you verify cache hits (HIT/MISS/BYPASS) during testing.
Upstream headersproxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
These headers tell the WordPress backend the original Host, client IP, and protocol. All four are required for WordPress to function correctly behind the proxy.
Rate limiting for loginlimit_req_zone $binary_remote_addr zone=wp_login:10m rate=5r/m; in the http block, then in the server block: location = /wp-login.php { limit_req zone=wp_login burst=3 nodelay; proxy_pass http://wordpress_backend; }

Apache Proxy Configuration

Apache with mod_proxy and mod_proxy_balancer provides a mature reverse proxy implementation with load balancing support.

Basic proxy

mod_proxy and mod_proxy_http

Enable: a2enmod proxy proxy_http proxy_balancer lbmethod_byrequests headers. In VirtualHost: ProxyPass / http://127.0.0.1:8080/ ProxyPassReverse / http://127.0.0.1:8080/. ProxyPassReverse rewrites Location headers in redirect responses so they point to the proxy, not the backend.

Load balancing

mod_proxy_balancer

<Proxy "balancer://wordpress"> BalancerMember http://10.0.1.10:8080 BalancerMember http://10.0.1.11:8080 ProxySet lbmethod=byrequests </Proxy> ProxyPass / balancer://wordpress/ ProxyPassReverse / balancer://wordpress/. Add status=+H to a BalancerMember to designate it as a hot standby.

Headers

Forwarding visitor info

RequestHeader set X-Forwarded-Proto "https" RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e". Apache's mod_remoteip handles real IP extraction: RemoteIPHeader X-Forwarded-For RemoteIPInternalProxy 10.0.1.0/24.

mod_cache

Proxy-level caching

Apache's mod_cache can cache proxy responses similarly to Nginx proxy_cache. Enable with a2enmod cache cache_disk and configure CacheRoot /var/cache/apache2/proxy. However, Varnish Cache in front of Apache is more commonly used for serious proxy caching on Apache-based stacks due to its far more powerful VCL configuration language.

When NOT to Use a Reverse Proxy

A reverse proxy adds complexity and potential failure points. It is not the right choice for every WordPress deployment.

For a single WordPress site on a single VPS where Nginx or Apache serves WordPress directly, adding a proxy layer provides no benefit. The common pattern of “Nginx as proxy in front of Apache” was once popular because Apache+mod_php was slow and Nginx handled static files better. With Apache MPM Event + PHP-FPM, this split is unnecessary – Apache serves static files efficiently and delegates PHP to FPM directly. Use a reverse proxy when you genuinely need multi-application routing, cross-server load balancing, or centralized SSL termination for a complex infrastructure. Do not add it because it seems more “professional” for a simple single-site deployment.

Need Help with WordPress?

If you have questions after reading the articles or need support – we are at your disposal. No commitments, no marketing jargon – a concrete proposal after a brief conversation.

Phone

+48 608 271 665

Mon–Fri, 8:00–16:00 CET

E-mail

contact@weboptimo.pl

We respond within 24h

Company

WebOptimo

VAT ID: PL6391758393