Cloudflare as a Transparent Proxy: Zero-Interference Edge Configuration

Troubleshooting: when the origin works but Cloudflare doesn't

In a transparent proxy setup, Cloudflare isn't modifying your content. But it is sitting between you and your users. That introduces a few failure modes worth memorizing — most of them involve caching.

Stale CSS or JS after a deploy

Cloudflare cached the old version. Purge the specific URL from Cloudflare Dashboard → Caching → Purge Cache → Custom Purge, or toggle Developer Mode on while you work (Dashboard → Caching → Developer Mode). Developer Mode bypasses cache entirely and auto-expires after three hours — good safety net if you forget to turn it off.

Long-term fix: use versioned or content-hash filenames (style.a1b2c3d.css). When the filename changes on deploy, cache invalidation is automatic — no purge needed.

526 error (invalid SSL certificate)

Cloudflare in Full (Strict) mode tried to connect to your origin over HTTPS and the SSL handshake failed. Your origin cert is expired, missing, or invalid.

# Check cert expiry
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -enddate

# Check if nginx is actually listening on 443
curl -sI --resolve "example.com:443:127.0.0.1" "https://example.com"

If the cert expired, certbot renew. If renewal failed silently, check /var/log/letsencrypt/letsencrypt.log. To prevent this entirely, add a renewal hook that reloads nginx after every successful renewal:

# /etc/letsencrypt/renewal-hooks/deploy/nginx-reload.sh
#!/bin/bash
systemctl reload nginx

Mixed content warnings but the origin is all HTTPS

A hardcoded http:// URL exists in your content. Cloudflare's Automatic HTTPS Rewrites was silently fixing these — now that it's off, you see the real problem. Browser DevTools → Console → filter for "mixed content" to find the exact URLs, then fix them at the source:

# WordPress search-replace — always --dry-run first
wp search-replace 'http://example.com' 'https://example.com' --dry-run

Cloudflare IPs in access logs instead of visitor IPs

If your logs show 172.70.x.x or 162.158.x.x for every request, real IP restoration isn't working. Verify real_ip_header CF-Connecting-IP; is set and that your cloudflare.conf is included at the http { } level in nginx.conf — not inside a server block. The full setup is in the Cloudflare Real IP guide.

Rate limiting or fail2ban blocking legitimate users

If real IP restoration isn't working, fail2ban sees all traffic from Cloudflare IPs as one "user" — one bad actor triggers a ban that blocks everyone. Even with real IPs working, tune limit_req rates conservatively: Cloudflare aggregates traffic, so multiple users can share the same edge IP. Use higher fail2ban thresholds than you would on a bare-metal server.

Bypassing Cloudflare to test the origin

When you need to confirm whether an issue is Cloudflare or your origin, test directly from the VPS:

# Gold standard — from the VPS, bypasses Cloudflare completely
curl -sI --resolve example.com:443:127.0.0.1 https://example.com

# From any machine — requires knowing the origin IP
curl -sI https://203.0.113.50 -H "Host: example.com"

# For browser testing — add to /etc/hosts temporarily
# 203.0.113.50 example.com
# (Remove the entry when done testing)

One-liner health check

Run this from the VPS whenever something feels off. If all three sections return green, the problem is at the Cloudflare layer — check caching, DNS, or SSL mode. If anything returns red, fix the origin first:

echo "=== Nginx ===" && systemctl is-active nginx && \
echo "=== PHP-FPM ===" && systemctl is-active php8.5-fpm && \
echo "=== Certs ===" && for d in /etc/letsencrypt/live/*/; do \
  echo -n "$(basename $d): "; \
  openssl x509 -in "$d/fullchain.pem" -noout -enddate 2>/dev/null | cut -d= -f2; \
done && \
echo "=== HSTS ===" && for d in $(ls /etc/nginx/sites-enabled/); do \
  echo -n "$d: "; \
  curl -sI --resolve "$d:443:127.0.0.1" "https://$d" 2>/dev/null \
    | grep -i strict-transport || echo "MISSING"; \
done

Result

With this configuration, SSL Labs grades the domain at A+ — not because Cloudflare is carrying the score, but because the origin is correctly configured and Cloudflare is simply not interfering. The origin is the single source of truth for every security decision. Cloudflare provides the global network, the edge caching, and the DDoS scrubbing. Everything else — every header, every redirect, every security policy — is yours.

Technical Audit Summary

This guide documents a transparent-proxy Cloudflare configuration where the origin owns all security policy. Every Cloudflare toggle is mapped to the origin configuration that replaces it.

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

Compatibility: The Cloudflare dashboard settings described here are current as of publication. Cloudflare occasionally reorganizes the dashboard layout and renames features; the underlying concepts (Full Strict SSL, HSTS, Auto Minify, Rocket Loader, etc.) remain the same. The origin hardening checklist assumes nginx 1.26+ and PHP-FPM 8.2+ but core logic applies broadly.

2026-05-28: Initial publication — Cloudflare transparent proxy configuration guide covering the dashboard settings checklist, trusted IP whitelist and managed challenge custom WAF rules, origin hardening prerequisites mapped to existing kbeezie guides, troubleshooting decision tree, and pre-flight validation commands. Cross-linked to Cloudflare Real IP, fail2ban, Let's Encrypt, Securing Nginx and PHP, WordPress installation, Bludit installation, WP-CLI, Preventing Search Overload, and WebP guides.

2026-05-28: Initial publication — Cloudflare transparent proxy configuration guide covering the dashboard settings checklist, origin hardening prerequisites mapped to existing kbeezie guides, troubleshooting decision tree, and pre-flight validation commands. Cross-linked to Cloudflare Real IP, fail2ban, Let's Encrypt, Securing Nginx and PHP, WordPress installation, Bludit installation, WP-CLI, Preventing Search Overload, and WebP guides.