Moving Static Site to Cloudflare Pages From A Squarespace/AWS House of Cards

About two years ago, Google did me dirty and sold its domain registrar service to Squarespace. As a former Squarespace user, I wasn’t happy about the change—the annual cost of each domain went up while the services went down. I slowly transitioned all of my domains to Cloudflare (another story for another day), but held off moving this site, as it was pre-paid for several years so why bother, right?

Wrong. Squarespace slowly chipped away at the features I had, and the final straw was breaking email forwarding. I don’t use email associated with the domain, so it wasn’t really a problem. That is, until it came time to renew the domain’s SSL certificate, which (of course!) had been set up requiring email verification. I needed to confirm ownership of the domain by email in order to extend the certificate for another year, but I wasn’t getting the emails.

I went through a painful process of trying to set up domain verification using DNS records. This, I learned, is an area where Cloudflare, Squarespace, and AWS really don’t play nicely together—with most of the opacity in the process coming from Squarespace. In the end, troubleshooting this labyrinthine setup was too much, especially when simpler solutions are there for the taking.

This is how I moved my static website from Squarespace and AWS to Cloudflare Pages.

Where We Started

A bit of history. I was first introduced to Amazon Web Services in 2016. Enticed by its rather generous free tier, I set up niamurrell.com as a static website on May 8th that year. Eventually, this led to the following setup:

  • Build static pages locally on my computer
  • Use AWS CLI to transfer static pages to an AWS S3 bucket
  • S3 bucket sits behind AWS Cloudfront CDN network for globally quick loading and SSL
  • Domain (currently Squarespace, but there have been several registrars over the years) points to Cloudfront distribution

When I first set this up, there wasn’t an abundance of no- to low-cost web hosts, and it wasn’t unusual to pay $5-10/month even for the most basic website. By comparison this AWS setup has cost about $0.53/month, and $0.50 of that was technically optional (the cost of the Hosted Zone required to serve the site over HTTPS).

Over the years a number of free services popped up, some of which I used for other sites, but I never changed this site’s hosting. Inertia I guess.

Where We’re Going

But it can be much simpler now! Cloudflare can do all of this, under one roof, and for free:

  • I still build locally but you can link a git repository for automatic deploys
  • Static pages are rendered from the build, or you can upload built pages
  • Cloudflare is its own CDN with globally quick loading and SSL (and WHOIS privacy, and email forwarding)
  • Cloudflare’s domain registrar is cheaper that Squarespace, and amongst the lower cost options in the market

Honestly, this seems like a no-brainer, so now just need to actually move the site!

Step 1 - Connect Domain to Cloudflare

Before you can do anything, you need to connect the domain to Cloudflare. This is different from moving the domain registration—basically in this first step you’re telling Cloudflare that your site exists, and asking it to proxy all traffic to your site through Cloudflare’s servers.

From the Cloudflare (I’m just going to call it CF from now on) dashboard in the Domains page, you click Onboard a domain. Type in the domain and then CF will search for its DNS records. You have the option to proxy A, AAAA, and CNAME records through Cloudflare.

Once the DNS records have been imported, the final step is to add Cloudflare’s nameservers to the DNS records with your domain registrar.

After a bit of time (sometimes in the minutes, sometimes in the hours), the domain will be listed as ‘Active’ in Cloudflare’s Domain Management section of the dashboard.

Step 2 - Create Cloudflare Pages Project

Still in Cloudflare, open BuildComputeWorkers & Pages and click the Create application button. I made the mistake here of using one of the big buttons that are now right in your face…these buttons are for Cloudflare Workers! For a simple static site, Cloudflare Pages is the better choice. So click the ‘Looking to deploy Pages? Get started‘ link instead.

The easiest setup is probably deploying from GitHub…this will make site updates automatic when pushing changes and lets you skip some of the steps I’ll get to later. But I prefer to build locally, so chose Drag & Drop Your Files. Then it’s as simple as creating a project name and uploading the files, and then the site will be visible on https://project-name.pages.dev.

Step 3 - Add Custom Domain

Now it’s possible to add a domain to point to this project. From the project’s dashboard, open the Custom domains tab and then Set up a custom domain. You’ll be prompted to delete the existing DNS records…this is scary, but needs must!

Be sure to add both domainname.com and www.domainname.com as custom domains for the project. After waiting a few minutes for these updates to propagate, you should see two new CNAME records attached to the domain with your project name as ‘Content’ for both of them.

Step 3.5 - Add Email Forwarding

This can really be set up any time after the domain is onboarded to Cloudflare, but I did it now. In the domain’s dashboard open EmailEmail Routing and add a destination address (the email address incoming emails should be forwarded to) and then follow the prompts to verify it.

