A self-hosted Varnish CDN covers three continents for under $15/month
Your users are in Tokyo, your server is in Paris — a CDN puts your pages 10 ms away from them. With Varnish or Apache Traffic Server on three $5 VPS instances, you get the same latency as BunnyCDN or Cloudflare, without a bandwidth bill that scales with your success.
June 2026, and your SaaS is taking off in Japan. 10,000 daily visitors from Tokyo, Osaka, Seoul. Your server sits in Hetzner’s Nuremberg data center — 260 ms of latency per request. An 80 KB CSS file takes half a second to arrive. Your conversion rate tanks because every extra second of load time costs you 7% in revenue.
The standard fix: flip on Cloudflare or BunnyCDN. Two clicks, and your static assets drop from 260 ms to 10 ms. The bill: $0.01/GB in Europe, up to $0.06/GB in Africa. At 10 TB/month, that’s $100 — fine. At 100 TB/month, the bill exceeds an engineer’s salary.
What nobody tells you: the software powering Cloudflare and Fastly is open source. It’s called Varnish Cache, and you can deploy it yourself on three $5 VPS instances to cover Europe, North America, and Asia. Here’s how.
Why a CDN changes everything — by the numbers
A CDN (Content Delivery Network) is a geographically distributed fleet of servers that cache your static files — CSS, JS, images, fonts — and serve them from the node closest to the user. The logic is straightforward: instead of crossing the Atlantic for every request, the user knocks on the door of a server in their own city.
The measured gains are massive:
- Cloudflare reports an average 65% reduction in origin bandwidth on standard CDN deployments (source).
- Docker Hub went from a 97% hit ratio to 99%+ by enabling Cloudflare’s Tiered Caching and Cache Reserve — cutting its S3 bill by two-thirds (source).
- BunnyCDN claims a global median latency of 24 ms across its 119 PoP network (source).
- Fastly documents a 189% ROI over three years for its Network Services customers, per Forrester (source).
The catch? These numbers describe SaaS CDNs. You pay per gigabyte, and the more successful you are, the steeper the bill.
The SaaS CDN landscape — three profiles, three price tags
Here’s what 5 TB/month costs in Europe and North America, based on public pricing as of March 2026:
Cloudflare is unbeatable on the free tier. BunnyCDN offers the best price/performance ratio for moderate usage. Fastly dominates among news publishers and streaming platforms that need sub-150 ms cache purging. CloudFront is a billing trap — AWS egress stacks on top of CDN transfer.
But none of them give you infrastructure control. If Cloudflare decides to drop your site (it happens — see the Kiwi Farms block in 2022), you have no recourse. If BunnyCDN has no PoP in South Africa, you can’t add one.
Building your own CDN — the three-node architecture
A minimal self-hosted CDN fits on three VPS instances from three different providers, in three distinct geographic regions. Each VPS runs a reverse proxy cache that intercepts requests, checks its local cache, and returns the file without touching the origin server.
[Tokyo User] ── 10 ms ──▶ [Tokyo VPS] ──▶ [Cache HIT ?]
│
├── YES: immediate response (< 10 ms)
│
└── NO: fetch from Paris origin (260 ms)
then cache for the next request A well-configured static site typically exceeds a 95% hit ratio. In other words, 19 out of 20 requests never reach your origin server.
Picking the cache engine — Varnish vs Apache Traffic Server
Two open-source projects dominate production HTTP caching:
Varnish Cache 9.0.3 (released May 18, 2026, EOL March 16, 2027) is the de facto standard. It powers Wikipedia, Facebook (historically), Twitter, and thousands of high-traffic sites. Its strength: VCL (Varnish Configuration Language), a DSL compiled to C that lets you write fine-grained caching rules without touching application code.
sub vcl_recv {
# Fast purge: a PURGE request empties the cache
if (req.method == "PURGE") {
return (purge);
}
# Never cache admin pages
if (req.url ~ "^/admin") {
return (pass);
}
}
sub vcl_backend_response {
# Content-type-specific TTLs
if (beresp.http.Content-Type ~ "image") {
set beresp.ttl = 7d;
} elsif (beresp.http.Content-Type ~ "text/html") {
set beresp.ttl = 10m;
}
} Apache Traffic Server (ATS) is the carrier-grade alternative. Used by Yahoo, Comcast, and Apple’s CDN, it handles multiple terabits per second in production. ATS supports HTTP/1.1 and HTTP/2 natively, is administered via a REST API (traffic_ctl), and is extensible in C through plugins. Its latest stable release (10.1.3, July 2026) includes fixes for 34 CVEs. The learning curve is steeper than Varnish, but horizontal scalability is superior.
Quick verdict: pick Varnish if you’re under 50,000 requests/second and want to configure in 30 minutes. Pick ATS if you expect to exceed 1 Gbps and have a team comfortable with Linux kernel tuning.
Deployment — three VPS instances, $15/month
Here’s a real configuration, priced as of July 2026:
On each VPS, the install takes five commands:
# Install Varnish 9.0 on Debian 12
curl -s https://packagecloud.io/install/repositories/varnishcache/varnish90/script.deb.sh | bash
apt install varnish -y
# Minimal config — listen on port 80, origin pointed at Paris
cat > /etc/varnish/default.vcl << 'VCL'
vcl 4.1;
backend origin {
.host = "51.15.x.x"; # Your origin server's IP
.port = "8080";
.connect_timeout = 5s;
.first_byte_timeout = 30s;
}
sub vcl_recv {
if (req.method == "PURGE") {
return (purge);
}
# Normalize requests to maximize hit ratio
unset req.http.Cookie;
}
sub vcl_backend_response {
set beresp.ttl = 1h;
set beresp.grace = 24h; # Serve stale content if origin is down
unset beresp.http.Set-Cookie;
}
VCL
systemctl enable --now varnish Grace mode is critical: if your origin server goes down, Varnish continues serving expired content for 24 hours. Your users notice nothing.
Routing — the missing piece
Once your three nodes are up, you need to route users to the closest one. Two approaches:
DNS GeoIP — the simplest. A service like NS1 (paid, ~$50/month) or bunny.net DNS (free up to 50M queries/month) responds with the closest node’s IP based on the DNS resolver’s location. This is how most commercial CDNs work under the hood.
Anycast BGP — the telco standard. You announce the same IP from all three data centers, and Internet routing (BGP) naturally directs traffic to the nearest node. Requires an ASN and an IP prefix — unrealistic under $200/month.
For a lean budget, DNS GeoIP with bunny.net DNS (free) is the pragmatic choice. Five-minute setup:
# Example using the BunnyDNS API
curl -X PUT "https://api.bunny.net/dnszone/12345/records/1" \
-H "AccessKey: $BUNNY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"Type": 1,
"Name": "cdn",
"Value": "",
"SmartRoutingType": 3
}' Honest trade-offs — what SaaS does that you won’t
A self-hosted CDN is not a universal replacement. Here’s what you lose compared to Cloudflare or BunnyCDN:
- DDoS protection. Cloudflare absorbs 2.3 Tbps attacks (record set in 2025). Your three $5 VPS instances go down at 10 Gbps.
- On-the-fly image optimization. BunnyCDN and Cloudflare resize images in real time (WebP, AVIF) without touching the origin. With Varnish, you must pre-generate variants.
- WAF and security rules. Cloudflare blocks SQL injection, XSS, and malicious bots at the CDN layer. Varnish doesn’t do that — you need to layer on ModSecurity or an external WAF.
- Instant global purge. Fastly clears its worldwide cache in 150 ms. Varnish requires a script that calls
PURGEon every node, taking 2-3 seconds across three PoPs.
The workaround: you can combine both. A SaaS CDN upfront for DDoS protection and WAF, with your own Varnish nodes as a secondary origin to absorb static load without paying SaaS egress fees. This is what The New York Times does with Fastly + internal Varnish.
Verdict — when to build your own
Use BunnyCDN or Cloudflare if:
- Your traffic is under 5 TB/month — the SaaS bill is cheaper than an engineer’s time configuring Varnish.
- You have no ops team — a SaaS CDN takes 10 minutes to configure; Varnish in production requires on-call rotation.
- You face regular DDoS attacks — Cloudflare’s edge filtering is irreplaceable on a small budget.
Build your own CDN if:
- You exceed 20 TB/month — at that volume, $15 in VPS beats any SaaS pricing tier.
- You have sovereignty requirements — your data must stay within the EU, and you don’t want to depend on a US company.
- You need caching rules that can’t be expressed in a SaaS dashboard — VCL is Turing-complete; Cloudflare’s UI is not.
A self-hosted CDN isn’t a self-hosting fad. It’s an economic calculation that flips to $15 a month the moment your traffic justifies three VPS instances. And with Varnish 9.0 and ATS 10.1, the software layer is more reliable than ever — it’s the same code running at the largest sites on the web.