Content Delivery Networks: A Practical CDN Deployment Guide

· Published · 19 min read

Global users reach nearby edge caches while controlled misses pass through an origin shield to a protected application origin

A content delivery network is easy to switch on. The difficult part is deciding what the edge may cache, what must always return to the application, and how you will recover when those rules are wrong. This guide builds that operating model from the first request trace through production cutover.

The examples use www.example.com, origin.example.net, and documentation addresses. Replace them with approved values. Commands that inspect a public endpoint are safe to run from an ordinary workstation. Configuration and DNS changes belong in a reviewed change window.

What a CDN actually changes

Without a CDN, a browser resolves your hostname and connects to the origin or its load balancer. With a CDN, DNS leads the browser to an edge location selected by the provider. A cached response can return from that edge. A miss, bypass, or uncacheable request continues to the origin, often through an upper-tier cache or origin shield.

This shortens some network paths and reduces repeated origin work. It does not repair a slow database query, make an uncached API fast, or remove the need for origin capacity. The first useful diagram for a CDN project is therefore a request map, not a vendor comparison.

TrafficStarting policyReason
Hashed CSS, JavaScript, fonts, and imagesLong shared-cache lifetime; new URL for every changed objectThe filename identifies the content, so an old object can remain cached safely.
HTML that is identical for everyoneShort shared-cache lifetime or revalidationSmall freshness windows can absorb traffic without hiding a release for long.
Personalized HTML and authenticated APIsprivate, no-store until a reviewed design proves otherwiseA shared cache must not mix one user's response with another user's request.
Public GET APICache only named routes with a deliberate key and TTLQuery strings, headers, authorization, language, and tenant identity can change the representation.
Video and large downloadsTest range requests, signed access, chunking, and origin loadPartial responses and authorization require more than a generic static-file rule.
Uploads, checkout, login, and administrationBypass cache and restrict at the edgeThese are state-changing or sensitive workflows, not cache candidates.

Capture a baseline before touching DNS

Measure from the places that matter to the application. One fast result from the office says little about customers on a different ISP or continent. Record the current DNS answers, TLS certificate, response headers, body checksum, timing, status, and origin load.

date -u
dig +short A www.example.com
dig +short AAAA www.example.com
dig +short CNAME www.example.com
curl -sS -D /tmp/origin-headers.txt \
  -o /tmp/origin-body.bin https://www.example.com/
sha256sum /tmp/origin-body.bin
sed -n '1,40p' /tmp/origin-headers.txt

curl -sS -o /dev/null \
  -w 'code=%{http_code} remote=%{remote_ip} dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' \
  https://www.example.com/

Run several samples rather than treating one request as a benchmark. Keep application and load-balancer metrics beside the client trace. A faster time-to-first-byte paired with a rising error rate is not a successful rollout.

Unsafe: curl -k disables certificate verification. It can help isolate a certificate problem during a controlled investigation, but it must not be used as the acceptance test or embedded in monitoring.

Make the origin's caching intent explicit

A CDN can override origin headers, but the cleanest design starts with honest HTTP responses. These directives carry different meanings:

DirectivePractical meaningCommon mistake
publicA shared cache may store the response when the other conditions permit it.Adding it to a response that contains account or tenant data.
privateThe response is intended for a private cache, usually one user's browser.Assuming it means encrypted or confidential storage.
no-storeCaches must not store the request or response.Replacing it with no-cache, which permits storage with revalidation.
no-cacheThe response may be stored but must be validated before reuse.Reading the name as “never store.”
max-ageFreshness lifetime for a browser and, unless overridden, shared caches.Giving unversioned assets a year-long lifetime.
s-maxageShared-cache freshness lifetime that takes precedence over max-age.Forgetting that the browser and edge can then have different lifetimes.
stale-while-revalidateAllows a stale response while the cache refreshes it in the background.Using it where even a brief stale response is unacceptable.
stale-if-errorAllows stale content during eligible upstream failure.Serving stale account, price, legal, or safety information without approval.

Nginx example for versioned static assets

