How AI is applied across API Evangelist and APIs.io. Read my AI disclosure →
API Evangelist API Evangelist
Discovery
Learnings
Guidance
Toolbox
Alignment
API Evangelist LLC

Deploying blogs.apievangelist.com

This site is no longer hosted on GitHub Pages. With ~111k aggregated posts, the github-pages hosted runner OOMs during Jekyll’s read phase, so the site is built locally and synced to S3 + CloudFront (in AWS account 007596076917, us-east-1).

  • Infrastructure: BlogsSiteStack in api-evangelist/apievangelist-aws — S3 bucket blogs.apievangelist.com (private, OAC) behind CloudFront EDFO4PRAM0OC3 (d5e4ib1wlxlas.cloudfront.net), with a clean-URL CloudFront Function and a DNS-validated ACM cert for blogs.apievangelist.com.
  • DNS: Cloudflare, DNS-only (grey cloud) CNAME → the CloudFront domain — same as api./mcp.apievangelist.com. A proxied record causes an HTTP→HTTPS redirect loop.

Build + deploy

From the apievangelist-aws repo (needs the 128 GB machine + Homebrew Ruby — the chruby ruby links a stale libruby and can’t load native gems):

BUCKET=blogs.apievangelist.com DIST=EDFO4PRAM0OC3 ./scripts/deploy-blogs.sh
# SKIP_BUILD=1 ... to sync an already-built _site without rebuilding (~16 min build)

That builds Jekyll, aws s3 syncs _site to the bucket, and invalidates CloudFront.

The blog list is served as shards, not one JSON

The list page (index.html) is client-side rendered. Shipping all ~111k posts as one ~32MB assets/blogs-data.json left the list blank for a minute-plus — CloudFront won’t auto-compress objects over 10MB, so it was served raw. deploy-blogs.sh now runs scripts/build-blog-shards.py, which splits the built monolith into date-ordered 2,000-post shards plus manifest.json and providers.json under assets/blogs/, all uploaded gzip-encoded. The client fetches only the newest shard on first paint (~100KB) and pulls older/other shards on demand (a “Since” date maps to a contiguous prefix; provider/keyword search progressively loads what it needs). The monolith is no longer served.