cdn-media-delivery

Guidance for configuring CDN delivery, cache management, and secure media access for headless CMS architectures.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "cdn-media-delivery" with this command: npx skills add melodic-software/claude-code-plugins/melodic-software-claude-code-plugins-cdn-media-delivery

CDN Media Delivery

Guidance for configuring CDN delivery, cache management, and secure media access for headless CMS architectures.

When to Use This Skill

  • Configuring CDN for media delivery

  • Implementing cache invalidation strategies

  • Setting up signed/secure URLs

  • Optimizing edge caching

  • Configuring origin shielding

CDN Architecture

Basic CDN Setup

┌─────────────────────────────────────────────────────────────┐ │ Users │ │ (Global, geographically distributed) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ CDN Edge Network │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ Edge │ │ Edge │ │ Edge │ │ Edge │ │ │ │ US-West │ │ US-East │ │ Europe │ │ Asia │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Origin Shield │ │ (Optional intermediate cache layer) │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Origin Server │ │ ┌───────────────┐ ┌────────────────┐ ┌───────────────┐ │ │ │ Media API │ │ Blob Storage │ │ Image │ │ │ │ (transform) │ │ (Azure/S3) │ │ Processor │ │ │ └───────────────┘ └────────────────┘ └───────────────┘ │ └─────────────────────────────────────────────────────────────┘

CDN Configuration

Azure CDN (Front Door)

// appsettings.json { "Cdn": { "Provider": "AzureFrontDoor", "Endpoint": "https://media.example.com", "OriginHost": "storage.blob.core.windows.net", "CacheRules": { "Images": { "CacheDuration": "365.00:00:00", "QueryStringCaching": "IgnoreQueryString" }, "Transforms": { "CacheDuration": "30.00:00:00", "QueryStringCaching": "UseQueryString" } } } }

CloudFront Configuration

public class CloudFrontConfiguration { public string DistributionId { get; set; } = string.Empty; public string DomainName { get; set; } = string.Empty; public string OriginId { get; set; } = string.Empty;

public CacheBehavior DefaultCacheBehavior { get; set; } = new()
{
    ViewerProtocolPolicy = "redirect-to-https",
    CachePolicyId = "658327ea-f89d-4fab-a63d-7e88639e58f6", // CachingOptimized
    Compress = true,
    AllowedMethods = new[] { "GET", "HEAD", "OPTIONS" },
    CachedMethods = new[] { "GET", "HEAD" }
};

public CacheBehavior[] CacheBehaviors { get; set; } =
{
    new()
    {
        PathPattern = "/media/transform/*",
        CachePolicyId = "custom-transform-policy",
        QueryStringCaching = QueryStringCaching.All
    }
};

}

Cloudflare Configuration

public class CloudflareConfiguration { public string ZoneId { get; set; } = string.Empty; public string ApiToken { get; set; } = string.Empty;

public PageRule[] PageRules { get; set; } =
{
    new()
    {
        Targets = new[] { "*example.com/media/*" },
        Actions = new PageRuleAction
        {
            CacheLevel = "cache_everything",
            EdgeCacheTtl = 2592000, // 30 days
            BrowserCacheTtl = 86400  // 1 day
        }
    }
};

}

Cache Headers

Setting Cache Headers

public class MediaCacheMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) { await next(context);

    if (context.Request.Path.StartsWithSegments("/media"))
    {
        var cacheControl = GetCacheControl(context.Request.Path);
        context.Response.Headers["Cache-Control"] = cacheControl;
        context.Response.Headers["Vary"] = "Accept, Accept-Encoding";
    }
}

private string GetCacheControl(PathString path)
{
    // Original media: cache for 1 year (immutable content)
    if (path.Value?.Contains("/original/") == true)
    {
        return "public, max-age=31536000, immutable";
    }

    // Transformed images: cache for 30 days
    if (path.Value?.Contains("/transform/") == true)
    {
        return "public, max-age=2592000, stale-while-revalidate=86400";
    }

    // Default: 1 day
    return "public, max-age=86400";
}

}

Cache-Control Directives

Directive Purpose Example

public

Allow CDN caching Images, static assets

private

Browser only User-specific content

max-age

Cache duration (seconds) max-age=86400 (1 day)

immutable

Never revalidate Versioned assets

stale-while-revalidate

Serve stale while fetching Background refresh

no-cache

Always revalidate Dynamic content

no-store

Never cache Sensitive data

Cache Invalidation

Invalidation Service

public interface ICdnInvalidationService { Task InvalidatePathAsync(string path); Task InvalidatePathsAsync(IEnumerable<string> paths); Task InvalidatePrefixAsync(string prefix); Task InvalidateAllAsync(); }

// Azure CDN implementation public class AzureCdnInvalidationService : ICdnInvalidationService { private readonly CdnManagementClient _cdnClient;

public async Task InvalidatePathAsync(string path)
{
    await _cdnClient.Endpoints.PurgeContentAsync(
        _resourceGroup,
        _profileName,
        _endpointName,
        new PurgeParameters(new[] { path }));
}

public async Task InvalidatePrefixAsync(string prefix)
{
    await _cdnClient.Endpoints.PurgeContentAsync(
        _resourceGroup,
        _profileName,
        _endpointName,
        new PurgeParameters(new[] { $"{prefix}/*" }));
}

}

// CloudFront implementation public class CloudFrontInvalidationService : ICdnInvalidationService { private readonly AmazonCloudFrontClient _client;

