AWS S3 — Object Storage, Static Hosting, and CDN Guide
Advertisement
Introduction
Why This Matters
Amazon S3 (Simple Storage Service) provides virtually unlimited, durable object storage at low cost. It stores everything from application assets and backups to data lake inputs and static websites. Paired with CloudFront, S3 delivers content globally with millisecond latency. Understanding S3 correctly prevents data exposure incidents, reduces egress costs, and ensures compliance with data retention policies.
Bucket Operations
# Create bucket (bucket names are globally unique)
aws s3api create-bucket \
--bucket my-app-assets-20240101 \
--region us-east-1
# Block all public access (default — recommended)
aws s3api put-public-access-block \
--bucket my-app-assets-20240101 \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
# Upload a single file
aws s3 cp ./dist/index.html s3://my-bucket/index.html
# Sync local directory to S3 (only changed files)
aws s3 sync ./dist/ s3://my-bucket/ \
--delete \
--cache-control "max-age=86400"
# Download file
aws s3 cp s3://my-bucket/backup.tar.gz ./
# List objects with size
aws s3 ls s3://my-bucket --recursive --human-readable --summarize
# Delete object
aws s3 rm s3://my-bucket/old-file.txt
# Delete all objects in bucket
aws s3 rm s3://my-bucket --recursiveBucket Policies
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE"
}
}
}
]
}# Apply bucket policy
aws s3api put-bucket-policy \
--bucket my-bucket \
--policy file://bucket-policy.jsonStatic Website Hosting
# Enable static website hosting
aws s3 website s3://my-bucket \
--index-document index.html \
--error-document 404.html
# Upload website files with correct content types
aws s3 sync ./dist/ s3://my-bucket/ \
--exclude "*.map" \
--cache-control "public, max-age=31536000, immutable"
# Override cache for index.html
aws s3 cp ./dist/index.html s3://my-bucket/index.html \
--cache-control "no-cache, no-store, must-revalidate"
# Website URL format
# http://my-bucket.s3-website-us-east-1.amazonaws.comCloudFront CDN Integration
# Create CloudFront distribution with S3 origin
aws cloudfront create-distribution \
--distribution-config file://cloudfront-config.json{
"Comment": "My app CDN",
"DefaultCacheBehavior": {
"ViewerProtocolPolicy": "redirect-to-https",
"Compress": true,
"CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6",
"TargetOriginId": "S3Origin"
},
"Origins": {
"Quantity": 1,
"Items": [{
"Id": "S3Origin",
"DomainName": "my-bucket.s3.us-east-1.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": ""
},
"OriginAccessControlId": "ABCDEF123456"
}]
},
"PriceClass": "PriceClass_100",
"Enabled": true
}Versioning and Lifecycle Rules
# Enable versioning
aws s3api put-bucket-versioning \
--bucket my-bucket \
--versioning-configuration Status=Enabled
# List object versions
aws s3api list-object-versions --bucket my-bucket --prefix my-file.txt
# Restore a previous version
aws s3api copy-object \
--bucket my-bucket \
--copy-source my-bucket/my-file.txt?versionId=abc123 \
--key my-file.txt{
"Rules": [
{
"ID": "archive-old-logs",
"Status": "Enabled",
"Filter": {"Prefix": "logs/"},
"Transitions": [
{"Days": 30, "StorageClass": "STANDARD_IA"},
{"Days": 90, "StorageClass": "GLACIER"}
],
"Expiration": {"Days": 365}
},
{
"ID": "delete-old-versions",
"Status": "Enabled",
"NoncurrentVersionExpiration": {"NoncurrentDays": 30}
}
]
}Presigned URLs
# Generate presigned URL for temporary access (15 minutes)
aws s3 presign s3://my-bucket/private-file.pdf \
--expires-in 900
# In Python
python3 -c "
import boto3
s3 = boto3.client('s3')
url = s3.generate_presigned_url(
'get_object',
Params={'Bucket': 'my-bucket', 'Key': 'private-file.pdf'},
ExpiresIn=900
)
print(url)
"Common Mistakes
- Setting bucket ACLs to public — use bucket policies and CloudFront OAC instead for controlled access
- Not enabling versioning on buckets containing important data — accidental deletions are unrecoverable without versioning
- Using S3 Transfer Acceleration for small files or same-region transfers — adds cost without meaningful speed improvement
- Not setting lifecycle rules on log buckets — S3 costs accumulate quickly for high-volume log storage
- Forgetting to set
Cache-Controlheaders on static assets — browsers re-fetch on every page load
Best Practices
- Block all public access at the account level unless you specifically need public buckets
- Use CloudFront with Origin Access Control (OAC) instead of public buckets for serving web assets
- Enable S3 server access logging or AWS CloudTrail data events for audit trails
- Use S3 Intelligent-Tiering for data with unknown access patterns — it automatically moves objects to cheaper tiers
- Encrypt buckets with SSE-S3 or SSE-KMS; use KMS for compliance requirements
- Separate production and staging data into separate buckets with separate IAM policies
Key Takeaways
- S3 provides 99.999999999% (11 nines) durability by replicating objects across multiple AZs within a region
- Block Public Access settings should be enabled at both the account and bucket level as the default posture
- Static website hosting via S3 works for SPAs but CloudFront is required for HTTPS and custom domains
- Versioning protects against accidental deletion and allows point-in-time object recovery
- Lifecycle rules automate transitioning objects to cheaper storage classes (Standard-IA, Glacier) and expiration
- Presigned URLs grant temporary, time-limited access to private objects without changing bucket permissions
- Storage classes (Standard, Standard-IA, Glacier, Glacier Deep Archive) offer significant cost differences for infrequently accessed data
- CloudFront with OAC is the recommended pattern for serving S3 content securely without making buckets public
Advertisement
Related reading
AWS for Developers 2026 — EC2, S3, Lambda, RDS, and CloudFront Guide6 min readTerraform Infrastructure Guide 2026 — Infrastructure as Code for AWS, GCP, and Azure6 min readKubernetes Guide 2026 — Deploy, Scale, and Manage Containers in Production5 min readServerless Computing Guide 2026 — AWS Lambda, Cloudflare Workers, and Edge Functions7 min readAWS Cloud Cost Optimization 2026 — Cut Your Bill by 60% Without Killing Performance7 min readDevOps Engineer Roadmap 2026 — From Zero to $150K+ in 18 Months9 min read