Once this is done you can open the Routing rules tab and create multiple custom email addresses that. You can also add a catch-all address so that anything@domain.com will get forwarded (this might garner a lot of spam email, be warned). This is handy for any email verification that will go to the default email addresses (webmaster, administrator, etc.) going forward…or you can just create them manually.

Step 4 - Dismantle AWS Setup

Check Success in Browser
First, confirm that the site is working as expected. Use a different browser (or clear cache), use another device altogether…make sure you’re not seeing cached responses and that the website is loading as it should.

Check DNS Routing
You can also confirm that the DNS records are routing properly: run dig domain.com and dig www.domain.com in Terminal and both prompts should have a positive number of responses in the ANSWER section:

$ dig niamurrell.com

; <<>> DiG 9.10.6 <<>> niamurrell.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60170
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

...
;; QUESTION SECTION:
;niamurrell.com.

;; ANSWER SECTION:
niamurrell.com. 300 IN A 104.21.93.47
niamurrell.com. 300 IN A 172.67.171.296

...

The first time I set this up, I failed to add the www.niamurrell.com as a second custom domain, and the site wasn’t loading. This is why it’s important to check both, because it’s easy to spot the problem using dig if one endpoint isn’t working:

$ dig www.niamurrell.com

; <<>> DiG 9.10.6 <<>> www.niamurrell.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 54374
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

...
;; QUESTION SECTION:
;www.niamurrell.com. IN A

;; AUTHORITY SECTION:
niamurrell.com. 536 IN SOA cory.ns.cloudflare.com. dns.cloudflare.com. 2394915161 10000 2400 604800 1800

...

ANSWER should not be empty!

Check Cloudfront Traffic
Another thing to check is that Cloudfront isn’t serving assets anymore. Log into AWS and open the Cloudfront service, navigate to your distribution and then go to Reports & analyticsViewers. Traffic should be zero or near-zero.

There may still be some traffic if bots or any weirdos have saved your Cloudfront distribution’s URL to crawl. It’s probably a good idea to search your codebase for any errant URLS (search cloudfront.net and amazonaws.com) and update those links if necessary.

Once all of these checks have been made and you’re certain no desired traffic is being served by AWS, disable to Cloudfront distribution and check everything again after a few minutes. If you don’t run into any problems, everything is set up as it should be! Leave the Cloudfront distribution disabled (or delete it) and delete the Route 53 Hosted Zone to stop all future charges. You can also delete the S3 bucket, but I opted to keep it for the time being as a backup.

Step 5 - Set Up Scripts To Deploy To Cloudflare

As previously written, I set up a bash function on my machine to commit updates to git, rebuild the site, push the built site to S3, and invalidate the CloudFront cache every time I had a new change on the website. Now this script needs to be updated to work with Cloudflare instead.

The original bash function:

function atp {
npm run grunt
git add -A
git commit -m "Add today's post"
git push
hexo g
aws s3 sync /Users/me/web-folder/public s3://bucket-name --size-only --exclude ".DS_Store" --delete
aws cloudfront create-invalidation --distribution-id ABC12D3E45F67 --paths "/*"
return
}

The new tool to incorporate is Cloudflare’s CLI, Wrangler. CF suggests it’s best to install wrangler to individual projects, but since I’m not working on a team or adding any CI/CD tooling, a global install is fine:

$ npm install -g wrangler

Then log in:

$ wrangler login

The command to push updated files is:

$ wrangler pages deploy /folder/path/to/built/project --project-name project-name

So my new bash function is:

function atp {
npm run grunt
git add -A
git commit -m "Add today's post"
git push
hexo g
wrangler pages deploy /Users/me/web-folder/public --project-name niamurrell-project
return
}

A great discovery is that Cloudflare pushes the changes immediately and automatically—no need to invalidate any caches, it just works!

Step 6 - Transfer the Domain From Squarespace

Again, not a necessary step, but I’m ready to be done with Squarespace once and for all! Transferring the domain is pretty straightforward:

  • Unlock the domain for transfer in Squarespace
  • Go to Cloudflare’s Transfer Domains page in the Domain Registration dashboard. You might need to wait a few minutes to hours for the domain to be available for transfer.
  • Request a transfer code from Squarespace…again, you might need to wait a while for it to arrive in your email inbox (2h 9m for me).
  • Give the code to Cloudflare
  • Wait a week because Squarespace doesn’t let you do it any faster.
  • After the transfer is complete, go back to Squarespace and delete the domain from the dashboard.

You’re now completely free from Squarespace and AWS! Revel in the lower annual domain fee, in the lack of monthly charges, in the quick and easy deploys! 🎉🎉