AWS Favicon Complete Guide
Master favicon deployment on AWS: S3 static hosting, CloudFront CDN distribution, Lambda@Edge dynamic favicons, Route 53 DNS, and AWS best practices.
AWS Favicon Architecture
S3 Bucket
Store favicon files
CloudFront
Global CDN delivery
Route 53
DNS management
Lambda@Edge
Edge processing
S3 Static Website Hosting
Step 1: Create S3 Bucket
Create Bucket via AWS Console
- Open S3 Console:
https://console.aws.amazon.com/s3/ - Click "Create bucket"
- Bucket name:
your-domain-com - Region: Choose closest to users (e.g.,
us-east-1) - Uncheck "Block all public access" (for public website)
- Acknowledge public access warning
- Click "Create bucket"
Enable Static Website Hosting
- Select your bucket ? Properties tab
- Scroll to "Static website hosting" ? Edit
- Enable:
Enable - Index document:
index.html - Error document:
404.html(optional) - Save changes
- Note the endpoint:
http://your-bucket.s3-website-us-east-1.amazonaws.com
Upload Favicon Files
# Via AWS CLI
aws s3 cp favicon.ico s3://your-bucket/ --content-type "image/x-icon"
aws s3 cp favicon-16x16.png s3://your-bucket/ --content-type "image/png"
aws s3 cp favicon-32x32.png s3://your-bucket/ --content-type "image/png"
aws s3 cp favicon-96x96.png s3://your-bucket/ --content-type "image/png"
aws s3 cp favicon-512x512.png s3://your-bucket/ --content-type "image/png"
aws s3 cp apple-touch-icon.png s3://your-bucket/ --content-type "image/png"
aws s3 cp site.webmanifest s3://your-bucket/ --content-type "application/manifest+json"
# Set cache control headers
aws s3 cp favicon.ico s3://your-bucket/ \
--content-type "image/x-icon" \
--cache-control "public, max-age=31536000, immutable" \
--metadata-directive REPLACEBucket Policy (Public Read)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket/*"
}
]
}Test: Access
http://your-bucket.s3-website-us-east-1.amazonaws.com/favicon.icoCloudFront CDN Configuration
Step 2: Create CloudFront Distribution
Create Distribution
- Open CloudFront Console:
https://console.aws.amazon.com/cloudfront/ - Click "Create distribution"
- Origin domain: Select your S3 bucket website endpoint
- Origin path: Leave empty (or
/) - Viewer protocol policy: Redirect HTTP to HTTPS
- Allowed HTTP methods: GET, HEAD
- Cache policy: CachingOptimized (recommended)
- Click "Create distribution"
Custom Cache Behavior for Favicons
After distribution is created ? Behaviors tab ? Create behavior:
- Path pattern:
favicon*or*.ico - Cache policy: Create custom or use CachingOptimized
- TTL: Min: 31536000, Max: 31536000, Default: 31536000 (1 year)
- Compress objects: Yes (for SVG)
Custom Cache Policy (Advanced)
Caching ? Cache policies ? Create cache policy:
Name: FaviconLongCache
Description: 1 year cache for favicon files
TTL Settings:
Minimum TTL: 31536000 seconds (1 year)
Maximum TTL: 31536000 seconds
Default TTL: 31536000 seconds
Cache Key Settings:
Query strings: None
Headers: None
Cookies: None
Compression: EnabledHTTPS with ACM Certificate
- Request certificate in AWS Certificate Manager (ACM)
- Region:
us-east-1(required for CloudFront) - Domain:
yourdomain.comand*.yourdomain.com - Validate via DNS (add CNAME records)
- In CloudFront distribution ? General ? Edit
- Alternate domain names (CNAMEs):
yourdomain.com - Custom SSL certificate: Select your ACM certificate
Distribution URL:
https://d1234abcd.cloudfront.net (takes 10-20 minutes to deploy)
Route 53 DNS Configuration
Step 3: Connect Domain to CloudFront
Create A Record (Alias)
- Open Route 53 Console ? Hosted zones
- Select your domain
- Click "Create record"
- Record name: Leave blank (for root) or
www - Record type: A - IPv4 address
- Alias: Yes
- Route traffic to: Alias to CloudFront distribution
- Choose distribution: Select your CloudFront distribution
- Click "Create records"
Example DNS Configuration
| Name | Type | Alias | Value |
|---|---|---|---|
| @ | A | Yes | d1234abcd.cloudfront.net |
| www | A | Yes | d1234abcd.cloudfront.net |
Verification: Wait 5-60 minutes for DNS propagation. Test with
nslookup yourdomain.comLambda@Edge Dynamic Favicons
Advanced: Edge Functions
Use Cases
- Serve different favicon per region/country
- A/B testing different favicons
- Custom cache headers per client
- Redirect old favicon paths
Example: Origin Request Function
'use strict';
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const uri = request.uri;
// Redirect /favicon.ico to /favicons/default.ico
if (uri === '/favicon.ico') {
request.uri = '/favicons/default.ico';
}
// Serve favicon based on country
const headers = request.headers;
const country = headers['cloudfront-viewer-country']
? headers['cloudfront-viewer-country'][0].value
: 'US';
if (uri.startsWith('/favicon')) {
// Different favicon per country
const countryFavicons = {
'US': '/favicons/us-favicon.ico',
'GB': '/favicons/uk-favicon.ico',
'DE': '/favicons/de-favicon.ico'
};
request.uri = countryFavicons[country] || '/favicon.ico';
}
callback(null, request);
};Deploy Lambda@Edge Function
- Create Lambda function in
us-east-1region (required) - Runtime: Node.js 18.x
- Paste code above
- Deploy function
- Publish new version (Actions ? Publish new version)
- Copy ARN with version number
- In CloudFront ? Behaviors ? Edit
- Function associations ? Origin request ? Paste Lambda ARN
- Save and wait for deployment
Note: Lambda@Edge runs in all CloudFront edge locations. Test thoroughly before deploying.
CloudFront Cache Invalidation
Update Cached Favicons
Method 1: AWS Console
- Open CloudFront Console
- Select your distribution
- Invalidations tab ? Create invalidation
- Object paths:
/favicon.ico
/favicon-*.png
/apple-touch-icon.png - Click "Create invalidation"
- Wait 5-15 minutes for completion
Method 2: AWS CLI
# Invalidate specific files
aws cloudfront create-invalidation \
--distribution-id E1234ABCD5678 \
--paths "/favicon.ico" "/favicon-16x16.png" "/favicon-32x32.png"
# Invalidate all favicon files
aws cloudfront create-invalidation \
--distribution-id E1234ABCD5678 \
--paths "/favicon*" "/*favicon*"
# Check invalidation status
aws cloudfront get-invalidation \
--distribution-id E1234ABCD5678 \
--id I2J4K6L8M0N2Method 3: Versioned URLs (Recommended)
Instead of invalidation, use versioned filenames:
- Upload new file:
favicon-v2.ico - Update HTML:
<link rel="icon" href="/favicon-v2.ico"> - No invalidation needed (new URL)
- Free (invalidations cost $0.005 per path after first 1000/month)
Cost Tip: First 1,000 invalidation paths per month are free. After that, $0.005 per path.
Infrastructure as Code (Terraform)
Automate AWS Setup
Complete Terraform Configuration
# S3 Bucket
resource "aws_s3_bucket" "website" {
bucket = "your-domain-com"
}
resource "aws_s3_bucket_website_configuration" "website" {
bucket = aws_s3_bucket.website.id
index_document {
suffix = "index.html"
}
}
resource "aws_s3_bucket_public_access_block" "website" {
bucket = aws_s3_bucket.website.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
resource "aws_s3_bucket_policy" "website" {
bucket = aws_s3_bucket.website.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "PublicReadGetObject"
Effect = "Allow"
Principal = "*"
Action = "s3:GetObject"
Resource = "${'$'}{aws_s3_bucket.website.arn}/*"
}
]
})
}
# CloudFront Distribution
resource "aws_cloudfront_distribution" "website" {
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
aliases = ["yourdomain.com", "www.yourdomain.com"]
origin {
domain_name = aws_s3_bucket_website_configuration.website.website_endpoint
origin_id = "S3-Website"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "http-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "S3-Website"
viewer_protocol_policy = "redirect-to-https"
compress = true
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
min_ttl = 0
default_ttl = 86400
max_ttl = 31536000
}
# Custom cache for favicons
ordered_cache_behavior {
path_pattern = "favicon*"
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "S3-Website"
viewer_protocol_policy = "redirect-to-https"
compress = true
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
min_ttl = 31536000
default_ttl = 31536000
max_ttl = 31536000
}
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"
}
}
}
# ACM Certificate
resource "aws_acm_certificate" "cert" {
provider = aws.us-east-1
domain_name = "yourdomain.com"
validation_method = "DNS"
subject_alternative_names = ["www.yourdomain.com"]
}
# Route 53 Records
resource "aws_route53_record" "website" {
zone_id = var.hosted_zone_id
name = "yourdomain.com"
type = "A"
alias {
name = aws_cloudfront_distribution.website.domain_name
zone_id = aws_cloudfront_distribution.website.hosted_zone_id
evaluate_target_health = false
}
}AWS Favicon Best Practices
? Recommendations
- Use CloudFront for global delivery
- Set cache TTL to 1 year for favicons
- Enable HTTPS with ACM certificates (free)
- Use S3 bucket versioning for rollback
- Set proper
Content-Typeheaders - Use versioned URLs instead of invalidations
- Enable CloudFront compression (for SVG)
- Monitor with CloudWatch metrics
- Use Terraform/CloudFormation for IaC
? Common Mistakes
- Forgetting to make S3 bucket public
- Not setting
Cache-Controlheaders - Using S3 directly (bypass CloudFront)
- ACM certificate in wrong region (must be us-east-1)
- Not compressing SVG files
- Excessive CloudFront invalidations (costs)
- Missing Route 53 alias records
- Not enabling HTTPS
- Ignoring CloudFront cache statistics
Monitoring & Costs
AWS Metrics & Pricing
CloudWatch Metrics
- Requests: Total favicon requests
- BytesDownloaded: Data transfer
- CacheHitRate: Percentage served from cache
- 4xxErrorRate / 5xxErrorRate: Errors
Estimated Monthly Costs (Free Tier)
| Service | Free Tier | After Free Tier |
|---|---|---|
| S3 Storage | 5 GB (12 months) | $0.023/GB/month |
| S3 Requests | 20,000 GET | $0.0004 per 1000 |
| CloudFront Data | 1 TB (12 months) | $0.085/GB |
| CloudFront Requests | 10M (12 months) | $0.0075 per 10,000 |
| Route 53 | $0.50/hosted zone | $0.50/month |
Typical Cost: $1-5/month for small-medium website with favicons on AWS Free Tier. After free tier: $5-20/month depending on traffic.
Generate AWS-Ready Favicons
Create favicon packages optimized for Amazon Web Services deployment
Generate Favicons