# Use this only when filenames contain a content hash.
location ~* ^/assets/.+\.[0-9a-f]{8,}\.(?:css|js|png|jpg|jpeg|gif|webp|svg|woff2)$ {
    try_files $uri =404;
    add_header Cache-Control "public, max-age=31536000, immutable" always;
}

# The application should set route-specific policy for HTML and APIs.
location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Do not apply the year-long rule to app.js, logo.png, or another reusable filename unless deployment creates a new URL whenever the bytes change. Purging is a recovery tool; content-addressed filenames are the normal release mechanism.

Application response examples

# Public HTML with a five-minute shared lifetime
Cache-Control: public, max-age=0, s-maxage=300, stale-while-revalidate=30

# Account page or authenticated API response
Cache-Control: private, no-store

# Versioned static object
Cache-Control: public, max-age=31536000, immutable

Design the cache key before chasing hit ratio

The cache key decides which requests may share one object. A key that includes every cookie and query parameter creates thousands of nearly empty cache variants. A key that ignores a meaningful language, tenant, currency, device, or authorization signal can serve the wrong representation.

Start with scheme, host, normalized path, and only the query parameters that change the response. Remove tracking parameters only after proving the application does not use them. Forwarding a value to the origin and including it in the cache key are separate decisions on several CDN platforms.

Example request:
https://www.example.com/products/42?color=blue&utm_source=newsletter

Possible reviewed key:
https | www.example.com | /products/42 | color=blue

Never ignore without evidence:
tenant, account, language, currency, authorization, preview, signed-access fields

Unsafe: a “cache everything” rule on all GET requests can store personalized HTML, error pages, redirects, and authenticated responses. If a provider offers a force-cache mode, scope it to known public paths and test the exact exclusion order.

Keep compression and variants under control

Compression changes the representation even when the URL stays the same. Most current CDNs can negotiate Brotli or gzip at the edge, but the origin, CDN, and browser must agree on how variants are stored and identified. Check Content-Encoding, Vary, body integrity, and object size with and without an Accept-Encoding request header.

URL='https://www.example.com/assets/app.9f31c2ab.js'

curl -sS --compressed -D /tmp/compressed.headers \
  -o /tmp/compressed.body "$URL"
curl -sS -H 'Accept-Encoding: identity' \
  -D /tmp/identity.headers -o /tmp/identity.body "$URL"

grep -Ei '^(HTTP/|content-encoding:|content-length:|vary:|etag:|cache-control:)' \
  /tmp/compressed.headers /tmp/identity.headers
wc -c /tmp/compressed.body /tmp/identity.body

curl --compressed asks for supported compression and transparently decodes the downloaded body, so the saved byte count is not the wire-transfer size. Use CDN logs, browser developer tools, or a packet-aware measurement when transfer size is the question.

Every new Vary field can multiply cache entries. Vary: Accept-Encoding is common. Vary: Cookie often destroys reuse because cookie values differ widely. Vary: User-Agent can create an uncontrolled number of variants. Prefer a small normalized device or content capability in the provider's cache key when the response truly differs.

CORS needs similar discipline. If the application returns a different Access-Control-Allow-Origin value for each approved origin, its cache design must prevent one caller receiving another caller's policy. Test allowed and denied origins explicitly. Never reflect an arbitrary Origin request header while also allowing credentials.

Keep the origin private enough to matter

A visitor who can resolve or guess the origin address may bypass edge rate limits, WAF rules, bot controls, and DDoS absorption. Protect the origin with the strongest mechanism the platform supports: private service connectivity, an origin access identity, mutual TLS, authenticated origin pulls, a rotated secret header checked by the origin, or maintained provider address ranges.

IP allowlists alone need an owner and an update process. CDN networks change. A stale allowlist can either block legitimate fills or leave an abandoned range trusted.

# Inventory exposure from an approved external probe.
dig +short origin.example.net
nmap -Pn -p 80,443 origin.example.net

# Confirm the public hostname and origin do not accidentally expose
# different applications for an untrusted Host header.
curl -sS -D - -o /dev/null \
  --resolve www.example.com:443:192.0.2.10 \
  https://www.example.com/

The --resolve test deliberately connects to a chosen address while preserving TLS SNI and the HTTP host. Run it only against systems you own or are authorized to test.

Close cache-poisoning and cache-deception paths

A cache turns one upstream response into many downstream responses. That multiplication is valuable for performance and dangerous when an attacker can influence the stored object. Keep untrusted forwarding headers, rewritten hostnames, method overrides, and ambiguous paths out of the key and origin request unless the application needs them.

Normalize or reject duplicate slashes, dot segments, encoded delimiters, unexpected ports, and unrecognized hostnames consistently at the edge and origin. If the two layers interpret a path differently, an attacker may persuade one layer that a private page looks like a static file. Do not classify cacheability from a filename extension alone when application routing can serve account content at that path.

# Use a non-sensitive test route and compare edge/origin interpretation.
for path in \
  '/public/test.css' \
  '/public//test.css' \
  '/public/../public/test.css' \
  '/account/test.css'; do
  printf '\npath=%s\n' "$path"
  curl --path-as-is -sS -D - -o /dev/null \
    "https://www.example.com${path}" \
    | grep -Ei '^(HTTP/|location:|cache-control:|age:|x-cache:|cf-cache-status:)'
done

These requests can appear in security monitoring, and the last path must use a dedicated test account or a route that carries no personal data. The expected outcome is defined by your router. What matters is that the CDN and origin agree and that private content never receives a shared-cache policy.

Do not trust a client-supplied X-Forwarded-Host, X-Original-URL, or similar override merely because the CDN forwards it. Strip unneeded values at the edge, set trusted forwarding metadata yourself, and make the origin accept only the intended host and proxy path. Add automated tests whenever a rule, framework router, or reverse proxy changes.

Use shielding to prevent a miss storm

With independent edge caches, a new release or purge can make many locations request the same object from the origin at once. Tiered caching or origin shielding sends those misses through a smaller upper tier. Request collapsing can reduce duplicate fills further.

This changes the failure path. Monitor the edge, shield, and origin separately. A shield selected far from the origin can add latency to every pass and miss. A purge of the entire site can still create a large refill wave.

Set up TLS, DNS, and cutover without guessing

Add the hostname to the CDN, complete domain validation, and wait for the edge certificate before changing public DNS. Confirm supported TLS versions, HTTP/2 and HTTP/3 policy, IPv6, redirects, HSTS ownership, and certificate renewal alerts. Keep the origin certificate valid even when only the CDN should reach it.

# Before cutover
dig +short CNAME cdn-validation.example.com
openssl s_client -connect cdn.example.net:443 \
  -servername www.example.com -verify_return_error </dev/null

# Test the CDN endpoint while retaining the production Host and SNI.
curl -sS -D /tmp/cdn-headers.txt -o /tmp/cdn-body.bin \
  --resolve www.example.com:443:192.0.2.20 \
  https://www.example.com/
sha256sum /tmp/cdn-body.bin
diff -u /tmp/origin-headers.txt /tmp/cdn-headers.txt || true

A header diff is evidence to review, not an automatic failure. The CDN will legitimately add cache, trace, and timing headers. Investigate lost security headers, changed cookies, unexpected redirects, compressed-body mistakes, and a changed content type.

Lower the existing DNS TTL ahead of the approved window, wait at least the previous TTL, then confirm major resolvers see the lower value. Keep the previous target available through the rollback window. Apex domains may require an ALIAS, ANAME, flattening, or provider-managed address rather than a normal CNAME.

Prove hits, misses, bypasses, and ranges

Vendor headers differ, but the test method is the same. Make two normal requests, inspect Age and provider cache-status headers, change a key component, test an excluded route, and verify the origin counters agree.

URL='https://www.example.com/assets/app.9f31c2ab.js'

for request_number in 1 2 3; do
  printf '\nrequest=%s\n' "$request_number"
  curl -sS -D - -o /dev/null "$URL" \
    | grep -Ei '^(HTTP/|age:|cache-control:|vary:|etag:|last-modified:|cf-cache-status:|x-cache:|x-cache-hits:|server-timing:)'
done

# Query-string behavior
curl -sS -D - -o /dev/null "${URL}?utm_source=test"

# Range behavior for a large object
curl -sS -D - -o /dev/null \
  -H 'Range: bytes=0-1023' \
  https://www.example.com/downloads/large-file.bin

# Private route must not become a shared-cache hit
curl -sS -D - -o /dev/null \
  https://www.example.com/account/

Do not send real session cookies into shared test logs. Use a dedicated test account and redact authorization, cookie, signed-URL, and personal fields from evidence.

Release with versioned URLs; invalidate narrowly

A release should publish immutable assets first, deploy HTML that points to their new names, and leave the prior assets available during rollback. This avoids a global purge and lets old HTML continue loading its matching files.

When an object must be removed early, invalidate the smallest path, prefix, host, or cache tag that solves the problem. Confirm whether the provider treats query variants, case, custom keys, and wildcard paths the way you expect.

# Amazon CloudFront example: invalidate one known object.
aws cloudfront create-invalidation \
  --distribution-id E1234567890ABC \
  --paths '/index.html'

# Azure Front Door Standard/Premium example: purge one path.
az afd endpoint purge \
  --resource-group cdn-production \
  --profile-name public-edge \
  --endpoint-name website \
  --domains www.example.com \
  --content-paths '/index.html'

