When hosting a content-based website, there’s usually media that you’ll want to host for it. You won’t want to host that static media in the application code or using blob storage in the database, so the best solution will usually be an object-store. With CloudFlare offering a free CDN, and Amazon S3 offering a great object-store solution, you can achieve this easily.

First, setup the S3 bucket. Name the bucket the same as the domain/subdomain you are going to use for your DNS (e.g. media.mysite.com). Make sure “Block all public access” is off (we will address this security concern later). Optionally enable “Bucket Versioning” if you want to version your objects. For encryption settings, choose “Server-side encryption with Amazon S3 managed keys (SSE-S3)” and enable “Bucket Key” encryption. Enable or disable “Object Lock” if desired.

Second, with the S3 bucket created, edit the bucket’s “Properties” and enable “Static website hosting”. For the “Index document” use index.html and “Error document” error.html; leave the “Redirection rules” blank. Keep track of the “Bucket website endpoint” as this will be used for the CNAME record when setting up CloudFlare.

Third, edit the bucket’s “Permissions” and update the bucket policy similar to the below. Replace the my-app-role with your app’s IAM role and keep the IPs in the policy aligned with CloudFlare’s list. This policy will allow your app to put and delete objects, and only allow CloudFlare direct access to the S3 “Bucket website endpoint”. It should be noted that as of now, previously S3 was implicitly Allow-all, now S3 is implicitly Deny-all, so an explicit policy has to be implemented on who is allowed to do what.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::1234567890:role/my-app-role"
            },
            "Action": [
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::media.mysite.com/*"
        },
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::media.mysite.com/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "173.245.48.0/20",
                        "103.21.244.0/22",
                        "103.22.200.0/22",
                        "103.31.4.0/22",
                        "141.101.64.0/18",
                        "108.162.192.0/18",
                        "190.93.240.0/20",
                        "188.114.96.0/20",
                        "197.234.240.0/22",
                        "198.41.128.0/17",
                        "162.158.0.0/15",
                        "104.16.0.0/13",
                        "104.24.0.0/14",
                        "172.64.0.0/13",
                        "131.0.72.0/22",
                        "2400:cb00::/32",
                        "2606:4700::/32",
                        "2803:f800::/32",
                        "2405:b500::/32",
                        "2405:8100::/32",
                        "2a06:98c0::/29",
                        "2c0f:f248::/32"
                    ]
                }
            }
        }
    ]
}

Finally, setup CloudFlare by adding a CNAME record to your CloudFlare hosted DNS with the Name as media and the target value being the “Bucket website endpoint” host (e.g. media.mysite.com.s3-website-us-east-1.amazonaws.com). For the “Proxy status”, enable it and sett TTL to auto.

Optionally, if you only want your media to be accessible from your own site, within CloudFlare, setup a “Configuration rule” named “Hotlink Protection” with a “Custom filter expression” of the below, “Hotlink Protection” enabled, and “Place at” First in “Select order”. Replace “mysite.com” with your domain.

not http.referer contains "mysite.com"

Once all that is done, you should be able to access static media content via media.mysite.com which gets cached and is shielded by CloudFlare (for free). This is a simple way to avoid having to manually manage a storage solution for media, and also an easy way of providing a CDN layer on top of your media storage solution.

Write A Comment