cdn-setup – Writing & Content skill for AI agents
Configure CDNs for content delivery. Set up CloudFront, Cloudflare, and Fastly. Use when optimizing global content delivery.
Install the cdn-setup skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/cdn-setup-d9bc3.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /cdn-setup – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/cdn-setup-d9bc3.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $cdn-setup – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/cdn-setup-d9bc3.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /cdn-setup – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/cdn-setup-d9bc3.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /cdn-setup – then describe the task you want done.
SKILL.md content
CDN Setup
Configure content delivery networks for fast, reliable global asset delivery with proper caching, invalidation, and security.
When to Use
- Serving static assets (JS, CSS, images, fonts) globally with low latency.
- Offloading traffic from origin servers to reduce compute costs.
- Adding TLS termination and DDoS protection at the edge.
- Implementing geo-based routing or content restrictions.
- Accelerating API responses with edge caching.
Examples use placeholders and create billable resources. Confirm the zone/distribution/account and rollback before provisioning, changing DNS/cache rules or purging. Cache only intentionally public responses; bypass authenticated, tenant-specific and sensitive routes even when paths resemble static assets. Do not strip query parameters that carry authorization or content identity.
Prerequisites
- Domain with DNS management access.
- Origin server or S3/R2 bucket with content to serve.
- AWS CLI configured (for CloudFront).
- Cloudflare account with zone configured (for Cloudflare CDN).
- Terraform 1.5+ (for infrastructure-as-code examples).
AWS CloudFront
Create a Distribution via CLI
# Create an S3 origin distribution with OAC (Origin Access Control)
aws cloudfront create-distribution --distribution-config '{
"CallerReference": "my-site-'$(date +%s)'",
"Comment": "Production site CDN",
"Enabled": true,
"Origins": {
"Quantity": 1,
"Items": [{
"Id": "s3-origin",
"DomainName": "my-bucket.s3.us-east-1.amazonaws.com",
"OriginPath": "",
"S3OriginConfig": {
"OriginAccessIdentity": ""
},
"OriginAccessControlId": "E2QWRUHAPOMQZL"
}]
},
"DefaultCacheBehavior": {
"TargetOriginId": "s3-origin",
"ViewerProtocolPolicy": "redirect-to-https",
"AllowedMethods": {
"Quantity": 2,
"Items": ["GET", "HEAD"]
},
"CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6",
"Compress": true
},
"DefaultRootObject": "index.html",
"PriceClass": "PriceClass_100",
"ViewerCertificate": {
"ACMCertificateArn": "arn:aws:acm:us-east-1:123456789:certificate/abc-123",
"SSLSupportMethod": "sni-only",
"MinimumProtocolVersion": "TLSv1.2_2021"
},
"Aliases": {
"Quantity": 1,
"Items": ["www.example.com"]
},
"CustomErrorResponses": {
"Quantity": 1,
"Items": [{
"ErrorCode": 404,
"ResponseCode": "200",
"ResponsePagePath": "/index.html",
"ErrorCachingMinTTL": 10
}]
}
}'Cache Invalidation
# Invalidate specific paths
aws cloudfront create-invalidation \
--distribution-id E1A2B3C4D5E6F7 \
--paths "/index.html" "/css/*" "/js/*"
# Invalidate everything (costs apply per path)
aws cloudfront create-invalidation \
--distribution-id E1A2B3C4D5E6F7 \
--paths "/*"
# Check invalidation status
aws cloudfront get-invalidation \
--distribution-id E1A2B3C4D5E6F7 \
--id I1A2B3C4D5E6F7
# List recent invalidations
aws cloudfront list-invalidations --distribution-id E1A2B3C4D5E6F7CloudFront Functions (Lightweight Edge Logic)
// URL rewrite function — add index.html to directory requests
function handler(event) {
var request = event.request;
var uri = request.uri;
if (uri.endsWith('/')) {
request.uri += 'index.html';
} else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}CloudFront with Terraform
This is a partial configuration: supply the referenced bucket, certificate and API origin, and a least-privilege S3 bucket policy granting this distribution access through OAC. OAC creation alone does not grant bucket reads. Review SPA fallbacks: private S3 origins may return 403 for missing objects; never turn genuine authorization failures into successful HTML responses.
# cloudfront.tf
resource "aws_cloudfront_distribution" "site" {
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
aliases = ["www.example.com"]
price_class = "PriceClass_100"
origin {
domain_name = aws_s3_bucket.site.bucket_regional_domain_name
origin_id = "s3-origin"
origin_access_control_id = aws_cloudfront_origin_access_control.oac.id
}
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "s3-origin"
cache_policy_id = "658327ea-f89d-4fab-a63d-7e88639e58f6" # CachingOptimized
origin_request_policy_id = "88a5eaf4-2fd4-4709-b370-b4c650ea3fcf" # CORS-S3Origin
viewer_protocol_policy = "redirect-to-https"
compress = true
}
# SPA fallback
custom_error_response {
error_code = 404
response_code = 200
response_page_path = "/index.html"
}
# API pass-through (no caching): add a real origin block with
# origin_id = "api-origin" and verified custom_origin_config first.
ordered_cache_behavior {
path_pattern = "/api/*"
allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "api-origin"
cache_policy_id = "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" # CachingDisabled
origin_request_policy_id = "b689b0a8-53d0-40ab-baf2-68738e2966ac" # AllViewerExceptHostHeader
viewer_protocol_policy = "https-only"
}
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.cert.arn
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2021"
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
}
resource "aws_cloudfront_origin_access_control" "oac" {
name = "s3-oac"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}Cloudflare CDN
Zone Setup
# Add a zone
curl -X POST "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"example.com","jump_start":true}'
# Get zone ID
ZONE_ID=$(curl -s "https://api.cloudflare.com/client/v4/zones?name=example.com" \
-H "Authorization: Bearer $CF_API_TOKEN" | jq -r '.result[0].id')Cache Rules (Replacing Page Rules)
# Create a cache rule for static assets
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/phases/http_request_cache_settings/entrypoint" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rules": [
{
"expression": "(http.request.uri.path.extension in {\"css\" \"js\" \"png\" \"jpg\" \"woff2\" \"svg\"})",
"action": "set_cache_settings",
"action_parameters": {
"cache": true,
"browser_ttl": { "mode": "override_origin", "default": 2592000 },
"edge_ttl": { "mode": "override_origin", "default": 86400 }
},
"description": "Cache static assets aggressively"
}
]
}'Purge Cache
# Purge everything
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"purge_everything":true}'
# Purge specific URLs
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"files":["https://example.com/style.css","https://example.com/app.js"]}'
# Purge by prefix
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"prefixes":["https://example.com/images/"]}'Cache Headers on Origin
nginx Cache Headers
# Put the fingerprinted regex first: nginx uses the first matching regex.
location ~* \.[a-f0-9]{8,}\.(js|css)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* \.(js|css)$ {
add_header Cache-Control "public, max-age=604800, must-revalidate";
}
# Images and fonts
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|woff2|ttf)$ {
expires 30d;
add_header Cache-Control "public, must-revalidate";
}
# HTML — always revalidate
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, must-revalidate";
}
# API responses — no caching
location /api/ {
add_header Cache-Control "no-store, no-cache";
add_header Vary "Authorization, Accept";
}Cache-Control Cheat Sheet
| Header | Meaning |
|--------|---------|
| public, max-age=31536000, immutable | Cache for 1 year, never revalidate (hashed assets) |
| public, max-age=86400, must-revalidate | Cache 1 day, check freshness after |
| private, max-age=600 | Browser cache only, 10 min (user-specific content) |
| `n
… (full content is in the download package)
Related skills
- citation-management – Manage citations systematically throughout the research and writing process.
- claimable-postgres – Provision instant temporary Postgres databases via Claimable Postgres by Neon (neon.new)…
- incident-commander – Comprehensive incident response framework from detection through resolution and…
- okta-attack – Okta-as-IdP red-team attack chain — tenant discovery, user enumeration (multiple…
- internal-narrative – Build and maintain one coherent company story across all audiences — employees…
- pydicom – Reads, inspects, writes, transforms, and preflights local DICOM datasets and pixel data…
- cloudflare-zero-trust – Protect internal apps with Cloudflare Access, device posture, and Zero Trust policies.
- cloudformation-best-practices – CloudFormation template optimization, nested stacks, drift detection, and…