Martin Hicks

Freelance mobile app & web developer
in sunny Manchester


Migrating to a static site

As you can see, if you click around my site a little, I’ve been far from a proficient blogger. In fact, I’ve been so lax, that my last flurry of posts was six (!) years ago. I decided that I needed to re-evaluate my web presence.

I didn’t want to remove my old content. While sparse, it’s still the content I chose to create, so in my mind perfectly pertinent for my site. But what I really didn’t need was a costly VPS running a fully baked LAMP stack just to host this site.

My site was powered, as many are, by WordPress. It’s very easy to use, has great plugin support and is easily themed. I was happy with it – when I (infrequently) used it. I considered migrating to one of the host of static site generators –  Jekyll, Hugo etc.  But would the effort be worth it? What was my actual need, and what was the first step?

Eliminate the VPS

Well, the first step was to eliminate the need for a VPS. How I (infrequently) edit and add content to the site was kind of irrelevant to me. I just didn’t want to think about maintaining a server. So switching to a different template engine / generator wasn’t for me. I just needed static versions of the rendered HTML WordPress was serving – so I chose the easy to use WordPress plugin Simply Static.

The plugin basically renders each page of your website, but instead of serving it to a browser, each page is saved as a static HTML file. A folder structure is created to handle each slug, so there’s no concerns about losing any SEO ranking or braking existing links.

I knew this approach wasn’t 100% perfect. While I was eliminating the need for a LAMP stack. I was basically losing the ability to easily edit my site. Remember each rendered page results in a single static HTML file. So your header / footer etc are duplicated across multiple pages. Perfect for speedily serving up your static content, but a nightmare for future edits….

Should I have taken the time to learn a static site generator instead? Maybe. Until I realised that I could still use WordPress (wait, what?) – just locally.

Updating my content

My new workflow is to spin up a local copy of the site and enter WordPress (local PHP, MySQL etc). When I’m happy with the new content or the changes to the theme I’ve made, I simply re-run the static export using Simply Static.

With this setup I’m also sacrificing the ability for people to comment. For now I think I’m just going to leave it comment-less, but I might look into one if the permalink based offerings such as Disqus

It’s working well so far – I’ll write a future post if this changes!

Static hosting

Next I needed somewhere new to serve the content from. I didn’t need my own server as I had no backend requirements, my site is now just HTML, CSS and JS afterall. Enter S3 and static hosting.

I knew from previous projects that S3 is a viable hosting environment. It’s globally scaleable and the costs are truly minimal. Add to that serving up a static site means no database, no scripting language etc – it’s fast too.

While there’s several deployment services, such as DeployHQ – I really wanted to avoid costs / dependencies to other services. So I decided to piece together my own deployment script using the node.js module S3-website

The module is really easy to use. You have the choice of running it from your CLI (i.e. globally install the package) or working in a more verbose manner within npm script files.

I decided to do a bit of both. This gave me the confidence that my setup would be correct, while also the speed of deploying at will. I’ll probably want to switch to an npm command so I can add error checking etc – but for now this is fine for me.

To deploy, I simply run `s3-website deploy site/ -d`, while I initially created my S3 hosting environment using the following:

const create = require('s3-website').s3site;

  domain:'', // required, will be the bucket name
  region:'eu-west-2', // optional, default: us-east-1
  index:'index.html', // optional index document, default: index.html
  error:'404.html', // optional error document, default: none
  exclude: ['.git/*', '.gitignore'], // optional path patterns to be excluded from being created/updated/removed, default: [], `*` is the wildcard
}, (err, website) => {
if(err) {
  domain:'', // required, will be the bucket name
  region:'eu-west-2', // optional, default: us-east-1
}, (err, website) => {
if(err) {
A few things to note:

1 – S3-deploy doesn’t appear to support aliases in your AWS credentials file. So, if like me, you have many separate access details for your personal AWS account, work, clients etc Then make sure you set your desired account as the [default] alias within ~/aws/credentials

2 – The second create block, creates a bucket, which in turn is set to redirect onto the main bucket. This mimics the behaviour my site has always had historically via .htaccess redirect rules (and is my personal preference)

3 – My current setup doesn’t include TLS, so no https – to do this I’ll need to route through CloudFront (I’ll blog this when I get round to it)

Making the switch

By now I had the static files for my site. I’d setup an S3 bucket to host from, with deployment scripts to easily update. Next I needed to point my domain to this new service.

Here is where I hit a multitude of problems. Most guides will tell you that you can create a CNAME record pointing to the full URI of your S3 endpoint (in my case The problem here is that you can’t add a CNAME record to the root of your domain, it must be second level e.g. www, subdomain etc.

So I created the www CNAME and pointed it to the S3 URI, but encountered redirect errors and was struggling to understand what to do about the A record – the IP address of the S3 domain can be one of many, changing on each ping, which I presume means you shouldn’t use it.

After a great deal of trial and error (lots of errors!) – I realised that in order to handle the A record, I would actually need to use Route 53 as my domain’s name servers. This would allow me to point the A record using Route 53’s alias mode – I wouldn’t need to know the IP address as Route 53 could internally look this up using the AWS alias. If anyone knows of a different (better?) way I’d love to hear more. (I’m guessing my issues were due to my desire to drop www, i.e. redirecting to


Using WordPress to create the static files is fairly pain free. Right now I didn’t want to go the extra hop to using a static generator, but to be honest this site is six years old, and if I start using it more I’ll no doubt want to modernise so maybe that’ll be a good time to explore these new tools.

I’ve only been running this new setup for a week, so I don’t have reliable costs for comparison, but I’m confident it will be coming in far lower than the thirty odd pounds a month I was spending. I know you can get VPS’s far cheaper now (like £5 per month on AWS Lightsail), but for me, and this site in particular, the removal of has been worth it.

Want to comment on this article? Have an exciting web development project you'd like to discuss? Hit me up at @martinhicks



Martin Hicks


Si Novi | product studio


Angular, React / React Native, HTML5, CSS3, PHP, AWS, Serverless, PWAs, Ionic, Yii, JavaScript, MySQL, iOS, Android, PhoneGap, Cordova.

I have many years experience working in Web Development (both front-end and back-end) and Mobile Apps. I specialise in making solutions that are simply intuitive, on budget and on time.

Over the past 4 years I've been specialising in producing scaleable APIs using both load-balanced EC2s and lambdas, hooked into Angular and React for browser based web apps and hybrid mobile apps.

Recently I've been enjoying learning more about PWAs and web components using StencilJS.




BSc Multimedia Computing (First-class Honours)
HND Music Production

Listening to