Skip to content

Behind Cloudflare or a proxy

Arkazzae edited this page Oct 7, 2026 · 1 revision

Set this up when visitors reach your site through Cloudflare, a load balancer, a CDN or any other reverse proxy. Without it, SafeHouse sees the proxy's address instead of each visitor's. Login limits then cannot block attackers by address, and the activity log records the proxy instead of the person.

How SafeHouse finds the visitor address

By default SafeHouse uses the address of the connection itself (REMOTE_ADDR). It ignores headers such as X-Forwarded-For, because anyone can send them. A visitor cannot fake their address that way.

A proxy changes this: the connection comes from the proxy, and the real visitor address travels in a header. SafeHouse reads that header only when you tell it which proxy to trust, and only on connections that really come from that proxy.

Set up Cloudflare

Use this when Cloudflare proxies the site (the orange cloud in Cloudflare's DNS settings).

  1. Go to SafeHouse → General.
  2. Set Proxy in front of the site to Cloudflare.
  3. Select Save Changes.

The General tab with the Proxy in front of the site setting

SafeHouse then takes the visitor address from Cloudflare's CF-Connecting-IP header, but only when the connection comes from one of Cloudflare's own address ranges. A request that reaches your server directly, bypassing Cloudflare, is judged by its own address, so the header cannot be forged.

To set the same thing in code, add this to wp-config.php:

define( 'SHOUSE_TRUSTED_PROXIES', 'cloudflare' );

Check it

Open Tools → Site Health. On a site behind Cloudflare, SafeHouse adds the check "SafeHouse and Cloudflare":

Result Meaning
"SafeHouse sees visitors' real addresses behind Cloudflare" Set up correctly.
"Requests come through Cloudflare, but SafeHouse is not set up for it" (critical) Do the steps above.
"SafeHouse is set up for Cloudflare, but this request did not come through it" Fine if you opened Site Health while reaching the server directly. If the site no longer uses Cloudflare, set Proxy in front of the site back to None: visitors connect directly.

SafeHouse ships Cloudflare's address ranges inside the plugin and does not download them. When Cloudflare adds ranges, they reach your site with a SafeHouse update.

Set up another proxy, CDN or load balancer

Name the proxy's addresses in wp-config.php, above the line /* That's all, stop editing! Happy publishing. */:

define( 'SHOUSE_TRUSTED_PROXIES', [ '10.0.0.0/8', '203.0.113.10' ] );

Each entry is one IPv4 or IPv6 address or a range in CIDR notation. List every address your proxy connects from.

SafeHouse then reads the visitor address from X-Forwarded-For on connections from those addresses. If your proxy uses another header, name it with SHOUSE_PROXY_HEADER. The value is the header's key in PHP's $_SERVER array: upper case, dashes turned into underscores, with HTTP_ in front.

define( 'SHOUSE_PROXY_HEADER', 'HTTP_X_REAL_IP' );
Header the proxy sends SHOUSE_PROXY_HEADER
X-Forwarded-For HTTP_X_FORWARDED_FOR (the default)
X-Real-IP HTTP_X_REAL_IP
True-Client-IP HTTP_TRUE_CLIENT_IP

When the header holds a list of addresses, SafeHouse reads it from the right and takes the first address that is not one of your trusted proxies. If it finds an invalid entry, or only trusted proxies, it falls back to the connection's address.

Cloudflare in front of your own load balancer

SHOUSE_TRUSTED_PROXIES is either 'cloudflare' or a list, not both. If Cloudflare connects to a load balancer that then connects to WordPress, the connection SafeHouse sees comes from the load balancer. Use the list form and include both the load balancer's addresses and Cloudflare's ranges, so that SafeHouse skips both when it reads X-Forwarded-For from the right. This works when your load balancer passes X-Forwarded-For on with Cloudflare's address appended.

What happens when nothing is set up

SafeHouse guards against the worst case. When requests come from a Cloudflare address and Cloudflare is not set up, or from a private address (such as 10.0.0.5 or 192.168.1.10) and SHOUSE_TRUSTED_PROXIES is not set, Login limits stops locking out addresses and keeps only its per-account rule. Locking out the proxy's address would lock out every visitor. Tools → Site Health then shows "Login limits cannot block by address on this server", with the reason.

A proxy on a public address that is not Cloudflare's cannot be told apart from a visitor. If your site is behind one, set SHOUSE_TRUSTED_PROXIES before you rely on Login limits. Otherwise one burst of failed logins can lock out the proxy, and everyone behind it with it. To end such a lockout, see Recover from a lockout.

How the constant and the setting interact

  • When SHOUSE_TRUSTED_PROXIES is defined, it wins. Proxy in front of the site is locked and shows "Set in wp-config.php with SHOUSE_TRUSTED_PROXIES."
  • With a list of proxies, the locked field shows None: visitors connect directly. That is expected: the list is in charge.
  • Saving the settings page while the constant is defined stores None for the field. This has no effect while the constant exists, but if you remove the constant later, set the field again.

What depends on the visitor address

  • Login limits: address lockouts and the allowlist
  • the activity log: the address of each event
  • Bot protection: SafeHouse sends the visitor address to Cloudflare Turnstile only when it knows the real one

Related pages

Clone this wiki locally