How I built my personal blog on AWS for free
I wanted a place to document what I learn. Not a LinkedIn post here and there — an actual blog I own and control.
The goal was simple: a fast, lightweight blog that I could automate with AI later. No databases, no plugins, no maintenance overhead.
Here’s exactly how I built it.
The setup
- AWS EC2 instance (free tier, Amazon Linux)
- Domain purchased on Cloudflare pointing to an Elastic IP
- Fresh server, nothing installed yet
Step 1 — Install Nginx
Apache is fine, but for serving static files Nginx is simpler and lighter.
sudo dnf install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
Check it’s running:
sudo systemctl status nginx
# Active: active (running) ✓
Step 2 — Install Hugo
Hugo isn’t in Amazon Linux’s default repositories, so install it manually:
wget https://github.com/gohugoio/hugo/releases/download/v0.145.0/hugo_0.145.0_linux-amd64.tar.gz
tar -xzf hugo_0.145.0_linux-amd64.tar.gz
sudo mv hugo /usr/local/bin/
rm hugo_0.145.0_linux-amd64.tar.gz LICENSE README.md
hugo version
Hugo is a static site generator — it takes Markdown files and converts them into a complete HTML website in milliseconds. No database, no PHP, no runtime dependencies.
Step 3 — Create the site and theme
cd ~
hugo new site lucianosblog
cd lucianosblog
hugo new theme luciano
Hugo generates the folder structure automatically. The theme goes in themes/luciano/layouts/ — from there you control every page with plain HTML templates.
I built a custom dark theme from scratch: fixed navigation, animated hero section, category grid, article cards, and a footer with social links. The CSS is around 120 lines.
Step 4 — Configure Nginx to serve Hugo
Tell Nginx where Hugo puts its generated files:
sudo tee /etc/nginx/conf.d/lucianosblog.conf << 'EOF'
server {
listen 80 default_server;
server_name _;
root /path/to/your/site/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
EOF
sudo nginx -t && sudo systemctl reload nginx
Build the site and test locally:
hugo build
curl -I http://localhost
# HTTP/1.1 200 OK ✓
Step 5 — SSL with Let’s Encrypt
Cloudflare was set to Full (strict) mode — which requires a valid certificate on the server. Without it, you get a 521 error.
sudo dnf install certbot python3-certbot-nginx -y
sudo certbot --nginx -d lucianosblog.com -d www.lucianosblog.com
Certbot detects your Nginx config automatically, gets the certificate from Let’s Encrypt, and updates the config to redirect HTTP to HTTPS. The whole thing takes about 60 seconds.
The result
A live blog at lucianosblog.com with:
- Static HTML served by Nginx — loads in under 200ms
- HTTPS with auto-renewing Let’s Encrypt certificate
- Custom dark theme with mobile support
- Total monthly cost: $0 (AWS free tier)
If you found this useful or have questions, connect with me on LinkedIn.