Fly.io is different from traditional hosting. When you deploy with Fly, your app runs simultaneously
across multiple regions — ord in Chicago, ams in Amsterdam, sin
in Singapore. That's a superpower for latency. It also means a single uptime monitor pointed at one
location gives you a false sense of security.
This guide walks through setting up comprehensive monitoring for your Fly.io app using Nines. Full disclosure: Nines itself runs on Fly.io. This is the exact setup we use.
Why Fly.io Apps Need Multi-Region Monitoring
Fly routes each user's request to the nearest healthy region. If machines in a region go unhealthy, Fly will attempt to route around it — but "attempt" is doing a lot of work in that sentence. DNS propagation delays, anycast anomalies, and resource exhaustion can be region-specific. A memory leak might only exhaust the smaller instance class you're running in a secondary region. BGP routing anomalies can make your app unreachable from certain geographies while other regions stay clean.
Your users in Singapore need the same monitoring coverage as your users in Chicago. A monitor that only checks from one location will miss regional failures that real users are hitting right now.
Step 1: Add a Health Check Endpoint
Before setting up external monitoring, give your monitors something precise to check. A dedicated
health endpoint returns 200 OK when the app process is alive and ready — not just
when the load balancer is responding.
In Go, this is three lines:
mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
If your app has downstream dependencies (database, cache), you can expand this to check them too —
return 503 if any are unreachable. Keep the check fast: under 100ms. Fly's own
[http_service] checks block in your fly.toml can point at the same
endpoint, so internal and external monitoring stay in sync.
Add the route before you deploy. Once it's live, you have a reliable signal to monitor.
Step 2: Create a Nines Account and Add Your HTTP Monitor
Sign up for Nines free. Once you're in, add an HTTP monitor for
your Fly app's primary URL — either your .fly.dev subdomain or your custom domain if
you've configured one.
When you create the monitor, select monitoring regions that match where your Fly app is deployed.
If you're running machines in ord, ams, and sin, monitor
from those same regions. A failure in Amsterdam shows up immediately — you're not waiting for a
US-based monitor to detect a European outage.
The free tier checks every 5 minutes from 2 regions. Pro checks every 1 minute from 5 regions. For a production app, 1-minute checks are worth it — 5 minutes is a long time for users to be hitting a broken endpoint before you know about it.
Step 3: Monitor Your Health Check Endpoint Specifically
Add a second monitor pointing at https://your-app.fly.dev/healthz (or whatever
path you chose). This is more precise than monitoring the root URL.
Monitoring the root URL tells you that something is responding. Monitoring your health endpoint tells you that the app process is alive, connected, and ready to handle requests. These can diverge: a CDN cache can serve your root page long after the app process has crashed, while your health endpoint will correctly return a failure. Two monitors, two distinct signals.
Step 4: Add SSL Monitoring
Fly handles TLS automatically via Let's Encrypt for .fly.dev subdomains. For custom
domains, you provision the certificate yourself through fly certs add — and that's
where things can go wrong.
Certificates expire. DNS challenges fail silently. Custom domain cert provisioning can get into a stuck state that Fly doesn't surface clearly. Add an SSL monitor in Nines for your domain and you'll get an alert:
- When the certificate is within 14 days of expiry
- When the cert chain is invalid or untrusted
- When the domain no longer resolves to a valid cert
This matters especially if you've got multiple custom domains across multiple Fly apps. It's easy to lose track of cert expiry across a fleet of apps. SSL monitoring catches it before your users get a browser security warning.
Step 5: Set Up a Public Status Page
In Nines, all your monitors automatically appear on your status page at
nines.sh/status/your-org. There's nothing to configure — add monitors, get a
status page. On Business plans you can also point a custom subdomain (like
status.yourcompany.com) at your status page via CNAME.
If you're running multiple Fly apps or have distinct components (API, background workers, webhooks), add monitors for each. They all appear on the same status page, so users get a single place to check when something feels off. Add the status page link to your app footer and your docs — the value compounds every time a user checks it during an incident instead of opening a support ticket.
The status page shows 90-day uptime history per monitor. That track record matters when you're selling to teams that care about reliability. Showing a clean history with well-handled incidents is more credible than no history at all.
Step 6: Configure Alerts
Connect Discord or Slack in Nines' notification settings. When any monitor flips to failing, you'll get an alert within the minute. When it recovers, you'll get a recovery notification — no need to keep checking manually.
One thing worth understanding: Fly's internal alerting is about machine health — whether the VM
is running, whether it's passing internal health checks, whether it has enough memory. That's
different from what Nines checks. Nines monitors the external network path: whether your app is
reachable from the public internet, whether it's returning the right status code, whether the
SSL cert is valid. These are complementary signals. Fly's internal alerts can't detect that a
network path from Singapore is timing out, or that your cert is 10 days from expiring, or that
your /healthz endpoint is returning 500 even though the machine is "up."
Putting It Together
Here's the complete monitoring setup for a Fly.io app:
- HTTP monitor on your root URL, checking from regions matching your Fly deployment
- HTTP monitor on
/healthz, same regions - SSL monitor on your custom domain (if applicable)
- Status page shared in your app footer and docs
- Discord or Slack alert for immediate notification on failure
This is exactly how Nines monitors itself. We run on Fly.io — primary region ord,
with machines in additional regions — and Nines' own monitors alert us the moment any region
shows a problem. If we break it, we know before our users do.
Sign up for Nines free. The setup takes about five minutes and you'll have multi-region monitoring running before your next deploy.