For the last couple of years, this blog lived on a Digital Ocean droplet. Hosting on Digital Ocean worked well, and I have no complaints about their service. But I like consistency. I spend most of my time in AWS for work and personal projects. So I decided to move this blog to AWS.

Step one was deciding how I wanted to run the blog.

  1. Option one would be a 1 to 1 copy of the infrastructure on Digital Ocean by running the ghost process directly on the instance.
  2. I could run a Docker container in something like ECS, or Fargate. Running on a container service would necessitate that I ran a separate database instance and provided local storage for uploaded files and other content.
  3. Option three is a hybrid approach of options one and two. It allowed Docker to manage the required dependencies, in this case, Nginx and Ghost.

I settled on option three. Currently, this blog is running on an ARM-powered instance with an Nginx container proxying requests to the Ghost container. There is also a container that periodically spins up, creates a tarball of the content directory then uploads that to S3 for backups. The bytes you received on your device came directly from CloudFront. The public pages of this blog have an extended cache TTL, so my little instance hardly ever sees traffic. The one tradeoff I made with this, is the homepage can take a couple of hours to update when I publish a new post. Because I get literally dozens of visitors a month, this doesn't matter.

The one catch and the reason CloudFront doesn't talk directly to the Ghost instance is SSL. CloudFront performs the SSL termination then talks to the instance over HTTP. CloudFront doesn't support sending an X-Forwarded-Proto header that Ghost requires. Because of this, Ghost will try and redirect all requests to https. But the client is already on https. So you get stuck in a loop. Because of this issue, Nginx writes the X-Forwarded-Proto header before proxying. Adding this header tells Ghost that we have already taken care of SSL, and it should just serve the requested page on HTTP.

Some things still on my todo list. When an instance is stood up, I have to ssh into it manually and pull the latest backup then un-tar it inside the correct volume. The ssh step isn't a big deal, but it's an extra step. I would like for this to happen automatically. Additionally, the IP address assigned to the instance is static. I want to use randomly assigned IPs and update the DNS record in Route53 when hosts come or go.

Those two items are far from "blockers," and this blog has been running on AWS for a couple of weeks now without issues.