AWS Builder Center

Article #6 is ready — setting up CloudWatch monitoring, billing alarms, and error-rate alerts for the pipeline.

How I added monitoring to my S3 + CloudFront static site using CloudWatch — billing alarms, 4xx/5xx error rate tracking, SNS email notifications, and the regional quirks that tripped me up along the way.

Setting Up Monitoring and Alerts for My Static Site with CloudWatch

Everything in this series so far has been about building the pipeline: hosting, HTTPS, automated deploys, staging. What I didn't have was any way to know if something actually broke — the only way I'd find out my site was down was by visiting it myself. This article covers closing that gap with CloudWatch: tracking CloudFront errors, setting a billing alarm, and getting notified by email when something needs attention.

Why This Matters More Than It Seems

For a personal project, "just check the site occasionally" feels like enough — until it isn't. A few scenarios this setup is actually meant to catch:
  • CloudFront starts returning a wave of 5xx errors because the S3 origin became unreachable (e.g., a bucket policy got accidentally tightened)
  • A misconfigured CloudFront Function or cache behavior causes 4xx errors for legitimate requests
  • Costs creep up unexpectedly — a runaway invalidation loop, or traffic far beyond what the Free Tier covers
None of these are hypothetical for a project like this; they're exactly the kind of thing a misconfigured IAM policy or a bad deploy could quietly cause.

The Pieces Involved

  1. CloudWatch Metrics — CloudFront and billing data, mostly collected automatically
  2. CloudWatch Alarms — thresholds that trigger when something looks wrong
  3. SNS (Simple Notification Service) — delivers the actual email when an alarm fires
  4. CloudWatch Dashboard — a single place to glance at the health of everything

Step 1: Enable Billing Alerts

This isn't on by default. In the Billing and Cost Management console, under Billing Preferences, I enabled "Receive CloudWatch Billing Alerts." This is a one-time account-level setting — without it, billing metrics never show up in CloudWatch at all, which tripped me up initially since I went straight to creating the alarm and couldn't find the metric.
A detail worth knowing: billing metrics are only available in the us-east-1 region, regardless of where your other resources live — the same regional quirk I ran into with ACM certificates for CloudFront.

Step 2: Create an SNS Topic for Notifications

Before setting up any alarms, I created an SNS topic (site-alerts) and subscribed my email address to it. AWS sends a confirmation email that has to be clicked before the subscription is active — easy to forget, and the alarms will fire silently into the void if you skip it.

Step 3: Set a Billing Alarm

With billing alerts enabled, I created a CloudWatch alarm on the EstimatedCharges metric:
  • Threshold: greater than a dollar amount I chose as a sane ceiling for a project this size
  • Period: checked once every 6 hours, since billing data doesn't update in real time anyway
  • Action: notify the site-alerts SNS topic
This is the single highest-value alarm in this whole setup. Everything else is about availability; this one is about making sure a mistake doesn't turn into a surprise invoice.

Step 4: Monitor CloudFront Error Rates

CloudFront automatically reports metrics like 4xxErrorRate and 5xxErrorRate as a percentage of total requests. I created two alarms:
  • 5xx error rate > 5% over a 5-minute period — this usually means the origin (S3) is failing to serve content, which is the "something is actually broken" signal
  • 4xx error rate > 10% over a 15-minute period — a softer signal, since some 4xx traffic (bad bots probing for paths) is normal background noise, but a sustained spike can mean a broken link or misconfigured redirect
I set the 5xx alarm's evaluation to trigger after 2 consecutive breaching periods rather than a single one, specifically to avoid getting paged for a brief blip that resolves itself — a single failed request during a CloudFront edge location hiccup isn't worth an email at midnight.

Step 5: Build a Simple Dashboard

Rather than digging through separate metric pages, I put together one CloudWatch dashboard with:
  • CloudFront requests over time
  • 4xx and 5xx error rates, side by side
  • Estimated monthly charges
  • Cache hit rate (a good proxy for whether CloudFront is actually doing its job efficiently)
This isn't strictly necessary — the alarms would notify me regardless — but having a single glance-able view made it much easier to understand what "normal" looks like, which in turn makes it easier to set sane alarm thresholds instead of guessing.

What I Got Wrong Initially

  • My first 5xx alarm threshold was set far too low (greater than 0%), which meant it fired on essentially any single failed request, including ones caused by my own testing. I had to recalibrate based on a few days of actual baseline data before the alarm became genuinely useful instead of just noisy.
  • I initially created the billing alarm in my site's primary region and couldn't find the EstimatedCharges metric at all — it only exists in us-east-1, which cost me more time than it should have to figure out.
  • I forgot to confirm the SNS email subscription, and spent a while confused about why a deliberately-triggered test alarm never actually emailed me.

A Note on Alarm Fatigue

It's tempting to alarm on everything once you see how easy it is to set one up. I'd push back on that instinct, including for myself: an alarm that fires too often — or fires on things that don't actually require action — trains you to ignore it, which defeats the entire purpose. I'd rather have three alarms I trust than fifteen I've learned to dismiss.

What I Learned

Observability is a separate skill from building the thing. Everything in this pipeline worked before I added any of this — monitoring doesn't make the system function, it makes failures visible. That's a genuinely different kind of design thinking than the infrastructure work in the earlier articles.
Alarm thresholds need real data, not guesses. My first instinct for every threshold was wrong in one direction or another. There's no substitute for watching the dashboard for a few days before deciding what "abnormal" actually means for your specific traffic pattern.
Regional quirks keep showing up in the same shape. ACM-for-CloudFront, billing metrics — both us-east-1-only, both easy to miss. Worth remembering as a pattern rather than relearning it each time.

What's Next

I think the natural next step for this series is stepping back from this one project and looking at a different AWS domain entirely — possibly a small serverless API with Lambda and API Gateway, to start building toward something more dynamic than a static site.
If you've got alarm thresholds that work well for a similar low-traffic static site, or think I'm over-monitoring a project this small, I'd like to hear your take.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article