Hosting a static website: Amazon S3 + Cloudflare

Jaroslav Hranička
7 min readJul 21, 2019

--

Amazon S3 + Cloudflare

In the old times, we all had been there. The space of shared hosting companies and cheap VPS providers. Those days are not over and it may be still reasonable to use them. But if you want to host a static website, there is another option. It could be easier and may cost you nothing or few cents at most.

So what are the possibilities in 2019?

  • Shared web hosting.
  • VPS with a web server (mostly Nginx or Apache).
  • Static pages host provider (GitHub Pages, GitLab Pages, ...).
  • Cloud application platform (Netlify, Heroku, ...).
  • A cloud service provider (AWS, Microsoft Azure, Google Cloud, ...).

Let’s talk about the latest one — a cloud, targeting minimal expenses and backed with an option of additional services.

There are already a lot of articles about that topic. Most of them cover everything dedicated to AWS (from domain registration up to CDN configuration). I’ll describe my personal use case which is different. It compounds of Amazon S3 + Cloudflare.

If you’d rather omit Cloudflare (and want to use Amazon CloudFront instead), this article is probably not for you.

Why Amazon S3?

It’s simple object storage, it’s cheap (free if you are eligible for free tier), it allows easy uploads (eg. from CI), etc. If I would require additional backend services, it would be easy in the AWS ecosystem. Last but not least, it provides a simple web server for us.

I can host files with Amazon S3 for free or few cents.

Why Cloudflare?

I already use Cloudflare as a DNS and CDN provider. I just want to move pages from VPS to somewhere else. Cloudflare provides a free plan, it’s reliable, easy to configure, provides TLS certificate, etc. In my scenario, I don’t see the benefits of Route53 and CloudFront which would cost >$6/year.

I can manage DNS and use CDN for free with Cloudflare.

Prerequisites

  • You already have an AWS account and know what it is.
  • You already have a Cloudflare account and know what DNS records are.
  • You already have a registered domain and set Cloudflare’s nameservers (so all the changes in Cloudflare will affect your domain).

I will describe how I host a static website www.hranicka.cz. You can use this article as a how-to tutorial for your website. Just replace my domain with your in all steps. Let’s begin!

S3: Web server

Price: Free (AWS Free Tier) or <$1/year (in case of proper configuration and small site)

First of all, log into your AWS account. Create a new S3 Bucket. The name has to be identical to your domain name (including all domain levels).

1. Create a Bucket (www.hranicka.cz in my case) in the preferred region with default settings. Just don’t forget to add tags if you mean it seriously.

Now, the Bucket which will be a storage for our files, has been created. There are no files (ahem, objects) in it and it’s not available via HTTP yet.

2. Upload files to the Bucket. For the beginning, it may be just a single index.html file. Open the Bucket and Upload a file via AWS Console (=Web UI). Continue with the default configuration.

TIP: It’s pretty easy to upload files to S3 via CLI. For example, doing a deployment after a build in CI (eg. Gitlab). But that’s beyond scope of this article.

3. Configure Bucket for a Static website hosting. Go to Properties > Static website hosting, enable it and set index.html as Index document.

Now, the Bucket is configured to work as a simple web server. You can see an Endpoint, a URL, on which the server is available. If you try to access it in your browser, it won’t work as expect. That’s because access to Bucket’s objects is restricted (recall “Block all public access” from the Bucket configuration).

4. Go to Permissions > Bucket Policy and insert the following JSON. It allows public access to your files.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::www.hranicka.cz/*"
]
}

Everything in the Bucket is now available over HTTP at the Endpoint revealed during previous step (http://www.hranicka.cz.s3-website.eu-central-1.amazonaws.com in my case). You should see uploaded HTML page.

Unfortunately, there is still something missing. We have own domain, but we don’t use it. Let’s change it.

Cloudflare: DNS, security, and cache

Price: Free

Log into your Cloudflare account and select your domain.

Create a domain alias for your S3 Endpoint. Go to the DNS section and create a new CNAME record. Ensure you pass traffic through Cloudflare (“orange cloud”) to leverage free CDN. Otherwise you would just set a DNS record.

The value is exactly the S3 Bucket Static website hosting URL without a protocol (http://).

Wait a few minutes (at least 5) and visit your domain (www.hranicka.cz in my case). You should see the same content as at the S3 Endpoint (http://www.hranicka.cz.s3-website.eu-central-1.amazonaws.com in my case).

We have a working website on our custom domain now!

You can also play around with security configuration (HSTS, TLS version, …), cache behavior, etc.

There is a space to speed-up the page and also save some bucks. Continue with Finetuning section. Your website deserves the best!

Troubleshooting:

  • Ensure you have configured your domain to use Cloudflare’s nameservers.
  • Ensure you use Flexible SSL configuration in the Cloudflare for your domain. Keep in mind the S3 Endpoint is not secured by TLS so it doesn’t work with Strict settings.
  • Purge Cloudflare caches or temporarily enable Development mode if you are getting old data or site does not work for you.

Finetuning

Redirect from non-www to www

Create an additional S3 Bucket for your root domain (hranicka.cz in my case). Configure Static website hosting (Properties > Static website hosting) to redirect all requests to www domain.

That’s not enough, it would work only for the S3 Endpoint. Go to Cloudflare and configure DNS to point your root domain to the S3 Endpoint which does the actual redirection.

Wait until the new DNS record propagates through the Net (5 min) and visit non-www variant. It should redirect to the www (hranicka.cz -> www.hranicka.cz in my case).

CDN cache and reduced number of requests to S3

Cloudflare caches just static content by default (images, stylesheets, javascript files, etc.). It means every time somebody visits the website, Cloudflare sends a request to the aliased S3 Endpoint and returns a fresh version of the HTML page.

To avoid this unnecessary round trip, let’s make Cloudflare caching also HTML content. Navigate to the Page Rules and create a new one:

  • Match everything on the domain (www.hranicka.cz/* in my case).
  • Add setting Cache Level: Cache Everything.
  • Add setting Edge Cache TTL: a day or a value suiting to your needs.
  • Save and Deploy

Keep in mind that if you change the original data (in S3), you need to wait until TTL expires or you have to purge Cloudflare cache.

Access only via custom domain

If you want to deny direct access to S3 Endpoint (http://www.hranicka.cz.s3-website.eu-central-1.amazonaws.com), it is possible.

Change S3 permissions to allow access only from Cloudflare servers. Open your Bucket settings, go to Permissions > Bucket Policy and add whitelist Cloudflare’s IPs:

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::www.hranicka.cz/*",
"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/12",
"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"
]
}
}
}
]
}

If you visit the S3 Endpoint, you should get 403 error now. It may save you some pennies (access to S3 is billed and your domain is covered by CDN).

--

--