AWS · Azure · GCP · OCI · all Terraform
This portfolio is not a screenshot of a multi-cloud diagram. It is served live by AWS, Azure, Google Cloud and Oracle Cloud, rotating between them every couple of days, each with its own AI chatbot, and with guardrails that keep the whole thing honest about cost.
The mechanism
cloud.albaker.info has four weighted DNS records, one per cloud. Route 53 answers in proportion to the weights, so setting one cloud to 100 and the rest to 0 sends every new visitor there. Each cloud also keeps a permanent name of its own (azure., gcp., oci.albaker.info), so any one of them can be checked directly at any time.
The rotation
A scheduled GitHub Actions workflow flips the weights at 00:00 UTC on those days. It changes only the four DNS records, nothing else, and sends an alert for every rotation. A manual run can point all traffic at any one cloud in under a minute, which doubles as a disaster-recovery drill.
DNS caching is the enemy of active/active. A one-minute TTL means a flipped weight is fully live within a minute. The cost is a few more DNS queries, which at this traffic is pennies.
Each cloud holds traffic long enough for browser and CDN caches to warm, so a returning visitor sees a consistent site instead of a different cloud on every click.
HTTPS health checks probe each cloud every 30 seconds. Three failures in a row and Route 53 stops answering with that cloud, whatever its weight, so the others absorb traffic in about 90 seconds with no one touching anything.
AWS, Azure and Google Cloud have health-check failover today. Oracle Cloud does not yet, so an OCI outage during OCI's turn would need a manual flip. Adding its probe is next on the list.
Same page, four stacks
| Layer | AWS | Azure | Google Cloud | Oracle Cloud |
|---|---|---|---|---|
| Hosting + CDN | S3 (private) + CloudFront | Static Web Apps | Firebase Hosting | Object Storage + API Gateway |
| TLS | ACM wildcard | Managed by SWA | Managed by Firebase | Let’s Encrypt via Terraform |
| Chatbot compute | Lambda | SWA managed Functions | Cloud Run functions | OCI Functions |
| Language model | Bedrock · Claude Sonnet | Azure OpenAI · GPT-4o mini | Vertex AI · Gemini 2.5 Flash | Generative AI · xAI Grok |
| Session + limits | DynamoDB | Cosmos DB serverless | Firestore | NoSQL Database |
| CI identity | OIDC role | OIDC federation | Workload Identity | Scoped API user |
The chatbot keeps a short conversation history per browser tab, stored on the cloud that is serving it, expired after an hour, and never shared between visitors. Each provider wants messages in a different shape, so each function converts at the point it calls the model and stores one common format.
Guardrails
Deploys to AWS, Azure and GCP use short-lived OIDC tokens from GitHub Actions. OCI uses a tightly scoped API user, not an admin key.
Plan jobs are read-only. Apply jobs cannot change their own permissions. Changing what CI may do is always a reviewed, local apply.
GuardDuty threat detection and IAM Access Analyzer are on, and the AWS account refuses API calls outside its one region, so a leaked credential cannot quietly build elsewhere.
HSTS, anti-framing and a content-security policy on AWS, Azure and GCP; OCI’s gateway is next. Geo-restriction is enforced at the CDN edge on AWS; the other three run it in the function, in log mode while the lookups are validated, because their free tiers have no edge option.
Per-visitor and daily limits on every chatbot. If the counter cannot be read, the request is refused: a briefly unavailable chat costs nothing, an unbounded one costs real money.
Budgets with alerts on every cloud. On AWS, crossing the hard limit automatically applies a policy that stops new paid activity, without waiting for me to read an email.
Delivered as code
Terraform plans each changed cloud and posts a summary of what would be added, changed or destroyed, so a reviewer reads the infrastructure change next to the code change.
Merging applies the plan made on main, never a stale one from the branch. One apply per cloud at a time, so two merges cannot race each other. The DNS stack and OCI apply through a deliberate manual step instead, because a mistake there takes the whole site down.
Any plan that would delete or replace a resource stops until the pull request carries an explicit label. Routine changes flow; destructive ones need a decision.
A smoke test after each deploy checks real responses, not just status codes, and an independent health check fails loudly if the monitoring itself goes quiet.
Trade-offs
Azure Front Door or a Google load balancer with Cloud Armor would add edge security on those clouds, for tens to hundreds of dollars a month. At portfolio traffic, the function-level check gives the same protection for $0. With real customers, I would buy the edge.
Weighted DNS with health checks is cheap and transparent. Its limit is client caching; a production system with strict failover targets would put an anycast front door ahead of it.
The bill
A nightly job pulls each cloud’s spend into a public dashboard. Publishing the real number is a small act of FinOps practice and a forcing function: any line that grows has to justify itself in public.
See the live cost dashboardNext step
Multi-cloud that actually fails over, CI that cannot grant itself more power, and a bill that never surprises anyone. I build and run this one myself, and it is all Terraform you can read in a pull request.
Start a conversation See the AgentCore platform