Migrating This Website to AWS
September 7, 2022I’ve decided to migrate this website from DreamHost to Amazon Web Services. The main driver for this is costs. This is a static website (consisting of only HTML, CSS, and a small portion of JavaScript) which is very suitable to be hosted in S3. This is also a very low traffic website, well within S3’s free tier. Keeping up with my current setup, I wanted to retain the following:
- Secure website hosted at https://jcazevedo.net/ with a valid SSL certificate;
- Requests to http://jcazevedo.net/ are redirected to https://jcazevedo.net/;
- Requests with the
www
subdomain (https://www.jcazevedo.net/) are redirected to https://jcazevedo.net/.
I also wanted to keep everything managed from within AWS, so that I could get
some infrastructure automation (Terraform) to help me with setting
everything up. Keeping everything managed from within AWS meant that I had to
have the jcazevedo.net
domain transferred and have an SSL certificate
provisioned by AWS (I was previously using Let’s Encrypt). I also
didn’t mind downtime (again, this is a very low traffic website).
Setting Up Terraform
It wasn’t absolutely necessary to use Terraform (or any tool allowing for infrastructure as code) for this. I don’t predict wanting to have this infrastructure reproducible nor frequently modified. Still, it serves as documentation on what is set up on AWS, so I figured it would be a good idea.
The first step was to get Terraform set up and the providers defined. I didn’t
want to keep Terraform’s state locally, so I decided to also use S3 as a state
backend. I don’t need locks on the state (it’s only going to be me deploying
this), so a single file on a S3 bucket would suffice. So, I created an _infra
folder on the root of the directory tree of this website and placed a
providers.tf
file in it:
The required version is set to 1.0.11 because that’s the one I’m currently using
at $WORK
. Setting up the state backend required manually creating a bucket for
it. Using Terraform to manage that bucket would lead us to the problem of
remotely managing state that we were trying to avoid with it in the first place.
With this set up, a call to terraform init
should complete successfully.
Setting Up the S3 Bucket(s)
The next step was to set up the S3 buckets. I actually went with 2 buckets: one
for the root domain (jcazevedo.net
) and another for the www
subdomain
(www.jcazevedo.net
). The reason for it was to set up a redirect on the www
subdomain, which S3 supports. To set the buckets up, I
created an s3.tf
file under the _infra_
folder with the following contents:
Most of the configuration is the same for both buckets. We want both buckets to allow GET requests from the public. The main difference is in the website configuration. The root bucket specifies an index and error document (to be served in case of errors), whereas the www bucket just configures the redirection policy.
Once this was set up, I pushed this website contents to root S3 bucket by
running a bundle exec jekyll build
followed by an aws s3 sync _site/
s3://jcazevedo.net/ --delete
. The site was already available via the root
bucket website endpoint
(http://jcazevedo.net.s3-website-us-east-1.amazonaws.com/)
and the redirection was already working via the www bucket website endpoint
(http://www.jcazevedo.net.s3-website-us-east-1.amazonaws.com/).
At this point the domain wasn’t yet migrated, so this was still redirecting to
the DreamHost instance.
Setting Up the Domain
I had never transferred a domain before, so I followed AWS
instructions.
This would take a while to complete, so I figured I would create the
Route53 zone before and have the domain already transferred to the
new zone. For that purpose I created a route53.tf
file under the _infra
folder with the following contents:
While the domain had its tranfer in progress, I proceeded to set up the SSL certificates.
Provisioning the SSL Certificates
I had to search how to define ACM certificates in Terraform and to intregate them with CloudFront. Fortunately, I found this blog post by Alex Hyett: Hosting a Secure Static Website on AWS S3 using Terraform (Step By Step Guide). The blog post covered pretty much what I had already done thus far, and was extremely helpful on the next steps: setting up SSL and the CloudFront distribution.
To set up SSL, I created the acm.tf
file under the _infra
folder with the
following contents:
For the validation method I used email instead of DNS since at that time I didn’t have the DNS moved yet. The email validation is performed while we’re applying the Terraform diff, so it’s quite fast.
Setting Up the CloudFront Distributions
CloudFront speeds up the distribution of static (and dynamic) web
content. It can handle caching, compression and can require viewers to use HTTPS
so that connections are encrypted. The previously mentioned blog
post by Alex Hyett provided
instructions to set CloudFront distributions pointing to existing S3 buckets and
using HTTPS, so I almost blindly copied the Terraform definitions. Similar to
what had been done before, we needed two distributions: one for the root bucket
and one for the www
bucket.
The configurations are similar, except for the caching settings, since the
second distribution only points to the S3 bucket that redirects to the non-www
website.
Adding Route53 Records Pointing to the CloudFront Distributions
The last part of the process involved creating new Route53 A records pointing to
the CloudFront distributions created previously. For this, I’ve added the
following to the route53.tf
file mentioned previously:
There’s one record for each of the distributions (www
and non-www
).
Waiting for the Domain Transfer
The domain transfer from DreamHost to Route53 took around 8 days. I was notified by email when it was completed. Since everything was already pre-configured and the website contents had already been pushed to S3, the website continued to be served as expected from https://jcazevedo.net/.