Skip to main content

Published · Updated

Cloudflare does not protect a directly reachable origin

The service was behind Cloudflare, but the origin accepted direct connections and its IP could be found. During a DDoS attack that meant the traffic could go around Cloudflare, and the WAF and rate-limiting rules I was tuning at the edge never saw those requests.

  • Cloudflare
  • DDoS
  • origin isolation
  • WAF
  • rate limiting
  • incident response

Why tightening the WAF didn’t help

My first move was to tighten the WAF and rate limits in Cloudflare. It didn’t reduce what was reaching the application, and Cloudflare showed nothing close to the load that was flooding the container logs.

That mismatch between Cloudflare and the origin logs was the clue: the traffic wasn’t going through Cloudflare. Censys and Shodan confirmed that the origin was exposed to the internet.

How the origin was reachable, and what I changed

The application ran in a Docker container with published ports and no reverse proxy in front of it. Docker writes its own iptables rules for published ports, so UFW on the host didn’t filter that traffic, even though it was enabled. Anyone with the origin IP could connect to the application directly.

I changed and isolated the origin IP and limited the ways the server could be reached. Only then did tuning the WAF and rate limiting make sense. The attack had no stable pattern: countries, providers, user agents and paths kept changing, and it came over HTTP/2 with heavy TLS load. I also used Sefinek’s community-maintained Cloudflare-WAF-Expressions ruleset.

In the application I cached database queries, views and routes, so each request did less work. That took load off the server, but on its own it didn’t close the way around Cloudflare.

  • Check how the origin can be found: DNS history, old records, other services on the same IP, and scanners such as Censys or Shodan.
  • If Docker publishes ports, check that the host firewall really filters them.
  • Let traffic reach the origin only through the paths the proxy setup needs.
  • Tune WAF and rate limiting after the direct path is closed, not before.
  • Caching reduces load, but it doesn’t replace closing the origin.

What I check on later deployments

When a service sits behind a reverse proxy or a CDN, I first check whether the origin accepts traffic outside that path. I do it before touching edge rules, because those rules never run for a request sent straight to the server.

Related project

Related case study: