What is a CDN? CDN stands for content delivery network. A CDN is a globally distributed network of servers that keep copies of your website’s files and serve them from whichever location is closest to the visitor. Instead of every request from Sydney, Chicago and London travelling all the way to your one server in Nuremberg, a data center nearby answers from its cache.
That sounds like a tool for Netflix and Amazon. In reality, a large share of the web runs through CDNs today, including plenty of small blogs, often without the owner knowing exactly what happens along the way. That’s why we didn’t want to just explain it for this article. We wanted to measure it.
We run getmind.io on a single Hetzner server in Nuremberg, Germany, with no CDN in front of it. On October 3, 2026 we fetched the same page from three locations (Nuremberg, Helsinki, and Ashburn, Virginia) and compared it against three major CDNs. Three findings up front:
1. Our article reaches Nuremberg after 43 ms, Helsinki after 88 ms and Virginia after 355 ms to first byte (median of five fetches). A comparable file from Cloudflare’s CDN reached Virginia in 47 ms.
2. In our logs from the past eight days, only 3 % of browser visitors list German as their first language. 44 % English, 17 % Chinese. Our “German” server mostly serves people who sit far away.
3. While digging, we found two things in our own configuration that a CDN would either have made worse or hidden from us. More on that below, honestly.

What is a CDN? The short version in five sentences
- Your website lives on an origin server, somewhere at a fixed location.
- A CDN puts many servers in many places in front of it, called edge servers or PoPs (points of presence).
- Visitors are automatically routed to the nearest edge server, usually via DNS or anycast.
- If the edge server already has the file in its cache, it serves it immediately (cache hit). If not, it fetches it once from the origin and keeps it (cache miss).
- As a result, pages get faster, the origin server gets relief, and attacks hit the big network first instead of your small server.
That’s really the core of it. The rest of this article explains why it works, where its limits are, and when it’s worth it for you.
Video: ByteByteGo walks through how a CDN works with clear animations. A good primer if you’d rather see it once visually.
Why do you need a CDN at all? The problem is distance
The internet is fast, but not faster than light. In fiber, a signal travels at roughly two thirds of the speed of light, about 200,000 kilometers per second. Nuremberg to Virginia is roughly 7,000 km as the crow flies, and cables don’t run straight. In practice, a round trip adds up to around 100 milliseconds.
We measured it. A simple ping to our server:
| From | Distance (rough) | Ping round trip |
|---|---|---|
| Nuremberg (same server) | 0 km | 0 ms |
| Helsinki (Hetzner) | ~1,600 km | 24 ms |
| Ashburn, Virginia (Hetzner) | ~7,000 km | 102 ms |
100 milliseconds sounds harmless. The catch: setting up an HTTPS connection takes more than one round trip. First the TCP handshake (one round trip), then the TLS handshake (one more with TLS 1.3), then the actual request (another one). Every round trip pays the full distance.

