After exploring Hashnode, Dev.to, and Medium, I decided to self-host my blog, not for performance, but for control. Here’s how I did it with AWS, Ghost, and a minimal budget.
đź§° TL;DR: Self-hosted my Ghost blog on AWS EC2 (t2.micro) using a custom Nginx setup with /blog routed. Faced installation challenges due to CPU limits, solved it with a t2.large temp instance.
How It All Started
It all started when I was in college and watched a video by Quincy Larson, creator of FreeCodeCamp, about why developers must have a blog. So I started geekaid.in. After writing on it for a while, I dropped it a year ago as it stopped aligning with what I originally thought of.
Even now, some blogs are ranking and creating traffic, but I stopped resonating with the idea behind it — it was more about building a brand than expressing myself.
So recently, I wanted to start fresh. I bought a new domain — hiteshpatel.tech — and began again.
Why I Picked Ghost
After exploring all the options, as a developer, there’s always an itch in me to control everything, try new things, and use my knowledge to build. So, using another platform was not an option. Maybe this time, I’ll have to spare more time for maintainability too — and I’m okay with that.
Hosting Ghost on AWS (My Setup)
I didn’t want to spend money on hosting the blog, and Ghost requires a server, unlike static sites that can be easily hosted on GitHub Pages for free.
So, AWS free tier was my go-to. I’m comfortable with AWS, so the setup was straightforward. Here it is:
As you can see, it’s a really simple architecture. I started a t2.micro instance and began installing mysql-server, nginx, node, and ghost — These are the dependencies we need.
After trying to install Ghost in production multiple times, my SSH window kept freezing. On checking, I found out the CPU was getting maxed out.
⚠️ T2.micro Warning: Ghost installation failed multiple times due to CPU spikes. I switched to T2.large for setup, created an AMI, then launched a T2.micro again using the AMI.
This resolved the issue. Now I wanted subdirectory routing for the blog, so I configured Nginx — and it’s pretty simple. Just route all requests coming from /blog to be served by Ghost.
location /blog { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:2368;
proxy_redirect off;
}
Mail Server
Ghost in production needs email configured for authentication, and it doesn’t allow you to use its CLI for login. I checked a few email services like Mailchimp and Mailgun — they were all paid, and I needed a free solution.
So I went with Gmail. Just created an app password for my Gmail account, and I was good to go.
Whether I Still Recommend This Setup
I wouldn’t recommend replicating this setup right now. This architecture is vulnerable — it can go down at any time. It has the lowest availability, no backups, and everything is on the instance store.
What I’d Improve If I Had More Time/Resources
I plan to improve this setup later by using RDS, EBS volumes, and auto-scaling — essentially, leveraging everything I’ve learned to create a more resilient and scalable architecture.