Unsafe at scale: invalidating /*, pressing “purge everything,” or clearing every cache tag can send the full audience back to the origin. The command remains valid for a genuine site-wide exposure or corruption event, but first confirm origin headroom, rate limits, refill order, and rollback.

Do not confuse a CDN with every adjacent edge product

CapabilityWhat it contributesWhat it does not guarantee
Authoritative DNSDirects the hostname toward the CDN or traffic manager.That the response is cached or the origin is protected.
Load balancerDistributes requests among origins or application instances.Global edge caching close to users.
WAF and bot controlsInspect or rate-limit eligible edge traffic.Protection when the origin remains directly reachable.
DDoS protectionAbsorbs or filters supported attack traffic.Application correctness or unlimited capacity.
Public JavaScript library CDNHosts common third-party open-source assets.A controlled CDN for your whole site, API, logs, purge, or origin.
Internet exchangeLets participating networks exchange traffic directly.That every connected network sells a CDN service or serves your object from that city.

Build a shortlist by workload, not by logo count

The providers below are starting points for evaluation, not a ranking. Contract, price, points of presence, cache behavior, logs, support, security controls, purge model, origin connectivity, data processing, and actual performance vary by plan and region.

Provider or serviceUseful evaluation angleCheck before selection
Akamai CDNLarge distributed platform, media and enterprise deliveryConfiguration model, contract, logs, purge, security integration, and support boundary
Cloudflare CDNIntegrated proxy, DNS, cache, security, and edge controlsPlan-specific cache keys, logs, rules, origin protection, and data location needs
Amazon CloudFrontAWS-integrated origins, policies, signed access, functions, and shieldingCache/origin-request policies, invalidation, logging cost, origin identity, and AWS egress
Fastly CDNProgrammable edge behavior, fast purge, shielding, and detailed delivery controlVCL or Compute skills, service limits, logging, key design, purge authentication, and support
Google Cloud CDNGoogle Cloud load-balancer integration, signed access, and backend services/bucketsCache mode, URL map, key policy, private origins, invalidation, and project cost model
Azure Front Door Standard/PremiumAzure global application delivery, caching, routing, and securityTier, rules engine, origin health, purge behavior, private link needs, and migration status
Imperva CDNApplication delivery combined with security controlsCache behavior, origin access, logs, false-positive operations, regional reach, and contract
bunny.net CDNSelf-service delivery, storage integration, and straightforward regional pricingRequired regions, log detail, purge, security, support, compliance, and origin controls
CDN77Web, software, and video deliveryActual audience coverage, cache policy, logs, traffic commitment, security, and support
Gcore CDNCDN, media, edge, and security optionsPlan-specific network reach, rules, observability, data handling, and support
CacheFlyContent and large-object deliveryAudience tests, cache key, origin shield, logs, purge model, and commercial terms
KeyCDNSelf-service pull zones and static deliveryFeature fit, regional tests, logs, security, purge, support, and compliance

For shared open-source front-end libraries, jsDelivr and cdnjs solve a narrower problem. They are not substitutes for controlling your own hostname, origin, cache policy, access logs, and purge process.

Use multi-CDN only when one CDN is not enough

Two providers can reduce dependence on one control plane or network, but they also create two cache languages, two log formats, two security policies, and two incident paths. The hard part is not adding a second CNAME. It is keeping both providers behaviorally equivalent while traffic moves between them.

Choose the steering layer deliberately. DNS steering is widely supported but follows resolver and TTL behavior. Anycast or provider-specific traffic management has different failure boundaries. Application redirects add another request and may not help when the primary hostname is unavailable. Whatever the method, measure how quickly a failed provider leaves service and how much cold-cache traffic reaches the origin after the move.

Use the same immutable asset URLs, cache intent, private-route exclusions, origin authentication, TLS policy, security headers, signed-access rules, and release identifiers on both paths. Send logs to one normalization pipeline and retain each provider's trace ID. A health check that fetches only /health can declare a CDN healthy while customer objects, certificate delivery, or origin fills are broken, so test representative public and uncached paths.

Multi-CDN is justified when measured availability, geography, contractual independence, capacity, media delivery, or regulatory requirements outweigh that extra work. For a small site with one origin and no 24-hour operations team, a well-tested single CDN plus a documented DNS bypass may recover faster than two partially maintained configurations.

Know which familiar service names require action

Name found in an inventoryCurrent operating decision
Edgio, EdgeCast, or Limelight deliveryDo not select it for a new deployment. Akamai acquired selected Edgio customer contracts and patent rights, not the Edgio network or technology, before Edgio's CDN ceased operation in January 2025. Confirm where any remaining hostname now terminates.
Azure CDN from EdgioRetired on 15 January 2025. Verify that profiles and DNS have moved to a supported service.
Azure Front Door (classic)Retires on 31 March 2027. New work should use Front Door Standard or Premium.
Azure CDN Standard from Microsoft (classic)Retires on 30 September 2027. Plan migration to Front Door Standard or Premium.
“Free CDN” in a feature listSeparate a vendor's free plan from a public library CDN. Confirm quotas, logs, support, security, terms, and whether your own hostname and origin are supported.

Evaluate CDN reach in India with measurements

DE-CIX India currently operates exchanges in Mumbai, Delhi, Chennai, Kolkata, Hyderabad, and Bengaluru. Its connected-network directory is useful evidence of interconnection, but it is not a product catalogue. The directory can also retain names during a network transition, so confirm service status with the network and CDN provider.

Network shown in the DE-CIX India directoryASNLocations currently listed
Akamai TechnologiesAS20940Mumbai, Delhi, Chennai, Kolkata
Amazon.comAS16509Mumbai, Delhi, Chennai, Kolkata
CloudflareAS13335Mumbai, Delhi
FastlyAS54113Mumbai
GoogleAS15169Mumbai, Delhi, Chennai
MicrosoftAS8075Mumbai, Delhi, Chennai
CacheFlyAS30081Mumbai
G-Core LabsAS199524Mumbai
ImpervaAS19551Mumbai
NetflixAS2906Mumbai, Delhi
MetaAS32934Mumbai, Delhi, Chennai, Kolkata, Hyderabad
AppleAS714Mumbai

This compact view was checked against the live directory on 19 August 2026. Netflix, Meta, and Apple are examples of content networks, not general CDN products offered to every website owner. Port capacity is deliberately omitted because it changes and does not tell you how your users will be routed. Use the live DE-CIX India connected-network directory for the full list, then test actual customer ISPs and cities.

# Resolve and record the edge selected from each approved test location.
dig +short A www.example.com
dig +short AAAA www.example.com

# Trace path quality without assuming the final responding router is the cache.
mtr -rwzc 20 www.example.com

# Capture repeatable HTTP timing and the selected remote address.
curl -sS -o /dev/null \
  -w 'remote=%{remote_ip} code=%{http_code} ttfb=%{time_starttransfer} total=%{time_total}\n' \
  https://www.example.com/assets/test-object.bin

Watch the signals that expose a bad CDN rule

Build one view that joins client experience, CDN delivery, and origin health. At minimum, follow request volume, hit/miss/bypass state, status codes, time to first byte, bytes served, origin requests, origin egress, shield behavior, purge activity, TLS errors, WAF decisions, and cost. Break results down by hostname, path class, country or region, device family, and release when those dimensions are available and privacy-approved.

A rising hit ratio is not automatically good. It may mean that an over-broad rule is caching something that should be private. Keep synthetic tests for known public, private, missing, redirected, ranged, compressed, and error responses.

Troubleshoot from the response back to the origin

SymptomEvidence to compareLikely boundary
Object never becomes a hitCache-Control, Vary, cookies, query key, status, size, provider cache statusUncacheable origin response, fragmented key, rule order, or eviction
Wrong language, currency, or tenantRequest dimensions, key definition, response variants, cookies, authorizationA meaningful value is missing from the key or a private route was cached
Release still shows old contentAsset URL, HTML URL, TTL, purge target, query variants, shield stateReusable filenames, incomplete invalidation, browser cache, or stale policy
Origin overload after purgePurge event, edge/shield misses, request collapsing, origin queue and saturationBroad invalidation or insufficient shield/refill control
Intermittent 502, 503, or 504CDN trace ID, origin health, connect/TLS time, timeout, keepalive, deployment eventsOrigin connection, capacity, health checks, or timeout mismatch
Large download failsRange request, 206, Content-Range, object size, timeout, compressionRange handling, fill limit, origin support, or transfer timeout
Direct origin remains reachableDNS history, certificates, firewall, object-store policy, origin authenticationMissing private connectivity or origin access enforcement

Roll back without creating a second incident

Rollback is usually a DNS or traffic-manager change plus restoration of the prior origin policy. Keep the origin capable of taking the expected load. Do not delete the CDN configuration, certificate, logs, or prior DNS target until the rollback window closes.

# Before rollback, record current answers and edge evidence.
date -u
dig www.example.com A +noall +answer
dig www.example.com AAAA +noall +answer
curl -sS -D /tmp/pre-rollback-headers.txt \
  -o /dev/null https://www.example.com/

# Apply the reviewed DNS or traffic-manager rollback outside this shell.
# Then verify from multiple resolvers and networks.
dig @1.1.1.1 www.example.com A +noall +answer
dig @8.8.8.8 www.example.com A +noall +answer
curl -sS -o /dev/null \
  -w 'remote=%{remote_ip} code=%{http_code} total=%{time_total}\n' \
  https://www.example.com/

If the incident is limited to one cache rule, a scoped configuration rollback is safer than bypassing the entire CDN. If the edge is unavailable, the origin must still enforce authentication, authorization, and safe host routing when direct traffic resumes.

A production acceptance record

  • Every hostname, origin, route class, data owner, DNS owner, and rollback owner is recorded.
  • Hashed assets, public HTML, public APIs, private responses, uploads, errors, redirects, and ranges have explicit cache decisions.
  • The cache key includes every value that changes a representation and excludes only proven noise.
  • The origin validates the CDN or uses private connectivity; direct bypass is tested and controlled.
  • TLS, IPv4, IPv6, HTTP versions, redirects, HSTS, CORS, cookies, compression, and security headers match the intended behavior.
  • Hits, misses, bypasses, revalidation, stale service, purge, shield, and request collapsing have been exercised.
  • Tests cover approved regions and customer ISPs, including India where it matters to the audience.
  • Logs, trace IDs, metrics, alerts, costs, retention, and privacy controls are available to the operators who will handle an incident.
  • Versioned releases, narrow invalidation, origin-capacity protection, DNS rollback, and configuration rollback have passed.

Primary references

Related technical notes

Technical review

Need this checked against your own sending system?

Share the domain, headers, bounces, provider warning, logs, or infrastructure symptom and NitWings will identify the practical next step.

Schedule a Technical Review
Advertisement