Publishing a Website the Modern Way


I am a proficient and successful software developer. I have been putting websites on the internet for over 15 years. Yet I have never been as frustrated in doing so as I have been today.

It used to be that you would sign up for a shared hosting account for like $3/month and click the “WordPress” button in your cPanel. Then, after updating your DNS records to point to the IP address of the shared hosting server, you could visit yourdomain.com and see the WordPress setup page. Another ten minutes of fiddling with phpMyAdmin and you would have a WordPress website. In 15 minutes or less you would have launched a new website on “your own” server. Could it stand up to the front page of hacker news? Nope. But it didn’t really matter, this is how it was done.

the wordpress setup page

In trying to start this blog I decided I would use modern technologies. Afterall, I do have a startup in the jamstack space. I’ve been a huge fan of Hugo since I found it when it was at version 0.11 in May of 2014. And I love golang, so this was an easy choice. I wanted to “own the whole stack” so I opted to not use Netlify or Vercel for hosting. Instead, since I am well versed in AWS services having been a user since 2011, I decided to put the site on S3 and serve it with CloudFront. This should be easy... right?

Wow, was I wrong.

Attempt Number 1

I’ll create a hosted zone in Route 53 and set the nameservers on my domain in my registrar. Next I’ll create an S3 bucket to hold the contents of my website. Then over to cloudfront to create a distribution and point it at the bucket. And finally, create a new DNS record to point my domain at CloudFront. Done.

Unable to connect to origin.

Hmmmm.

Oh, right, the bucket needs “Static Web Hosting” turned on. I totally forgot to do that.

Unable to connect to origin.

Ok…

Well, since I didn’t make the objects in the bucket publicly accessible (because I only want the website available via CloudFront) maybe I need a bucket policy. Google google google. Yep, that must be the problem. Alright, enter the policy and click save.

Unable to save bucket policy. One of the principals is invalid.

Double check. Triple check. That’s the correct value for the principal. Google google google. I need to tell CloudFront to create an origin access identity. How do I do that? I need to use the bucket name as the origin instead of the S3 website endpoint. Well if I do that then the website won’t be served from S3 properly. But that’s the only way to do it. I give up. There must be an easier way. Google google google.

Attempt Number 2

I found this project from AWS. This should make it simple. It’s got a “Launch on AWS” button. Perfect. Click. Enter in the values for the CloudFormation template. Wait for the stack to launch.

CREATE_FAILED

What now? Oh, there are still some resources from my first attempt hanging around and they are conflicting with the resources that the stack is trying to create. No problem, I’ll just delete those and relaunch the stack.

CREATE_COMPLETE

Awesome. And the example site is showing up on www.mydomain.com. Now I just need to deploy my site to the S3 bucket. The code for my site is on GitHub, might as well use GitHub Actions. Type type type, git push.

Deploy successful.

Excellent. I’m really making progress now. And my website is now showing up at www.mydomain.com. Now… how do I redirect mydomain.com to www.mydomain.com? There must be an easy way to do that in Route 53, right? Nope.

Ok. I need to create another S3 bucket, another ACM Certificate, another CloudFront distribution, and tell the S3 bucket to redirect requests to www.mydomain.com. Seems like a lot of work for something so simple, but if that’s how I’ve got to do it then that’s how I’ve got to do it. Type type type, click click click.

Redirect works. Great!

This is looking awesome. Let’s check the console in Firefox and see if things are getting cached.

Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”)

Hmmm. Why would that be? The readme for the GitHub repo says that it helps create a “Secure Static Website” and uses Lambda@Edge. Wait a minute, I thought this was a static website. But I’m running lambda functions now? The readme also has a section on updating the content security policy.

  1. Make your changes to the header values by editing source/secured-headers/index.js.

  2. Deploy the solution by following the steps in Update the website content locally

“Update the website content locally” says to install npm, clone the repo, build the artifacts, copy my website into a particular folder, and run the following S3 commands.

What? I just want to get my blog online. When did this become rocket science? I am done for the night. Going to bed. I will try again tomorrow.