DDoS protection with a CDN: what gets absorbed vs still hits origin
For developers running web apps behind a CDN and trying to understand what attack traffic the edge actually stops versus what still reaches their infrastructure. This guide explains the request path, the failure modes that bypass CDN shielding, and the concrete origin, proxy, and app settings you can apply today.
TL;DR — A CDN can absorb volumetric junk aimed at your web hostname, terminate TLS, cache responses, and drop obvious Layer 3/4/7 floods before they touch your app. It does not magically protect anything that bypasses the CDN path: direct-to-origin IP traffic, non-HTTP services, expensive cache-miss requests, login/API abuse that looks valid, or backend resource exhaustion caused by requests the CDN forwards. Reading time: ~7 min
What it is and where it sits
For a web application, CDN-based DDoS protection sits in front of your origin and becomes the public entry point for HTTP/HTTPS. Clients resolve your hostname to the CDN edge, not directly to your VM, load balancer, or Kubernetes ingress. The CDN then decides whether to serve from cache, challenge/block/rate-limit, or forward the request upstream.
In architecture terms, it usually replaces one of these public-facing patterns:
- direct
A/AAAArecord to an origin IP - public cloud load balancer exposed to the internet
- public ingress controller service in Kubernetes
After introducing the CDN, your origin should ideally accept traffic only from the CDN or from your internal network. If your origin still has a public IP that anyone can hit directly, a large chunk of your "DDoS protection" is optional from the attacker’s point of view.
Typical request path:
View as text
[Client] ---- 1. DNS for app.example.com ----> [DNS/CDN] [Client] <---- 2. CDN edge IPs ---------------- [DNS/CDN] [Client] ---- 3. TLS + GET / -----------------> [CDN Edge] [CDN Edge] ---- 4a. cache hit ---------------> [Client] [CDN Edge] ---- 4b. cache miss / allowed ----> [Origin LB] [Origin LB] ---- 5. forward ------------------> [App] [App] ---- 6. response ----------------------> [Origin LB] [Origin LB] ---- 7. response -----------------> [CDN Edge] [CDN Edge] ---- 8. response ------------------> [Client]
What talks to it:
- browsers, mobile apps, bots, API clients
- your DNS, because the hostname must resolve to the CDN path
- your origin, because the CDN becomes an HTTP client to your backend
What it does not replace:
- origin firewalling / security groups
- app-level authz/authn
- database capacity planning
- queue backpressure
- non-web DDoS controls for SSH, SMTP, VPN, game UDP, etc.
The key mental model: the CDN protects the path through the CDN. Anything outside that path is still your problem.
How it actually works
Mechanically, the CDN helps in four different ways, and they are easy to conflate:
- Anycast edge capacity / network absorption: floods to the CDN-advertised IPs are spread across many edge locations.
- Protocol termination: the edge handles TCP/TLS/HTTP parsing so your origin does not pay that cost for every request.
- Caching: repeated requests for cacheable content never reach your origin.
- Filtering / shaping: rate limits, bot heuristics, request normalization, header validation, and sometimes challenge pages stop obviously abusive traffic.
Now the important part: only requests that are both destined for the CDN hostname and handled by the CDN policy benefit from that. If the attacker sends traffic to your origin IP directly, the CDN is out of the path.
End-to-end example: product page traffic spike during a bot flood
Assume:
shop.example.compoints to the CDN- CDN origin is
origin-lb.internal.example.net - product pages are cacheable for 60 seconds
- checkout and
/api/cartare not cacheable - origin NGINX is currently public on
203.0.113.10
Step by step:
- A botnet sends 200k requests/sec to
https://shop.example.com/products/123. - DNS resolves to CDN edge IPs. The flood lands on the CDN network, not on
203.0.113.10. - The CDN terminates TLS and sees the same URL repeated.
- Because
/products/123is cacheable and already warm, most requests are served from edge cache. Your origin sees little or nothing for that URL. - The attacker switches to
POST /api/cartwith random bodies and valid-looking headers. - The CDN still absorbs TCP/TLS overhead and may rate-limit obviously abusive clients, but these are dynamic, uncacheable requests. Allowed requests are forwarded to origin.
- Your app now spends CPU on session lookup, cart mutation, database writes, and lock contention. This is no longer a pure CDN problem.
- Meanwhile, the attacker discovers
203.0.113.10from an old DNS record or leaked email header and sends requests directly there. Those requests bypass the CDN entirely.
What reaches you in that scenario:
- all direct-to-origin traffic
- all allowed cache misses
- all dynamic/API traffic the CDN forwards
- expensive requests that are syntactically valid but semantically abusive
- origin fetch bursts after cache expiry if many edges revalidate at once
What the CDN absorbed:
- the bulk of the network flood against the hostname
- TLS handshake cost for edge-terminated requests
- repeated requests for cacheable objects
- malformed HTTP or obviously rate-abusive traffic, depending on policy
How you diagnose the bypass quickly:
curl -I https://shop.example.com/
curl -I --resolve shop.example.com:443:203.0.113.10 https://shop.example.com/
If the second command succeeds and returns your app directly, your origin is publicly reachable.
Typical output shape when the CDN path is used:
$ curl -I https://shop.example.com/
HTTP/2 200
content-type: text/html; charset=utf-8
cache-control: public, max-age=60
via: 1.1 some-cdn-edge
x-cache: HIT
server: cdn
Typical output shape when direct origin access is still possible:
$ curl -I --resolve shop.example.com:443:203.0.113.10 https://shop.example.com/
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 30 Oct 2026 10:22:11 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 18432
Connection: keep-alive
That second response is the red flag. If an attacker can do it, so can a flood.
When to use it (and when not to)
Use CDN-based DDoS protection when your app is internet-facing over HTTP/HTTPS and you can put a reverse proxy layer in front of it without breaking client behavior.
| Scenario | Recommendation |
|---|---|
| Public marketing site, docs, ecommerce catalog, media-heavy app | Yes. High value: cache offload plus edge absorption. |
| JSON API with browser/mobile clients | Usually yes, but assume dynamic endpoints still hit origin. Add origin rate limits and app quotas. |
| Login, checkout, search, GraphQL, expensive report endpoints | Yes, but CDN is only partial protection. Protect origin and app internals too. |
| Internal app only reachable over VPN/private network | Probably not needed; private ingress and network ACLs matter more. |
| Non-HTTP services like SSH, SMTP, Postgres, Redis, custom UDP | No, not with a web CDN. Use provider network protections, firewalls, private networking, and service-specific controls. |
| Tiny hobby app with no public IP except a managed platform endpoint | Maybe not. If the platform already fronts traffic and origin is not directly exposed, extra CDN complexity may not pay off. |
| You cannot restrict origin access to CDN egress or private links | Be careful. You still get some benefit, but direct-origin bypass remains a major gap. |
You probably don’t need this if your app is not publicly reachable on the internet, or your managed platform already terminates traffic behind a provider edge and does not expose a stable origin IP you control.
Trade-offs
Every benefit comes with a bill somewhere.
-
Benefit: absorbs volumetric traffic at the edge
Cost: you now depend on an extra network hop and an external control plane. Misconfiguring DNS, TLS mode, or origin health can take the site down globally. -
Benefit: cache reduces origin load dramatically
Cost: cache invalidation, stale content bugs, auth leakage if you cache personalized responses incorrectly, and debugging "why did I get old data?" incidents. -
Benefit: edge terminates TLS and HTTP cheaply
Cost: origin logs may no longer show the real client IP unless you trust and parse forwarding headers correctly. Get this wrong and rate limiting/audit trails become fiction. -
Benefit: edge filtering/rate limiting blocks obvious abuse
Cost: false positives, challenge pages breaking API clients, and attackers adapting to look like normal traffic. -
Benefit: hides origin details when configured well
Cost: only if you actually lock down the origin. Leaving port 443 open to the world nullifies much of the value. -
Benefit: simpler global performance story
Cost: vendor-specific config models, headers, purge semantics, and WAF/rate-limit rule syntax create lock-in.
Latency trade-off is usually small for cached content and often positive overall, but for uncached dynamic requests you are adding one more proxy hop. For latency-sensitive APIs, measure p95/p99 after enabling the CDN rather than assuming it is free.
In practice
1) Lock origin to CDN egress or your load balancer only
⚠️ If you apply firewall rules remotely to the only public ingress on a host, you can lock yourself out or take production down. Keep an out-of-band console/session open and test from a known-good source before saving persistent rules.
On a Linux origin using iptables, allow HTTPS only from your load balancer subnet or CDN egress ranges, then drop everyone else. Replace the example CIDRs with the ranges your provider documents.
iptables -A INPUT -p tcp --dport 443 -s 198.51.100.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -s 2001:db8:100::/48 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j DROP
iptables -A INPUT -p tcp --dport 80 -j DROP
iptables -S INPUT
This forces web traffic through the approved upstream path. The gotcha: CDN egress IP ranges can change; if you hardcode them, you need an update process or you will create intermittent origin outages.
If you are on a cloud VM, do the same in security groups / firewall rules in your provider dashboard rather than only on-host. In most dashboards this is under something like Networking -> Security Groups or VPC -> Firewall Rules.
2) Trust forwarded client IPs only from the proxy you control
If NGINX sits behind the CDN or a cloud load balancer, configure real_ip so logs and rate limits use the actual client address, not the proxy address.
http {
set_real_ip_from 198.51.100.0/24;
set_real_ip_from 2001:db8:100::/48;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
log_format main '$remote_addr - $host "$request" $status $body_bytes_sent '
'rt=$request_time ua="$http_user_agent"';
limit_req_zone $binary_remote_addr zone=perip:10m rate=20r/s;
server {
listen 443 ssl http2;
server_name shop.example.com;
location /api/ {
limit_req zone=perip burst=40 nodelay;
proxy_pass http://app_upstream;
}
}
}
This makes origin-side rate limiting meaningful again. The gotcha: never trust X-Forwarded-For from the whole internet; only accept it from known proxy source ranges, or clients can spoof their IP and bypass per-IP controls.
3) Verify direct-origin bypass and redirect behavior
A common mistake is leaving port 80/443 open on origin and then assuming the CDN is mandatory. Another is redirect loops caused by mismatched TLS expectations between edge and origin.
curl -I https://shop.example.com/login
curl -I --resolve shop.example.com:443:203.0.113.10 https://shop.example.com/login
curl -I http://203.0.113.10/
A misconfigured origin often looks like this:
$ curl -I --resolve shop.example.com:443:203.0.113.10 https://shop.example.com/login
HTTP/1.1 301 Moved Permanently
Server: nginx/1.24.0
Location: https://shop.example.com/login
That 301 by itself is not protection; it still proves the origin is reachable and spending resources. If you see repeated redirects in the CDN path, check whether the origin thinks the request is HTTP because the proxy headers are not being honored.
Further reading
- MDN Web Docs: the "HTTP caching" guide
- NGINX docs:
ngx_http_realip_module - OWASP Web Security Testing Guide: HTTP header and proxy deployment sections
- RFC 7239: Forwarded HTTP Extension
- Your cloud provider’s load balancer and firewall documentation
This article was written by an AI system and published pending human review. Verify anything you intend to act on.
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI