Networking

CDN

Content Delivery Network - A geographically distributed network of servers that delivers web content to users based on their location, improving performance, reliability, and reducing latency.

What is a CDN?

CDN (Content Delivery Network) is a distributed network of servers strategically positioned around the world to deliver web content to users from the nearest location. CDNs cache static content like images, videos, CSS, and JavaScript files, significantly reducing load times and improving user experience.

How CDN Works

Basic Architecture

User in New York → CDN Edge Server (New York)
User in London   → CDN Edge Server (London)
User in Tokyo    → CDN Edge Server (Tokyo)
              ↓
All edge servers sync with Origin Server

Benefits:
- Reduced latency (shorter distance)
- Lower bandwidth costs
- Improved availability
- DDoS protection

Request Flow

// Without CDN
User → Origin Server (3000ms)

// With CDN
User → Nearest Edge Server (50ms) → [Cache Hit]
User → Nearest Edge Server (50ms) → Origin Server (300ms) → [Cache Miss]

// Typical CDN URL structure
const cdnUrl = 'https://cdn.example.com/images/logo.png';
const originUrl = 'https://www.example.com/images/logo.png';

CDN Integration

Using CDN for Static Assets

// Next.js with CDN
export default {
  assetPrefix: process.env.NODE_ENV === 'production'
    ? 'https://cdn.example.com'
    : '',
  images: {
    domains: ['cdn.example.com'],
    loader: 'custom',
    loaderFile: './cdn-loader.ts'
  }
};

// Custom loader
export default function cdnLoader({ src, width, quality }: any) {
  const params = new URLSearchParams({
    url: src,
    w: width.toString(),
    q: (quality || 75).toString()
  });
  return `https://cdn.example.com/img?${params}`;
}

Cloudflare CDN Setup

// Configure cache headers for Cloudflare CDN
export async function GET(request: Request) {
  const response = new Response('Hello from CDN', {
    headers: {
      'Content-Type': 'text/html',
      // Cache for 1 hour
      'Cache-Control': 'public, max-age=3600',
      // Cloudflare specific
      'CDN-Cache-Control': 'max-age=7200',
      // Edge cache tag for purging
      'Cache-Tag': 'homepage, v2'
    }
  });

  return response;
}

Programmatic CDN Purge

class CloudflareCDN {
  private apiToken: string;
  private zoneId: string;

  constructor(apiToken: string, zoneId: string) {
    this.apiToken = apiToken;
    this.zoneId = zoneId;
  }

  async purgeCache(urls: string[]) {
    const response = await fetch(
      `https://api.cloudflare.com/client/v4/zones/${this.zoneId}/purge_cache`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiToken}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          files: urls
        })
      }
    );

    return response.json();
  }

  async purgeEverything() {
    const response = await fetch(
      `https://api.cloudflare.com/client/v4/zones/${this.zoneId}/purge_cache`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiToken}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          purge_everything: true
        })
      }
    );

    return response.json();
  }

  async purgeByTags(tags: string[]) {
    const response = await fetch(
      `https://api.cloudflare.com/client/v4/zones/${this.zoneId}/purge_cache`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiToken}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          tags
        })
      }
    );

    return response.json();
  }
}

// Usage
const cdn = new CloudflareCDN(
  process.env.CF_API_TOKEN!,
  process.env.CF_ZONE_ID!
);

// Purge specific URLs
await cdn.purgeCache([
  'https://example.com/style.css',
  'https://example.com/script.js'
]);

// Purge by cache tags
await cdn.purgeByTags(['homepage', 'products']);

CDN Caching Strategies

Cache-Control Headers

// Cache static assets aggressively
function staticAssetHeaders() {
  return {
    // Browser cache: 7 days
    // CDN cache: 30 days
    'Cache-Control': 'public, max-age=604800, s-maxage=2592000, immutable'
  };
}

// Cache API responses with revalidation
function apiHeaders() {
  return {
    // Browser: 5 minutes, must revalidate
    // CDN: 10 minutes
    'Cache-Control': 'public, max-age=300, s-maxage=600, must-revalidate'
  };
}

// Don't cache dynamic content
function dynamicHeaders() {
  return {
    'Cache-Control': 'private, no-cache, no-store, must-revalidate',
    'Expires': '0'
  };
}

Stale-While-Revalidate

// Serve stale content while fetching fresh data
export async function GET() {
  return new Response(JSON.stringify({ data: 'value' }), {
    headers: {
      'Content-Type': 'application/json',
      // Serve from cache for 1 hour
      // Serve stale for 24 hours while revalidating
      'Cache-Control': 'max-age=3600, stale-while-revalidate=86400'
    }
  });
}

CDN with Web Scraping

Bypassing CDN Protection

async function scrapeWithCDNBypass(url: string) {
  // Some CDNs block automated requests
  // Use CorsProxy to handle CDN challenges
  const response = await fetch(
    `https://corsproxy.io/?url=${url}`,
    {
      headers: {
        'x-cors-api-key': process.env.CORS_API_KEY!,
        'x-cors-proxy-type': 'residential',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0'
      }
    }
  );

  return response.text();
}

Respecting CDN Caching

async function respectCDNCache(url: string) {
  const response = await fetch(url);

  // Check CDN headers
  const cacheStatus = response.headers.get('cf-cache-status'); // Cloudflare
  const cdnHit = response.headers.get('x-cache'); // General

  console.log('Cache Status:', cacheStatus); // HIT, MISS, EXPIRED, etc.
  console.log('CDN Hit:', cdnHit);

  // Only scrape if needed (cache miss)
  if (cacheStatus === 'MISS') {
    console.log('Fresh fetch from origin');
  }

  return response.text();
}