public async Task InvalidatePathAsync(string path)
{
    var request = new CreateInvalidationRequest
    {
        DistributionId = _distributionId,
        InvalidationBatch = new InvalidationBatch
        {
            CallerReference = Guid.NewGuid().ToString(),
            Paths = new Paths
            {
                Items = new List&#x3C;string> { path },
                Quantity = 1
            }
        }
    };

    await _client.CreateInvalidationAsync(request);
}

}

Event-Based Invalidation

public class MediaUpdatedHandler : INotificationHandler<MediaUpdatedEvent> { private readonly ICdnInvalidationService _cdn;

public async Task Handle(MediaUpdatedEvent notification, CancellationToken ct)
{
    // Invalidate original
    await _cdn.InvalidatePathAsync($"/media/{notification.MediaId}");

    // Invalidate all transformations
    await _cdn.InvalidatePrefixAsync($"/media/transform/{notification.MediaId}");
}

}

Signed URLs

Signed URL Generation

public class SignedUrlService { public string GenerateSignedUrl( string path, TimeSpan validity, SignedUrlOptions? options = null) { options ??= new SignedUrlOptions();

    var expiry = DateTime.UtcNow.Add(validity);
    var expiryTimestamp = new DateTimeOffset(expiry).ToUnixTimeSeconds();

    // Build URL with parameters
    var urlBuilder = new UriBuilder($"{_cdnBaseUrl}{path}");
    var query = HttpUtility.ParseQueryString(urlBuilder.Query);

    query["expires"] = expiryTimestamp.ToString();

    if (options.AllowedIp != null)
    {
        query["ip"] = options.AllowedIp;
    }

    // Generate signature
    var signatureData = $"{path}|{expiryTimestamp}|{options.AllowedIp}";
    var signature = ComputeSignature(signatureData);
    query["signature"] = signature;

    urlBuilder.Query = query.ToString();
    return urlBuilder.ToString();
}

private string ComputeSignature(string data)
{
    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(_signingKey));
    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
    return Convert.ToBase64String(hash)
        .Replace("+", "-")
        .Replace("/", "_")
        .TrimEnd('=');
}

}

public class SignedUrlOptions { public string? AllowedIp { get; set; } public string? AllowedCountry { get; set; } public int? MaxDownloads { get; set; } }

Signed URL Validation

public class SignedUrlValidationMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) { if (RequiresSignedUrl(context.Request.Path)) { var query = context.Request.Query;

        // Check expiry
        if (!long.TryParse(query["expires"], out var expiry) ||
            DateTimeOffset.UtcNow.ToUnixTimeSeconds() > expiry)
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync("URL expired");
            return;
        }

        // Validate signature
        var expectedSignature = ComputeSignature(
            context.Request.Path,
            expiry,
            query["ip"]);

        if (query["signature"] != expectedSignature)
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync("Invalid signature");
            return;
        }

        // Check IP restriction
        if (!string.IsNullOrEmpty(query["ip"]))
        {
            var clientIp = context.Connection.RemoteIpAddress?.ToString();
            if (clientIp != query["ip"])
            {
                context.Response.StatusCode = 403;
                await context.Response.WriteAsync("IP not allowed");
                return;
            }
        }
    }

    await next(context);
}

}

Origin Shielding

Shield Configuration

public class OriginShieldConfiguration { public bool Enabled { get; set; } = true; public string ShieldRegion { get; set; } = "us-east-1"; public int ShieldCacheTtl { get; set; } = 3600; // 1 hour public int MaxConnectionsToOrigin { get; set; } = 100; }

Benefits

Feature Without Shield With Shield

Origin requests From each edge From one region

Cache efficiency Per-edge Shared shield cache

Origin load High Reduced 90%+

Latency Variable Predictable

CDN URL Generation

URL Service

public class CdnUrlService { public string GetMediaUrl(MediaItem media, MediaUrlOptions? options = null) { options ??= new MediaUrlOptions();

    var path = $"/media/{media.StoragePath}";

    // Add transformation query params
    if (options.Width.HasValue || options.Height.HasValue)
    {
        var query = new List&#x3C;string>();

        if (options.Width.HasValue) query.Add($"w={options.Width}");
        if (options.Height.HasValue) query.Add($"h={options.Height}");
        if (options.Format.HasValue) query.Add($"format={options.Format}");
        if (options.Quality.HasValue) query.Add($"q={options.Quality}");

        path += "?" + string.Join("&#x26;", query);
    }

    // Generate signed URL if private
    if (media.IsPrivate || options.RequireSignature)
    {
        return _signedUrlService.GenerateSignedUrl(
            path,
            options.UrlValidity ?? TimeSpan.FromHours(1));
    }

    return $"{_cdnBaseUrl}{path}";
}

}

public class MediaUrlOptions { public int? Width { get; set; } public int? Height { get; set; } public ImageFormat? Format { get; set; } public int? Quality { get; set; } public bool RequireSignature { get; set; } public TimeSpan? UrlValidity { get; set; } }

Performance Monitoring

CDN Metrics

public class CdnMetrics { public long TotalRequests { get; set; } public long CacheHits { get; set; } public long CacheMisses { get; set; } public double CacheHitRatio => (double)CacheHits / TotalRequests; public long BandwidthBytes { get; set; } public double AverageLatencyMs { get; set; } public Dictionary<string, long> RequestsByRegion { get; set; } = new(); public Dictionary<int, long> StatusCodeCounts { get; set; } = new(); }

Related Skills

  • media-asset-management

  • Media storage and organization

  • image-optimization

  • Image processing before CDN

  • headless-api-design

  • Media API endpoints

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

design-thinking

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

plantuml-syntax

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

system-prompt-engineering

No summary provided by upstream source.

Repository SourceNeeds Review