Here’s what that looks like in numbers. We fetched our DNS article five times per location with curl and logged each phase (median):
| Location | TCP connected | TLS done | First byte (TTFB) | Complete (25 KB gzip) |
|---|---|---|---|---|
| Nuremberg | 2 ms | 41 ms | 43 ms | 44 ms |
| Helsinki | 26 ms | 62 ms | 88 ms | 113 ms |
| Ashburn (US) | 103 ms | 252 ms | 355 ms | 456 ms |
You can almost see the round trips with the naked eye: in Ashburn, each stage costs about 100 ms more. Before a visitor in Virginia sees a single byte of text, a third of a second has passed. And that’s only the HTML. Images, fonts and scripts follow.
A CDN solves exactly this part: it shortens the distance. The TLS handshake happens with a server in the same city, not one on another continent.
CDN vs. your own server: a direct comparison
To see what a CDN does from the same starting point, we also loaded a well-known, publicly hosted file: the jQuery library (87 KB), which sits on three major CDNs. Time to first byte, five runs each:
| Source | Nuremberg | Helsinki | Ashburn (US) |
|---|---|---|---|
| getmind.io (own server, no CDN), 73 KB image | 23–30 ms | 116–125 ms | 342–428 ms |
| cdnjs (Cloudflare) | 75–86 ms | 31–46 ms | 41–52 ms |
| jsDelivr (multi-CDN) | 75–81 ms | 41–52 ms | 34–51 ms |
| code.jquery.com (Fastly) | 47–54 ms | 44–53 ms | 32–40 ms |
Two things stand out.
First: in Ashburn, the CDN is roughly eight times faster than our server. In Helsinki, about twice as fast. That’s the normal case CDNs were built for.
Second: in Nuremberg, our own server is faster than every CDN. Obviously, since we’re measuring from the same machine. But there’s a more interesting reason: Cloudflare answered our request from Nuremberg in Paris (colo=CDG in the trace output), not Frankfurt. A CDN doesn’t automatically serve from the geographically closest place but from the closest one in network terms, and which one that is depends on your provider’s network. From Helsinki, Cloudflare answered from Helsinki (colo=HEL, ping 1.6 ms), from Ashburn from Ashburn (colo=IAD, ping 0.9 ms).
The honest summary: a CDN doesn’t make a website faster for everyone. It makes it faster for distant visitors and roughly the same for nearby ones. If all your visitors are in the same region as your server, you gain little in speed.
How does a CDN work? Step by step
Say you open https://example.com/image.webp and the site sits behind a CDN.
- DNS lookup. Your computer asks which IP address belongs to
example.com. Instead of the origin server’s address, it gets back an address belonging to the CDN. (How name resolution works in detail is covered in our article What Is DNS?.) - Route to the nearest edge. Your packet heads to that address and lands at the CDN’s closest data center. How “closest” gets decided is explained below under anycast.
- TLS at the edge. The encrypted connection is established with the edge server, not the origin. That’s why the CDN needs a valid certificate for your domain.
- Cache check. The edge server checks whether it already has
image.webpand whether its copy is still valid. - Hit or miss. On a hit, the file comes back immediately. On a miss, the edge asks the origin server (often over a fast, persistent connection), stores the response, and passes it on.
- The next visitor in the same region gets the file straight from cache. The origin never notices.

Technically, a CDN is a large, distributed reverse proxy with a cache. It stands in front of your server, accepts requests, and answers as many as it can by itself. We took the difference between reverse proxy, load balancer and CDN apart in detail in What Is a Reverse Proxy?.
How to tell whether a site runs through a CDN
Most CDNs give themselves away in the HTTP response headers. Run curl -sI URL to see them. For our test files it looked like this:
# cdnjs.cloudflare.com
server: cloudflare
cf-cache-status: BYPASS
cf-ray: a44a14505c58d5c0-CDG
# cdn.jsdelivr.net
x-served-by: cache-fra-etou8220050-FRA
x-cache: HIT
age: 271804
# getmind.io
server: Caddy
cache-control: no-cache
- At Cloudflare,
cf-rayends with the data center’s airport code (CDG= Paris,HEL= Helsinki,IAD= Washington). x-cache: HITmeans it came from cache.age: 271804means this copy has been sitting there for a little over three days.- For
code.jquery.comfrom the US, we sawx-cache: HIT, HITwith two data centers (LGAandIAD). That’s a tiered cache: a regional node asks a larger node first before going to the origin. - Ours:
server: Caddy, nothing else. No CDN in front.
Anycast: how one IP address lives in 300 places at once
This is where it gets interesting, and it’s the part most explanations skip. We looked up the address of cdnjs.cloudflare.com from our three locations:
Nuremberg: 104.17.24.14 104.17.25.14
Helsinki: 104.17.25.14 104.17.24.14
Ashburn: 104.17.24.14 104.17.25.14
The same IP address everywhere. And yet three different data centers answered, with ping times of 14 ms, 1.6 ms and 0.9 ms. How can one address be in three places at once?
That’s anycast. Normally an IP address belongs to exactly one place (that’s called unicast). With anycast, many data centers announce the same address in internet routing (via BGP). Every router along the way simply sends the packet to whichever destination is shortest from its point of view. Visitors end up at the nearest location automatically, without anyone having to make a decision.

