gazetteer.krisgrzepka.com / infrastructure
A PHP and Apache container that had stopped working — three of its upstream APIs were dead or paywalled, and a free-tier host added twelve seconds to the first request. It now runs serverless, and the frontend never learned that anything changed.
A visitor
Opens the map and picks a country
Route 53
A subdomain on an existing hosted zone
Alias to CloudFront — no extra lookup to pay for
ACM certificate
Issued and DNS-validated by Terraform during the first apply
us-east-1, because CloudFront reads certificates there
CloudFront
Two origins behind one domain: the site, and the API
Default behaviour caches; the API prefix does not
S3
The map, its tiles of country geometry, and the vendor scripts
Public access blocked — only CloudFront can read it, via OAC
Fetching a file from the live site to time the real path…
The page asks for a country
Borders, weather, local time, Wikipedia, cities, earthquakes
Still calls /libs/php/*.php — the paths never changed
CloudFront behaviour
One path prefix is sent to a second origin instead of the bucket
This is why no frontend code had to be rewritten
Lambda
Fourteen PHP scripts folded into one handler that routes on the filename
Node.js 20, no npm dependencies — no build, no supply chain
CloudWatch
Upstream failures are logged with the endpoint that caused them
Retention set in Terraform — logs cannot grow a bill
Public data providers
Geography, weather, time zones and points of interest
Keys live in Lambda environment variables, never in the browser
Calling a live endpoint to time the real path…
/libs/php/* meant the entire backend could be replaced without touching a line of frontend code. The migration's blast radius was one Terraform file.