How to host a static website using AWS S3 and Cloudflare

I’ve been noticing a previous post about how to host a static site using AWS services has been gaining in popularity.

Most recently a blog post by Thom Greene (@tbgree00) had mentioned the previous article and while all the steps in the previous post are accurate and works – I wanted to share how I now host static websites using AWS S3 and Cloudflare.

But first, why the change?

It’s a simpler process. In the previous post several AWS services (Route 53, Cloudfront, & Cert Manager) was needed to do what Cloudflare does by itself. It’s also cheaper as there is a cost that comes with Route 53 and Cloudfront, whereas Cloudflare is FREE.

It is more secure. In the previous post we created an S3 bucket and gave it public read access, using the process detailed below the bucket is no longer publicly accessible and only accessible if coming through Cloudflare. This ensures no one can try to side step all the protections that Cloudflare offers when trying to reach my static sites.

Requirements before getting started:

  • An Amazon Web Services account.
  • Domain name – I use and suggest either Namecheap or NameSilo to register new domains if you haven’t already. (Use coupon SAVE1OFFNAMESILO at NameSilo to save $1.00)
  • Already have a static HTML page designed and ready to upload.

Host a static website using AWS S3 and Cloudflare

Amazon S3 Bucket Setup

  1. First create a S3 bucket with the same name as your domain name, be sure to include the www. and select your desired AWS region.
    create s3 bucket www
  2. Then enable static website hosting for the bucket under the Properties tab.
    s3 static web hosting

    and set an index and error document file names and click SAVE. Be sure to make note of the bucket endpoint URL

    enable static website hosting

  3. To allow this bucket to be accessible via Cloudflare we will need to edit the bucket policy, under the permissions tab

    s3 bucket policy menu

    and copy/paste the following:

        "Version": "2012-10-17",
        "Statement": [
                "Sid": "PublicReadGetObject",
                "Effect": "Allow",
                "Principal": "*",
                "Action": "s3:GetObject",
                "Resource": "*",
                "Condition": {
                    "IpAddress": {
                        "aws:SourceIp": [

    Note: Be sure to replace MYDOMAINNAME in the policy with your own domain name.

  4. You can now upload your static website to your S3 bucket.
    Note: Your website will not be accessible yet.

AWS S3 non-www bucket setup

We need to create a second S3 bucket so that when users try to access they will be redirected to

  1. Create a second S3 bucket with the same name as your domain name, this one WITHOUT the www.
  2. Enable static website hosting for the bucket, but this time set it to redirect to your bucket.
    s3 static website redirect

That’s it for the second bucket, now lets setup Cloudflare!

Cloudflare setup

  1. Log into Cloudflare and click on “+Add Site“.
    cloudflare add site

    Then type in your domain name and click on “Add Site“.

    cloudflare add domain

  2. Then select the FREE Cloudflare plan. Feel free to use another plan if you feel you need it.
    cloudflare select plan
  3. Next you may have one or more DNS records associated with your domain, if so remove them by clicking on the X next to each one of them.
    cloudflare remove dns records
  4. Now lets add some DNS records for our two AWS S3 buckets. We need to add a record for each S3 bucket.
    • Create a CNAME record with the name www and for the server field enter the bucket endpoint URL without the https://
    • Create a second CNAME record with the name of your domain (without the www.) and for it’s server field enter the bucket endpoint URL, also without the https://

    cloudflare add dns
    Then click on Continue.

  5. Cloudflare will then give you two nameservers to point your domain name to. So now log into your domain name registar and update the name servers to the nameservers Cloudflare gives you.
    cloudflare name servers

At this point you’ll just need to wait for DNS to update. This could potentially take 24-48 hours, but in most cases this is much faster.

There you have it, you now have a static website being hosted on S3 and the protections and speed improvements from Cloudflare.

29 thoughts on “How to host a static website using AWS S3 and Cloudflare”

  1. Thanks for the guide.

    If you also use the domain for mail (e.g. via G Suite), does not having an A record affect mail delivery (e.g. recipients flagging your email as spam)?

  2. I keep getting “Invalid hostname: Use ‘@’ to represent the root domain.” at step 8 and can’t create any of the 2 CNAME records recommended there. Are you sure a step was not skipped? Maybe there should be a record there already before we can create those records in step 8. Any ideas?

    1. I had the same problem. Took me a while to work out that the bucket endpoint URL you get when you create it is different from the path of the data uploaded.

      When you get the location of index.html, for example, it shows up as

      This won’t work in Cloudflare, though. There, it has to be formatted as, as this is the endpoint you get when the bucket is created.

      I had to delete the bucket and start again to get it to work.

  3. I guess that works, though it does waste a bucket for every variation of domain name you want to point at that bucket. Even though the 100 bucket limit is a soft limit, it’s still sort of annoying. Thanks for the article.

  4. Hi Mike,

    Thanks for a great article, I’ll definitely be implementing this into my next website. Will this work for user generated content? I have an s3 bucket which I want to use that will allow users to upload images. These images will be deleted after 1 calendar month, however I want to make sure that I’m taking as many precautionary measures as I can in the event that my website was targeted.

      1. I am facing the same error and I gave a try to curl:

        ➜ ~ curl -X GET -vvv
        Note: Unnecessary use of -X or –request, GET is already inferred.
        * Trying…
        * TCP_NODELAY set
        * Connected to ( port 80 (#0)
        > GET / HTTP/1.1
        > Host:
        > User-Agent: curl/7.63.0
        > Accept: */*
        < HTTP/1.1 200 OK
        < Date: Tue, 03 Sep 2019 23:48:36 GMT
        < Content-Type: text/html
        < Transfer-Encoding: chunked
        < Connection: keep-alive
        < Set-Cookie: __cfduid=daa3722d4756ddd3cef578c8c557ccbaa1567554516; expires=Wed, 02-Sep-20 23:48:36 GMT; path=/;; HttpOnly
        < x-amz-id-2: y6keCOxN4RWpdwssQzO3MthhiW5g2TjCOUQuono0O9pCMzmHArzaIt8DU7oNk4isxsaAIuiV36E=
        < x-amz-request-id: 28DBFA40D8651F13
        < Last-Modified: Tue, 03 Sep 2019 17:23:05 GMT
        < Server: cloudflare
        < CF-RAY: 510b9d916bfeb839-WAW
        * Connection #0 to host left intact
        elo s3 by andilabs%

        ➜ ~ curl -X GET -vvv
        Note: Unnecessary use of -X or –request, GET is already inferred.
        * Could not resolve host:
        * Closing connection 0
        curl: (6) Could not resolve host:

      2. Andi,

        So long as you’ve followed the above instructions as listed you should be good. Curious, have you made any changes to any of the Cloudflare settings?

        In CLOUDFLARE on the SSL/TLS tab what is your SSL set to (Off, Flexible, Full, or Full Strict)?

  5. Hello Mike,

    Recently, I made the decision to migrate my site from 1and1 (host and domain registrant) to Cloudflare and AWS. After doing so, I started scouring the net for tutorials on how to set these services up to talk to each other and get my content back online. I read a lot of confusing things and did a lot of even more confusing things in the process.

    This article cleared up some of that confusion and I appreciate you creating it.

    But with that, I do have a few questions.

    1. Since Cloudflare is my new domain registrant, I assume I won’t be doing anything with list #9, Change Your Nameservers.

    2. If I understand correctly… the CNAME in the DNS on Cloudflare are setup to target the S3 End Points. This creates the handshake from Cloudflare to S3. And the bucket policy applied to the means that all calls for information will be routed through Cloudflare’s IPs and anything not from those IPs will be prevented access. So the Access should say “Objects can be public” correct? Do I need to add the policy to both buckets or just the one acting as the host bucket?

    3. After following these steps; I’m am getting an error. Error 522, Connection timed out. It’s showing that it’s going through Cloudflare, but that I’m not connected to the host. I only have one index.html file on the server for the time being. For testing reasons, it’s a redirect that will connect to Google when the connection is made.

    Thanks again for the great article. I appreciate the effort it took to get it put together and shared with noobs like myself.

  6. So if I follow what you are saying here I do not need to set the bucket public as it is all handled through the bucket policy that allows access only to the cloudflare IPs

    1. Sunil,

      Doesn’t look like you’ve followed the steps above as being able to access the file directly via the S3 URL would not be permitted if you used the Bucket Policy I included above. That bucket policy restricts access only via CloudFlare, which in this case would also be providing the HTTPS cert.


  7. Hi Mike, appreciate the guide but how about if I dont want the www like your https://miketabor?

    I followed your guide but reversed the part about creating the www first and redirect the non-www and couldn’t get it to work. Googled dozens of pages and everyone is doing it with the www or using Route 53 which is what I wanna avoid. 😀

    I’m sure if you list both steps it’ll be more helpful to more noobs like me out there.


    1. For steps 1-4 you would do for the NON-www folder instead. Making sure to edit the bucket policy in step 3 to not include the www. in the bucket name.

      For the steps under “AWS S3 non-www bucket setup” you would create a new bucket named ‘’ and have it redirect to the bucket without the WWW.

      Hope this helps!


      1. Cool. Thank you Mike.
        One thing though, I’m getting the following errors in DNS Section of Cloudflare:

        An A, AAAA or CNAME record was not found pointing to the root domain. The domain will not resolve.
        An MX record was not found for your root domain. An MX record is required for mail to reach addresses.

        Even when I’ve two DNS CNAME records with names www and waleedshaukat respectively pointing to their corresponding s3 urls.

        Is it due to https protocol set in redirecting s3 url above I roughly guess ?

        FYI, my Cloudflare Crypto settings are:
        – SSL (Active) : Full
        – Always use HTTPS : On
        – Automative HTTPS Writes : On
        – TLS 1.3 : Enabled
        – Onion Routing: On
        – Opportunistic Encryption: On
        – HSTS : disable

        I’m basically building my personal site Can you point to the issue here?

    1. Priel,

      I’ve never tried nor know why you would want to do so. Just from a search engine optimization (SEO) stand point this would be a big negative as Google and other search engines would see this as duplicate content.


Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top