Image CDN Optimization

Dynamic Image Transformation

interface ImageTransformOptions {
  width?: number;
  height?: number;
  quality?: number;
  format?: 'webp' | 'avif' | 'jpeg' | 'png';
  fit?: 'cover' | 'contain' | 'fill';
}

class ImageCDN {
  private baseUrl: string;

  constructor(baseUrl: string) {
    this.baseUrl = baseUrl;
  }

  getImageUrl(path: string, options: ImageTransformOptions = {}): string {
    const params = new URLSearchParams();

    if (options.width) params.append('w', options.width.toString());
    if (options.height) params.append('h', options.height.toString());
    if (options.quality) params.append('q', options.quality.toString());
    if (options.format) params.append('f', options.format);
    if (options.fit) params.append('fit', options.fit);

    return `${this.baseUrl}/${path}?${params}`;
  }
}

// Usage
const cdn = new ImageCDN('https://cdn.example.com');

// Get optimized image URLs
const thumbnail = cdn.getImageUrl('products/shoe.jpg', {
  width: 300,
  height: 300,
  quality: 80,
  format: 'webp',
  fit: 'cover'
});

const fullsize = cdn.getImageUrl('products/shoe.jpg', {
  width: 1920,
  quality: 90,
  format: 'webp'
});

CDN Edge Functions

Cloudflare Workers

// Deploy logic at CDN edge
export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);

    // A/B testing at the edge
    const variant = Math.random() > 0.5 ? 'A' : 'B';

    // Rewrite URL based on variant
    url.pathname = `/variants/${variant}${url.pathname}`;

    // Fetch from origin
    const response = await fetch(url.toString());

    // Add custom headers
    const newResponse = new Response(response.body, response);
    newResponse.headers.set('X-Variant', variant);

    return newResponse;
  }
};

Geographic Routing

export default {
  async fetch(request: Request): Promise<Response> {
    // Get user location from CDN
    const country = request.headers.get('cf-ipcountry');
    const continent = request.headers.get('cf-ipcontinent');

    // Route to regional API
    const apiEndpoint = getRegionalEndpoint(country || 'US');

    const response = await fetch(apiEndpoint, {
      method: request.method,
      headers: request.headers,
      body: request.body
    });

    return response;
  }
};

function getRegionalEndpoint(country: string): string {
  const regions: Record<string, string> = {
    'US': 'https://us-api.example.com',
    'EU': 'https://eu-api.example.com',
    'APAC': 'https://apac-api.example.com'
  };

  return regions[country] || regions['US'];
}

CDN Performance Monitoring

Measuring CDN Performance

async function measureCDNPerformance(url: string) {
  const startTime = performance.now();

  const response = await fetch(url);

  const endTime = performance.now();
  const loadTime = endTime - startTime;

  const metrics = {
    loadTime: `${loadTime.toFixed(2)}ms`,
    cacheStatus: response.headers.get('cf-cache-status'),
    cdnRay: response.headers.get('cf-ray'),
    dataCenter: response.headers.get('cf-ray')?.split('-')[1],
    contentLength: response.headers.get('content-length'),
    contentType: response.headers.get('content-type')
  };

  return metrics;
}

// Compare CDN vs Origin
async function compareCDNvsOrigin() {
  const cdnUrl = 'https://cdn.example.com/image.jpg';
  const originUrl = 'https://origin.example.com/image.jpg';

  const [cdnMetrics, originMetrics] = await Promise.all([
    measureCDNPerformance(cdnUrl),
    measureCDNPerformance(originUrl)
  ]);

  console.log('CDN:', cdnMetrics);
  console.log('Origin:', originMetrics);
}

Security Features

DDoS Protection

// CDN provides automatic DDoS protection
// Configure rate limiting at edge
interface RateLimitConfig {
  maxRequests: number;
  windowSeconds: number;
  action: 'block' | 'challenge' | 'log';
}

const rateLimitConfig: RateLimitConfig = {
  maxRequests: 100,
  windowSeconds: 60,
  action: 'challenge'
};

// Cloudflare Worker implementation
export default {
  async fetch(request: Request, env: any): Promise<Response> {
    const ip = request.headers.get('cf-connecting-ip') || '';

    // Check rate limit
    const rateLimitKey = `ratelimit:${ip}`;
    const count = await env.KV.get(rateLimitKey);

    if (count && parseInt(count) > rateLimitConfig.maxRequests) {
      return new Response('Rate limit exceeded', { status: 429 });
    }

    // Increment counter
    await env.KV.put(rateLimitKey, (parseInt(count || '0') + 1).toString(), {
      expirationTtl: rateLimitConfig.windowSeconds
    });

    return fetch(request);
  }
};

Best Practices

For Website Owners

  1. Use long cache times for static assets
  2. Implement cache-busting strategies
  3. Configure proper cache headers
  4. Use CDN purging when content updates
  5. Enable compression (gzip, brotli)

For Developers

  1. Use CDN URLs for all static assets
  2. Implement fallback to origin
  3. Monitor CDN performance metrics
  4. Test cache behavior thoroughly
  5. Use edge functions for dynamic logic

Performance Optimization

  1. Minimize DNS lookups
  2. Use HTTP/2 or HTTP/3
  3. Enable early hints
  4. Implement image optimization
  5. Use prefetch/preconnect headers

Learn More

Create a free Account to fix CORS Errors in Production

Say goodbye to CORS errors and get back to building great web applications. It's free!

CORSPROXY Dashboard

Related Terms

More in Networking

Related guides

Back to Glossary