
Why I Built a Blog in 2026
The actual reasons a cloud engineer builds a static blog from scratch instead of using an existing platform. Spoiler — it is mostly about control.
Why I Built a Blog in 2026
Everyone asks the same question: "Why not just use Substack? Ghost? Medium?"
Fair question. Here's the real answer.
Control over the stack
I'm a cloud engineer. I have strong opinions about infrastructure.
A platform gives you a URL and a CMS. That's fine. But it also gives you:
- A tracking pixel you didn't ask for
- A dependency on their CDN configuration
- No control over cache headers
- Zero ability to add custom response headers
My setup (plain Terraform, not CDK — I wanted the state file, not an abstraction on top of it):
# infra/terraform/cloudfront.tf
resource "aws_cloudfront_distribution" "site" {
is_ipv6_enabled = true
http_version = "http2and3"
price_class = var.price_class # PriceClass_200 — includes India edge locations
origin {
domain_name = aws_s3_bucket.site.bucket_regional_domain_name
origin_access_control_id = aws_cloudfront_origin_access_control.site.id
}
default_cache_behavior {
viewer_protocol_policy = "redirect-to-https"
compress = true
response_headers_policy_id = aws_cloudfront_response_headers_policy.security.id
}
}Cost
This blog costs approximately $0.50–$1.00 per month at zero traffic.
That's:
- S3: ~$0.023/GB stored — negligible for HTML + fonts
- CloudFront: first 1TB/month free, then $0.0085/GB in India region
- Route 53: $0.50/hosted zone/month — that's the biggest line item
The build is the product
Shipping the blog is the content, at least for the first few months.
Writing about how the site is built while building it creates a feedback loop: I can't cut corners on the infrastructure if I'm going to write about it.
Security defaults I care about
Every response gets:
Strict-Transport-Security: max-age=63072000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()
No CDN fonts. No analytics scripts. No cookies at all in v1. I'll add a cookieless analytics option later if I want numbers.
Content-Security-Policy is still on the TODO list, not a header I can claim yet. React Router inlines a hydration script and the theme-toggle script inlines too, so a strict policy needs their SHA-256 hashes before it can ship without breaking the site.
Performance targets
Lighthouse ≥ 95 across all four categories. CLS = 0.
The only JavaScript served is the React hydration bundle and the theme toggle. Both are small.
Fonts are self-hosted via @fontsource, so there are no third-party network requests.
What's the catch?
Authoring is slightly more friction than a hosted platform. To publish a post:
- Write an
.mdxfile incontent/posts/ - Run
infra/terraform/scripts/deploy.sh— builds, syncs to S3 with the right cache headers, invalidates CloudFront
That's two steps and about a minute, no CI involved yet. A GitHub Actions deploy role
is already in the Terraform (github_oidc.tf) for whenever I wire the workflow up —
I've shipped worse deploy pipelines at real jobs even with that in place.