With jsDelivr we saw something different: different addresses per location. In Nuremberg and Helsinki, addresses from Fastly’s network (151.101.x.x); in Ashburn, Cloudflare addresses (104.17.x.x). jsDelivr is a multi-CDN: a nameserver decides, based on where the request comes from, which of several CDN providers serves you. That’s the second method, DNS-based routing, and it can be combined with anycast. The headers from Nuremberg even showed both at once: server: cloudflare and a Fastly node in x-served-by.
Anycast has a nice side effect for security: an attack with millions of packets spreads itself across all locations automatically, because each attacker lands at their nearest data center. No single server has to carry the whole load.
What a CDN caches, and what it doesn’t
A common misconception: “With a CDN, my whole website sits on 300 servers.” Usually that’s not true. What a CDN caches is decided by two things: the provider’s default rules and the Cache-Control headers your server sends.
Typically cached (static content):
- Images (WebP, AVIF, JPEG, PNG, SVG)
- CSS and JavaScript
- Fonts
- Videos and downloads
Typically not cached (dynamic content):
- HTML pages (many providers don’t by default, because they might be personalized)
- Anything with cookies, logins, shopping carts
- API responses
- POST requests
Cloudflare, for example, does not cache HTML by default. You can see it above: cf-cache-status: BYPASS. For the jQuery file on cdnjs that doesn’t matter, but for a website it means: without extra rules, every page request still goes all the way to your server. Only images and scripts come from nearby.
Cache-Control: the instruction you give yourself
These are the rules our Caddy web server sends for getmind.io:
HTML pages: cache-control: no-cache
Images (.webp): cache-control: public, max-age=86400, stale-while-revalidate=604800
Build assets: cache-control: public, max-age=31536000, immutable
Translated:
no-cachedoesn’t mean “never store”. It means “check with the server before every use whether it’s still current”. Ideal for HTML that changes daily on our site.max-age=86400means: use it for one day without asking.stale-while-revalidate=604800: after that, keep serving the old copy for up to seven days while fetching a fresh one in the background.immutablefor a year: this file never changes. Works because the filename contains a hash. New version, new name.
A CDN reads these headers and follows them. That’s the single most important sentence for anyone setting up a CDN: the CDN is only as good as your server’s cache headers. Bad headers don’t get fixed by a CDN, they get distributed worldwide.
What we found in our own configuration
We wanted to know what would happen if we put a CDN in front of getmind.io tomorrow. So we took a closer look at our responses and logs. Two findings.
Finding 1: a 404 page with a one-year guarantee
Our rule “build assets are immutable for a year” is tied to the path /_astro/*. We requested a file that doesn’t exist there:
$ curl -sI https://getmind.io/_astro/doesnotexist.css
HTTP/2 404
cache-control: public, max-age=31536000, immutable
The error page gets the instruction “unchangeable for a year”. Without a CDN that’s nearly harmless, it only affects the one browser that requested the wrong address. With a CDN it becomes a classic problem: if someone requests a file before it has finished uploading (say, during a deploy), the CDN stores the 404 for a year at that location. Everyone there would get a broken page until someone purges the cache manually.
The rule is simple: long cache lifetimes only for responses with status 200. Many CDNs cache errors only briefly by default, but you shouldn’t rely on it. We haven’t changed this yet and are noting it openly. Since there’s no CDN in front right now, it isn’t an acute risk.
Finding 2: 64 % of our traffic is error pages for bots
We analyzed the getmind.io access logs from September 25 to October 3, 2026, roughly eight days, 42,116 requests:
| Status | Requests | Bytes transferred |
|---|---|---|
| 200 (success) | 13,395 | 410 MB |
| 404 (not found) | 25,107 | 744 MB |
| 308 (redirect) | 3,368 | ~0 MB |
| Other | 274 | ~5 MB |
Almost two thirds of all bytes served are error pages. Who keeps asking for things that don’t exist? The top paths speak for themselves: /.env (196 times), /graphql (191), /.env.local (139), paths with %2e%2e%2f (that’s ../, an attempt to break out of the web root), plus hundreds of requests for old WordPress uploads and pages that never existed on this domain. These are scanners combing the whole internet for accidentally published password files and vulnerabilities.
The annoying part: our 404 page weighs 29.7 KB and is served uncompressed, even though the client offers gzip. Compressed it would be 7.2 KB. The cause is a detail in our Caddy config: the error handler (handle_errors) bypasses compression. As a rough estimate (assuming practically all 404 responses are this page), only about 180 MB would have flowed instead of 744 MB if compressed. So about 560 MB in eight days go to uncompressed error pages for bots.
What does this have to do with CDNs? A CDN would hide this load. Bots would bounce off the CDN, our server would get quieter, and we would never have noticed. That’s convenient, but it’s also a downside: a CDN makes symptoms invisible that should really be fixed at the root. We haven’t touched this one yet either, it’s on the list.
For context: according to our logs, 51 % of the real page views are bots anyway (search engines, AI crawlers, scripts). Which AI crawlers exactly, we broke down in our AI crawler log analysis.
Why getmind.io doesn’t use a CDN (yet)
That sounds contradictory at first: we show that a CDN would be eight times faster in the US, and we don’t use one. Here’s why:
1. The domain is already on Cloudflare, just without the proxy. Our nameservers are laura.ns.cloudflare.com and augustus.ns.cloudflare.com, so Cloudflare already handles our DNS. But the getmind.io record points straight at our server IP (in the Cloudflare dashboard that’s “DNS only”, the grey cloud). For us, a CDN would technically be one click. That we haven’t clicked it was not a deliberate decision so far but convenience, and this article is the occasion to make that decision on purpose.
2. Our traffic is small. In eight days we served 1.16 GB, extrapolated to about 4.4 GB a month. Any small server handles that without breaking a sweat.
3. We use the logs. For analyses like the one above we need the real visitor IPs and user agents in our own logs. Behind a CDN, requests arrive from CDN addresses, and the real IP only lives in a header (CF-Connecting-IP or X-Forwarded-For). That’s solvable but it’s work, and tools like fail2ban would need to be adjusted too.
4. Privacy. A CDN sees every page view, including the IP address. For a German business using a US provider that means a data processing agreement, an updated privacy policy, and a look at third-country transfer rules under GDPR. Solvable, but not zero.
What speaks for it: the 3 % German-language browser visitors in our logs. If 97 % of our readers sit elsewhere, “our server is in Nuremberg, that’s fine” is a weak argument. For visitors from Asia (17 % with a Chinese language setting), the gap is probably even bigger than the 355 ms from Virginia, though we didn’t measure it.
Our honest take: for getmind.io a CDN is nice, but not necessary. We’d fix the two findings above first, then test a CDN for images only, and measure the result.
The benefits of a CDN at a glance
- Faster load times for distant visitors. Our US measurement: 355 ms TTFB from our own server, about 47 ms from the CDN.
- Less load on the origin server. Every cache hit is a request your server never sees.
- DDoS protection. The CDN’s network is orders of magnitude bigger than your server, and anycast spreads attacks across all locations.
- Availability. Some CDNs can serve a cached version if your server goes down briefly (Cloudflare calls it “Always Online”, the generic mechanism is
stale-if-error). - Lower bandwidth costs, if your host bills for traffic.
- Extras: automatic image optimization, HTTP/3, bot filtering, web application firewall, edge functions.

The downsides nobody likes to talk about
- An additional point of failure. When a big CDN goes down, thousands of websites go down with it, including ones whose own servers are running perfectly. This has happened several times, with different providers.
- Cache headaches. “I changed the page but I still see the old version.” The most common CDN support topic. The cause is almost always cache lifetimes that are too long or wrong headers (see Finding 1).
- Privacy (see above).
- The real visitor IP is missing from your logs unless you explicitly take it from the header.
- Lock-in. The more features you use at the CDN (rules, workers, firewall), the harder it gets to switch.
- Little gain for a local audience. Our Nuremberg measurement: our own server was faster than all three CDNs.
Which CDN providers are there?
A rough overview of well-known providers, not exhaustive. Prices change, so always check with the provider.
| Provider | Typical for | Pricing model (as of Oct 3, 2026, provider sites) |
|---|---|---|
| Cloudflare | Getting started, sites of every size | Free plan with CDN and basic DDoS protection, paid plans for more rules |
| Bunny.net | Small to mid-sized projects, European provider | Pay-as-you-go, from $0.01 per GB in Europe/North America, $1 monthly minimum |
| Fastly | Large platforms, lots of control | Usage-based, aimed at pros |
| Akamai | Enterprises, very large network | Custom contracts |
| Amazon CloudFront | If you’re already on AWS | Usage-based by region and requests |
For perspective: our extrapolated 4.4 GB a month would cost about 4 cents at Bunny, so the $1 minimum applies. For small websites, bandwidth is no longer a real cost factor. Setup time is.
If you host on platforms like Vercel, Netlify or Cloudflare Pages, you get a CDN automatically as part of the product. More on that in our article on Vercel alternatives.
Video: IBM Technology explains content delivery networks at the whiteboard, including caching and edge locations.
Do I need a CDN? An honest checklist
A CDN tends to pay off if …
- your visitors are spread across several continents (check your logs, don’t guess:
Accept-Languageand IP origin give good hints), - you serve lots of large files (images, video, downloads),
- your server is weak or can’t handle traffic spikes,
- you’re a worthwhile target for DDoS attacks (shops, games, political topics),
- your host charges a lot for traffic.
A CDN tends to bring little if …
- your audience sits in the same region as your server (a bakery in Leeds with a server in London),
- your pages are almost entirely dynamic (logged-in users, personalized content), so hardly anything can be cached,
- you need logs with real IPs and don’t have time for the switch,
- privacy requirements make an additional processor difficult.
A middle ground we see as our own next step: a CDN for images and static files only, on a separate subdomain (e.g. static.example.com). HTML keeps coming straight from your own server, the heavy files from nearby. On our site, images account for 44 % of successfully served bytes.
Setting up a CDN: the typical process
Details depend on the provider, but the pattern is almost always the same:
- Check your cache headers before switching anything:
curl -sI https://your-domain.com/image.webp. Do images, CSS and JS have sensiblemax-agevalues? Do error pages avoid long cache lifetimes? - Create an account with the provider and register your domain or origin server.
- Switch DNS. Either hand your domain’s nameservers to the CDN (common with Cloudflare) or create a CNAME record pointing at the CDN (common with Bunny and many others).
- TLS certificate for your domain at the CDN. Most handle this automatically via Let’s Encrypt.
- Real visitor IP: have your web server take it from the header (
CF-Connecting-IP,X-Forwarded-For) and only trust requests from CDN addresses. Otherwise your logs, rate limits and fail2ban will only see the CDN. - Lock down the origin. Ideally your server is only reachable by the CDN. Otherwise attackers can simply bypass the CDN by hitting your real IP directly, which can often be dug up from old DNS records.
- Measure. Before and after, from several locations, with
curl -wlike above. Not once but several times, and with an eye on cache hits (x-cache,cf-cache-status). - Learn to purge. Every CDN has a way to evict files from cache immediately. Know it before you need it in an emergency.
Here’s how to measure the phases of a request yourself, exactly as we did for this article:
curl -s --compressed -o /dev/null \
-w 'dns=%{time_namelookup} tcp=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' \
https://your-domain.com/
What we didn’t measure
So nobody reads more into the numbers than they contain:
- Only three locations, all in data centers with excellent connectivity. A smartphone on mobile data in Jakarta sees very different numbers.
- We didn’t measure Asia, South America or Africa, even though 17 % of our browser visitors list Chinese as their language.
- The CDN comparison values come from someone else’s very popular files (jQuery). Those are in almost every edge cache. A rarely requested file on your own site would see more cache misses and be correspondingly slower.
- The language split is based on the
Accept-Languageheader of 3,961 page views without a recognizable bot user agent. 35 % sent no language at all, and those are probably bots too. - Load time isn’t the same as user experience. Google cares about Core Web Vitals (e.g. LCP), which also depend on image sizes, fonts and JavaScript, not just network distance.
Frequently asked questions
What is a CDN in simple terms?
A CDN (content delivery network) is a network of many servers around the world that hold copies of your website’s files. Visitors get the files from the nearest server instead of a distant origin server. The page loads faster, and your own server gets relief.
What does CDN stand for?
CDN stands for content delivery network, sometimes also content distribution network.
What exactly does a CDN do?
It receives requests for your website, answers them from its cache whenever possible, and only asks your server when needed. On top of that it often handles TLS encryption, compression, image optimization and attack protection.
Is Cloudflare a CDN?
Yes. Cloudflare is one of the best-known CDN providers and offers a free plan. But Cloudflare is more than a CDN: it also does DNS, DDoS protection, firewall, zero-trust access and edge functions. Important: if you use Cloudflare only as a DNS provider (grey cloud), your traffic does not go through the CDN. That’s the current setup for getmind.io.
Do I need a CDN for my website?
Not necessarily. If most of your visitors sit in the same region as your server, the speed gain is small. In our Nuremberg test, our own server was actually faster. A CDN makes sense for international audiences, lots of large files, weak servers or elevated attack risk.
Is a CDN free?
There are free offerings, most notably Cloudflare’s free plan. Paid providers like Bunny.net bill by data volume, from about one cent per gigabyte in Europe and North America. For small websites the cost is usually negligible.
Does a CDN make my website faster?
For distant visitors usually by a lot: in our measurement, our server without a CDN needed 355 ms to first byte in the US, while a comparable file from Cloudflare’s CDN took about 47 ms. For visitors near your server, barely, and on a cache miss a CDN can even be marginally slower because it adds an extra hop.
Is a CDN GDPR compliant?
It can be, but not automatically. The CDN processes your visitors’ IP addresses, so you usually need a data processing agreement and a mention in your privacy policy. With providers outside the EU, third-country transfer rules come into play. When in doubt, get legal advice.
What’s the difference between a CDN and web hosting?
Hosting is where your website actually lives and gets generated (the origin server). A CDN doesn’t replace hosting, it sits in front of it and distributes copies. No hosting, no CDN. The exception is purely static sites on platforms that bundle both into one product.
What’s the difference between a CDN and a reverse proxy?
A CDN is technically a globally distributed reverse proxy with a cache. A single reverse proxy (like Nginx or Caddy) stands in one place in front of your application, a CDN in hundreds. Details in What Is a Reverse Proxy?.
What do cache hit and cache miss mean?
A cache hit means the edge server already had the requested file stored and served it directly. A cache miss means it didn’t and had to fetch it from the origin first. The higher the hit ratio, the more you get out of the CDN.
How do I check whether a website uses a CDN?
Look at the response headers with curl -sI https://domain.com. Clues are headers like server: cloudflare, cf-ray, x-cache, x-served-by, via or age. Alternatively, look up the domain’s IP address and check which network it belongs to.
Conclusion: a CDN shortens distances, it doesn’t fix anything
At its core a CDN is a simple idea: put copies of your files where your visitors are. Our measurement shows how much that can bring. In the US, our page took 355 ms without a CDN, the CDN counterpart about 47 ms. But it also shows the other side: close to your own server a CDN brings nothing, and it hides problems instead of solving them.
For us, concretely: homework first (no long cache lifetimes for error pages, compressed 404 pages), then test a CDN for images, then measure again. If you’re weighing it yourself, start the same way: check your logs for where your visitors come from, check your cache headers, and measure before and after.
If you want to go deeper into the basics: how a domain name turns into an IP address is covered in What Is DNS?, and how to set up your own server properly in Linux Server Setup.