Introduction

Have you ever found your website slowing down because of all the images and assets it needs to load? Or maybe you’ve struggled with managing these files as your site grows. Here’s the thing: storing and serving images directly from your web server might seem convenient at first, but it can quickly turn into a bottleneck.

That’s where AWS comes in. With services like S3 for storage and CloudFront as a powerful CDN, you can easily manage, optimize, and deliver images and assets to your users lightning-fast, no matter where they are in the world.

In this guide, I’ll walk you through why it’s a bad idea to keep images on your web app server, why separating services is a game changer, and how AWS tools can make your life so much easier. Let’s dive in!

Why Storing Images on Your Web Server Is a Bad Idea

Increased Server Load

When your web server is responsible for both running your app and serving images, it can quickly get overwhelmed. Every image request piles on extra work, slowing everything down. If your site gets a lot of traffic, the server may struggle to keep up, causing delays or even crashes. Imagine trying to carry all your groceries and run at the same time—it’s just not efficient!

Limited Scalability

As your site grows, so will the number of images and users. A single web server can only handle so much before you hit a wall. Scaling up often means spending more money on bigger servers or dealing with the hassle of migrating everything. With cloud storage like AWS S3, you don’t have to worry about running out of space—it grows with you, no sweat.

Risk of Performance Bottlenecks

Large image files can slow your site to a crawl, especially if you’re serving them from the same server that handles your app’s functionality. When one part of your site is slow, it can hold up everything else, leaving users frustrated with long loading times. Think of it like a traffic jam on a one-lane road—everything gets backed up.

Security Concerns

Serving images from your web server can expose you to unnecessary risks. Hackers could exploit vulnerabilities to access sensitive information, or other sites might steal your bandwidth by hotlinking your images. Without proper safeguards, you might accidentally reveal server file paths, which is like leaving your front door wide open.

Why Should We Use a CDN?

If you’ve ever been annoyed by a slow-loading website, you’ll understand why a CDN (Content Delivery Network) is a game-changer. A CDN is like having a network of mini warehouses spread across the globe, each storing copies of your site’s images and assets. Instead of every user having to wait for content to travel all the way from your main server, a CDN delivers it from the nearest warehouse, making everything faster and smoother.

CDN speeds up content delivery by distributing data to global edge servers.
CDN speeds up content delivery by distributing data to global edge servers.

Here’s why using a CDN for image and asset delivery is a no-brainer:

Faster Load Times for Users Everywhere

Let’s say your main server is in New York, but someone in Tokyo visits your site. Without a CDN, their request has to travel halfway around the world, which takes time. With a CDN, a server near Tokyo delivers the content, cutting down the travel time and making your site load in a snap. Faster load times mean happier users, and happier users stick around longer.

Reduced Latency and Improved User Experience

Latency is that annoying delay between a user clicking something and the content actually showing up. The further away a user is from your server, the higher the latency. A CDN solves this by bringing your images and assets closer to the user, reducing delays and making everything feel instant. Whether someone’s browsing your site from their couch in London or a café in Sydney, they’ll enjoy the same seamless experience.

Offloading Traffic from Your Main Server

Think of your web server as a busy chef in a restaurant. Without a CDN, the chef has to handle everything: cooking, serving, and even delivering food to faraway customers. With a CDN, the chef (your server) can focus on cooking (running your app), while the CDN handles delivery (serving images and assets). This offloads a ton of traffic from your main server, preventing overloads and keeping your site running smoothly even during traffic spikes.

What Are S3 and CloudFront?

S3 (Simple Storage Service)

S3 is Amazon’s secure, scalable, and highly reliable cloud storage solution. It’s designed to store any kind of data, including images, videos, and other assets, making it an ideal choice for websites and applications. Whether you’re hosting a small personal blog or running a large-scale e-commerce platform, S3 can handle your storage needs effortlessly. Plus, it offers flexible storage tiers, so you only pay for what you use.

CloudFront

CloudFront is Amazon’s Content Delivery Network (CDN) service that ensures fast and secure content delivery. It works by caching your images and assets on edge servers located around the world, so users can access them quickly from the server closest to them. When combined with S3, CloudFront optimizes the delivery process by seamlessly fetching stored assets and serving them with minimal latency. Together, S3 and CloudFront provide a powerful, efficient, and scalable solution for managing and delivering website content.

Cost of Using S3 and CloudFront

One of the best things about AWS is that you only pay for what you use. Here’s a quick breakdown:

  • S3 Costs:
    • Storage Costs: You pay per GB of data stored, with different rates depending on the storage tier (e.g., Standard, Infrequent Access, Glacier).
    • Request Costs: Charges apply for PUT, GET, and other requests made to your bucket.
    • Data Transfer: Transferring data out of S3 to the internet incurs additional fees.
  • CloudFront Costs:
    • Data Transfer: You pay for the amount of data delivered to users through edge locations.
    • Requests: Charges apply for HTTP/HTTPS requests made to CloudFront.
    • Regional Pricing: Costs may vary depending on where your users are located.

You can reference Amazon S3 Pricing and Amazon CloudFront Pricing for detailed information.

Example: Cost of Using S3 and CloudFront

Let’s say you run a small e-commerce website and need to store and serve product images. Here’s a simplified cost breakdown:

Scenario Details

  • Storage: 100 GB of images stored in S3 (Standard Tier).
  • Requests: 50,000 GET requests and 10,000 PUT requests to S3 per month.
  • Data Transfer: 100 GB of data transferred out to CloudFront.
  • CloudFront Data Delivery: 100 GB of data delivered to end-users through the CDN.

