Complete Guide: Configure Private S3 Bucket with CloudFront and Cloudflare
Overview
This guide walks through setting up a private S3 bucket with CloudFront as the content delivery layer and Cloudflare as the proxy/caching layer. This architecture provides security, performance, and cost optimization.
Phase 1: AWS S3 Configuration
Step 1.1: Create S3 Bucket
-
Log in to AWS Management Console
-
Navigate to S3 > Create bucket
-
Configure bucket settings:
· Bucket name: your-assets-bucket (choose a globally unique name)
· AWS Region: Select nearest region (e.g., us-east-1)
· Block Public Access: ✅ Keep all settings checked
· Block public access through ACLs
· Block public access through bucket policies
· Bucket Versioning: Disabled (unless needed)
· Tags: Optional
· Default Encryption: Enable SSE-S3 (recommended)
-
Click Create bucket
Step 1.2: Upload Files
-
Navigate to your new bucket
-
Click Upload > Add files
-
Upload your static assets (images, CSS, JS, etc.)
-
Set Permissions for each file (keep private)
-
Click Upload
Phase 2: AWS CloudFront Configuration
Step 2.1: Create CloudFront Key Pair (for Signed URLs/Cookies - Optional)
Only required if you need signed URLs/cookies
-
Navigate to IAM > Security credentials
-
Scroll to CloudFront key pairs
-
Click Create New Key Pair
-
Download the private key (.pem file) - Keep this secure
-
Note the Key Pair ID
Step 2.2: Create CloudFront Distribution
-
Navigate to CloudFront > Distributions
-
Click Create distribution
-
Configure Origin settings:
Origin domain: Select your S3 bucket
· It should appear as: your-assets-bucket.s3.us-east-1.amazonaws.com
Origin path: Leave blank
Name: your-assets-bucket-origin
Origin access: Origin access control settings (recommended)
· Click Create control setting
· Origin access control: Create new setting
· Name: s3-oac-access
· Description: Access from CloudFront to S3
· Signing behavior: Always
· Default settings: Leave as is
· Click Create
-
Configure Default cache behavior:
Cache policy: CachingOptimized (or create custom)
· If custom, set:
· Min TTL: 86400 (1 day)
· Default TTL: 604800 (7 days)
· Max TTL: 31536000 (1 year)
Origin request policy: CORS-S3Origin (if using CORS)
Response headers policy:
· Select SecurityHeadersPolicy or create custom · Recommended headers:
Strict-Transport-Security: max-age=31536000; includeSubDomains X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block Referrer-Policy: strict-origin-when-cross-originViewer protocol policy: Redirect HTTP to HTTPS Allowed HTTP methods: GET, HEAD, OPTIONS Cache key and origin requests: Cache policy and origin request policy
-
Configure Settings:
Price class: Use Only North America and Europe (or choose based on needs)
Alternate domain name (CNAME): assets.yourdomain.com
· Note: You'll configure SSL certificate later
Custom SSL certificate:
· Click Request certificate
· Follow ACM wizard for *.yourdomain.com
· Or use existing certificate
Default root object: Leave blank (unless serving SPA)
Logging: Enable if needed
WAF: Enable AWS WAF if needed
-
Click Create distribution
Step 2.3: Update S3 Bucket Policy for CloudFront Access
-
After distribution creation, CloudFront will show a Copy Policy button
-
Click Copy Policy
-
Navigate to your S3 bucket
-
Go to Permissions > Bucket Policy
-
Paste and save the policy:
{
"Version": "2012-10-17",
"Statement": {
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-assets-bucket/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/ABCDEFGHIJKLMN"
}
}
}
}Phase 3: Cloudflare Configuration
Step 3.1: DNS Configuration
-
Log in to Cloudflare Dashboard
-
Select your domain
-
Navigate to DNS > Records
-
Add CNAME record: · Type: CNAME · Name: assets (or subdomain of choice) · Target: abc123def456.cloudfront.net (your CloudFront domain) · Proxy status: ✅ Proxied (orange cloud) · TTL: Auto
-
Click Save
Step 3.2: SSL/TLS Configuration
-
Navigate to SSL/TLS > Overview
-
Set encryption mode: Full (strict)
-
Navigate to SSL/TLS > Edge Certificates
-
Enable:
· ✅ Always Use HTTPS
· ✅ Automatic HTTPS Rewrites
· ✅ Minimum TLS Version: TLS 1.2
-
Configure Authenticated Origin Pulls (Optional but recommended):
· Navigate to SSL/TLS > Origin Server
· Click Create Certificate
· Select: Generate private key and CSR with Cloudflare
· Hostnames: assets.yourdomain.com
· Certificate Validity: 15 years
· Click Create
· Download certificate and key
· Configure on CloudFront (upload as custom SSL)
Step 3.3: Cache Configuration
-
Navigate to Caching > Configuration
-
Set Caching Level: Standard
-
Set Browser Cache TTL: 1 month
-
Navigate to Caching > Configuration > Cache Rules
-
Create new Cache Rule: · Rule name: S3 Assets Cache
· When incoming requests match:
· Field: Hostname
· Operator: equals
· Value: assets.yourdomain.com
· Then set cache configuration:
· Cache Eligibility: Eligible for cache
· Edge TTL: 1 month
· Browser TTL: 1 month
· Cache Key: Custom
· Include: Host, Path, Query string · Query string: Include all· Click Deploy
Step 3.4: Security Configuration
-
Navigate to Security > WAF
-
Create new rule: · Rule name: Block Direct CloudFront Access
· When request matches:
· Field: Host
· Operator: does not equal
· Value: assets.yourdomain.com
· Then: Block
-
Navigate to Security > Settings
· Security Level: Medium
· Challenge Passage: 30 minutes
· Browser Integrity Check: On
Step 3.5: Performance Configuration
-
Navigate to Speed > Optimization
-
Configure:
· ✅ Auto Minify (JS, CSS, HTML)
· ✅ Brotli compression
· ✅ Rocket Loader: Off
· ✅ Mirage: Off
· ✅ Polish: Lossless/Lossy (for images)
Phase 4: Testing & Validation
Step 4.1: Test Direct Access
- Try accessing S3 directly:
· Should return 403 Access Deniedhttps://your-assets-bucket.s3.amazonaws.com/image.jpg - Try accessing CloudFront directly:
· Should return 200 OK (or 403 if using signed URLs)https://abc123def456.cloudfront.net/image.jpg
Step 4.2: Test Through Cloudflare
- Access through Cloudflare:
· Should return 200 OKhttps://assets.yourdomain.com/image.jpg - Check headers:
· Verify headers include: · cf-cache-status: HIT · x-amz-cf-pop (CloudFront POP) · Security headers you configured
curl -I https://assets.yourdomain.com/image.jpg
Step 4.3: Cache Validation
- Check Cloudflare cache status: · First request: cf-cache-status: MISS · Subsequent requests: cf-cache-status: HIT
- Purge cache if needed: · Cloudflare: Caching > Configuration > Purge Cache · CloudFront: Invalidations > Create invalidation