When I’ve searched a solution for hosting my tech blog I’ve heard that the combo S3 + Cloudflare was the cheapest.

I bought my domain name on Gandi. I use Hugo for managing the content of website.

The architecture

The setup steps

1- Create a new site with Hugo

Install Hugo and run the following command:

$ hugo new site my-blog

Note: replace “my-blog” with the name of your site

Add your theme and setup your site. Then build your site:

$ cd my-blog
$ hugo

And then test it with:

$ cd my-blog
$ hugo server
Watching for changes in my-blog/{content,data,layouts,static,themes}
Watching for config changes in my-blog/config.toml
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop

2- Create the S3 buckets

Assuming you want to enable www.my-blog.com and my-blog.com, you will have to create 2 buckets.

Lets create the first bucket www.my-blog.com:

$ aws s3api create-bucket --bucket www.my-blog.com --region eu-west-1

Note: You can choose another region :)

Enable the website hosting:

$ aws s3 website s3://www.my-blog.com/ --index-document index.html --error-document 404.html

Now we create the last bucket my-blog.com:

$ aws s3api create-bucket --bucket my-blog.com --region eu-west-1

Note: You can choose another region :)

This bucket will be empty. All the requests will be redirected to my-blog.com

Create the file webconfig.json:

{
  "RedirectAllRequestsTo": {
    "HostName": "www.my-blog.com",
    "Protocol": "https"
  }
}

Then enable the website configuration :

$ aws s3api put-bucket-website --bucket my-blog.com --website-configuration file://webconfig.json

3- Put a policy to limit web access to Cloudflare servers

Create the file policy.json:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::www.my-blog.com/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "2400:cb00::/32",
                        "2405:8100::/32",
                        "2405:b500::/32",
                        "2606:4700::/32",
                        "2803:f800::/32",
                        "2c0f:f248::/32",
                        "2a06:98c0::/29",
                        "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/12",
                        "172.64.0.0/13",
                        "131.0.72.0/22"
                    ]
                }
            }
        }
    ]
}

The access is restricted to the IP ranges of Cloudflare.

Now put the policy on bucket:

$ aws s3api put-bucket-policy --bucket www.my-blog.com --policy file://policy.json

4- Upload your webpages into the bucket

$ cd my-blog
$ hugo --minify --enableGitInfo
$ aws s3 sync public s3://www.my-blog.com

5- Configure DNS entries at Cloudflare

Go to the DNS sections, and add these 2 entries:

TypeNameValue
CNAMEwww.my-blog.comwww.my-blog.com.s3-website-eu-west-1.amazonaws.com
CNAMEmy-blog.commy-blog.com.s3-website-eu-west-1.amazonaws.com

Do not forget to update the DNS servers for your domain name.

Congratulations !!! your site is online :)