S3 Costs

  1. Storage Costs:
  • 100 GB in S3 Standard Storage = $2.30 per month (approx. $0.023 per GB).
  1. Request Costs:
  • 50,000 GET requests = $0.04 (approx. $0.0004 per 1,000 requests).
  • 10,000 PUT requests = $0.05 (approx. $0.005 per 1,000 requests).
  1. Data Transfer Costs (to CloudFront):
  • 100 GB = $0 (data transfer from S3 to CloudFront is free).

Total S3 Cost: $2.39/month

CloudFront Costs

  1. Data Transfer Costs (from CloudFront to users):
  • 100 GB delivered to end-users = $8.50 (approx. $0.085 per GB for the first 10 TB).
  1. Request Costs:
  • 50,000 HTTP/HTTPS requests = $0.10 (approx. $0.002 per 1,000 requests).

Total CloudFront Cost: $8.60/month

Grand Total

Total Monthly Cost: $2.39 + $8.60 = $10.99

Setting Up AWS S3 and CloudFront for Image and Asset Hosting

This guide will walk you through configuring AWS S3 and CloudFront to serve images efficiently with a custom subdomain.

This setup ensures that:

  • Requests from your allowed domains (e.g., yoursite.com) can access the assets.
  • Requests with no Referer header (e.g., direct access to S3 URLs) are blocked.
  • Requests from unauthorized websites (hotlinking) are denied.
  1. Create an SSL Certificate in AWS Certificate Manager (ACM)

Since CloudFront requires a valid SSL certificate to use HTTPS with a custom domain, the first step is to generate an SSL certificate.

  • Go to AWS Certificate Manager (ACM).
  • Click Request a certificate.
  • Choose Request a public certificate.
  • Enter your subdomain (images.yoursite.com), and optionally add *.yoursite.com if you want a wildcard certificate.
  • Select DNS Validation (Recommended).
  • After submitting, AWS will provide CNAME records that you need to add in your DNS provider (e.g., Route 53, Cloudflare, GoDaddy).
  • Once the DNS record is validated, the certificate will be issued.
AWS Certificate Manager: Successfully Issued SSL Certificate for Subdomains
AWS Certificate Manager: Successfully Issued SSL Certificate for Subdomains
  1. Create a Subdomain for Serving Images

Now that the SSL certificate is ready, set up a subdomain (images.yoursite.com) to serve your images.

  • Go to your DNS provider (Route 53, Cloudflare, or another).
  • Create a CNAME record:
    • Record Name: images
    • Type: CNAME
    • Value: <your-cloudfront-distribution-id>.cloudfront.net
  1. Create a CloudFront Distribution

Now, set up CloudFront to serve images from S3.

  • Go to AWS CloudFront → Create Distribution.
  • Under Origin, configure:
    • Origin Domain Name: Select your S3 bucket.
    • Origin Access: Choose Legacy access identitiesCreate Origin Access Identity (OAI).
    • Bucket Policy: Select I will update the bucket policy manually.
  • Configure Behaviors:
    • Compress Objects Automatically: ✅ Yes
    • Viewer Protocol Policy: Redirect HTTP to HTTPS
    • Allowed HTTP Methods: GET, HEAD
    • Restrict Viewer Access: ❌ No (unless you want signed URLs)
  • Cache and Origin Request Settings:
    • Cache Policy: ✅ CachingOptimized
    • Origin Request Policy: ✅ UserAgentRefererHeaders (Passes Referer to S3)
  • Assign the SSL Certificate:
    • Under Settings, choose Custom SSL Certificate.
    • Select the certificate you created in AWS Certificate Manager.
  • Click Create Distribution.
CloudFront: Origin configuration
CloudFront: Origin configuration
CloudFront: Behavior configuration
CloudFront: Behavior configuration
  1. Configure S3 Bucket Permissions

By default, an S3 bucket is private. We need to allow CloudFront to access it.

  • Go to S3 → Select your bucket.
  • Permissions → Enable ✅ Block all public access (since CloudFront will handle access).
  • Update the Bucket Policy:

Replace <bucket name> and <cloud front oai> with your actual values:


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowAccessFromSubdomains",
            "Effect": "Allow",
            "Principal": {
                "AWS": ""
            },
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::/images/*",
                "arn:aws:s3:::/assets/*"
            ],
            "Condition": {
                "StringLike": {
                    "aws:Referer": [
                        "http://*.yoursite.com/*",
                        "https://*.yoursite.com/*",
                        "http://yoursite.com/*",
                        "https://yoursite.com/*"
                    ]
                }
            }
        }
    ]
}
  1. Final Steps
  • Deploy CloudFront: Wait for the CloudFront distribution to finish deploying.
  • Test Image Loading:
    • Try accessing an image: https://images.yoursite.com/path/to/image.jpg
  • If you get 403 Forbidden, check that:
    • The CloudFront OAI is correctly assigned.
    • The S3 bucket policy includes the OAI ARN.
    • The Referer header is forwarded.

✅ Now, you have a fully configured, optimized, and secure image-serving setup with AWS S3 and CloudFront! 🚀

Conclusion

And there you have it! With AWS S3 and CloudFront working together, we’ve built a fast, secure, and cost-effective way to serve images like a pro. No more bogging down your web server or dealing with slow load times—CloudFront handles the heavy lifting, while S3 keeps everything organized and secure. By forwarding the Referer header and blocking direct S3 access, we’ve also locked things down to prevent hotlinking and unwanted traffic. Now your images load lightning-fast, stay protected, and scale effortlessly. Simple, efficient, and built to last! 🚀