From content-management-system
Guides CDN configuration for media delivery, cache invalidation, signed URLs, edge caching, origin shielding, and secure access in headless CMS using Azure Front Door and CloudFront.
npx claudepluginhub melodic-software/claude-code-plugins --plugin content-management-systemThis skill is limited to using the following tools:
Guidance for configuring CDN delivery, cache management, and secure media access for headless CMS architectures.
Guides designing CDN architectures, caching strategies, and global content distribution. Covers cache hierarchies, origin shielding, invalidation, and edge optimization.
Configures AWS CloudFront distributions for global content delivery with caching, security headers, WAF integration, and origins. Use for low-latency static sites, APIs, media, and DDoS protection.
Designs and optimizes CDN architectures: tiered caching, origin shielding, edge compute, cache hit ratio optimization, multi-CDN strategies, geographic routing. For high TTFB, origin overload, low cache hits, global apps.
Share bugs, ideas, or general feedback.
Guidance for configuring CDN delivery, cache management, and secure media access for headless CMS architectures.
┌─────────────────────────────────────────────────────────────┐
│ 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 │ │
│ └───────────────┘ └────────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────┘
// 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"
}
}
}
}
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
}
};
}
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
}
}
};
}
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";
}
}
| 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 |
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<string> { path },
Quantity = 1
}
}
};
await _client.CreateInvalidationAsync(request);
}
}
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}");
}
}
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; }
}
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);
}
}
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;
}
| 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 |
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<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("&", 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; }
}
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();
}
media-asset-management - Media storage and organizationimage-optimization - Image processing before CDNheadless-api-design - Media API endpoints