DEV Community

upordown.online
upordown.online

Posted on

Ping is not an uptime check: 5 ways ICMP lies about whether your site is up

The monitor said the server was up: 0% packet loss, 12 ms round trip. The site had been returning 502 Bad Gateway for forty minutes. Nobody got paged, because the uptime check was a ping.

The opposite happens too. A team moves behind a cloud firewall, ping starts timing out, and the pager goes off at 3 AM for a site that is serving traffic perfectly well.

TL;DR

  • Ping tests whether a host answers ICMP echo. Users don't use ICMP. They use DNS, TCP, TLS and HTTP.
  • Ping can be green during a full outage and red during perfect health.
  • For uptime, check an HTTP request to a real page, with a timeout and a content check.
  • My opinion: ping-based uptime monitoring for websites should be retired. Use it only as a diagnostic.

Lie 1: the host is up, the app isn't

Ping is answered by the operating system kernel. Your web server, app runtime, database and reverse proxy can all be dead and the kernel will still reply in milliseconds.

$ ping -c 3 203.0.113.10
3 packets transmitted, 3 received, 0% packet loss
$ curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/
502
Enter fullscreen mode Exit fullscreen mode

That's the most common lie, and the most expensive one.

Lie 2: ICMP is blocked, the site is fine

Many cloud providers, firewalls and CDNs drop ICMP by default. Some security policies require it. Ping then reports 100% loss for a host serving millions of requests.

$ ping -c 3 example.com
3 packets transmitted, 0 received, 100% packet loss
$ curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/
200
Enter fullscreen mode Exit fullscreen mode

If your monitoring can't tell these two apart, it trains people to ignore alerts.

Lie 3: you're pinging the CDN, not your server

When a site sits behind a CDN, its DNS points at an edge node near you. Pinging the domain tells you that edge is reachable. It says nothing about whether the edge can reach your origin. Origin failures show up as CDN-branded error pages, which ping will never see. If you're on Cloudflare, those show up as 521, 522 and 523, explained in Cloudflare errors 521, 522 and 523 explained in plain words.

Lie 4: latency numbers that don't match user experience

Routers often deprioritise ICMP. A ping of 300 ms can coexist with fast page loads, and a ping of 20 ms can coexist with 8-second TLS handshakes because the server is overloaded. ICMP latency measures the network path to the box, not the time to first byte.

Measure what users wait for:

curl -sS -o /dev/null --max-time 15 -w \
'dns:     %{time_namelookup}s
connect: %{time_connect}s
tls:     %{time_appconnect}s
ttfb:    %{time_starttransfer}s
total:   %{time_total}s
code:    %{http_code}
' https://example.com/
Enter fullscreen mode Exit fullscreen mode

If connect is fast and ttfb is slow, the network is fine and the app is struggling. Ping would never tell you that.

Lie 5: IPv4 is fine, IPv6 is broken

ping usually picks one address family. Many users' devices prefer IPv6. If your AAAA record points at a misconfigured listener, a chunk of users get timeouts while your IPv4 ping looks perfect.

curl -4 -sS -o /dev/null -w 'v4 %{http_code}\n' https://example.com/
curl -6 -sS -o /dev/null -w 'v6 %{http_code}\n' https://example.com/
Enter fullscreen mode Exit fullscreen mode

Mobile networks are often IPv6-first, which is one reason a site can work on Wi-Fi but fail on mobile data.

What a real uptime check looks like

Here's a minimal check in Python that you could run from cron or a CI job:

import sys, time, urllib.request

URL = "https://example.com/"
KEYWORD = b"Sign in"

start = time.time()
try:
    req = urllib.request.Request(URL, headers={"User-Agent": "uptime-check/1.0"})
    with urllib.request.urlopen(req, timeout=10) as r:
        body = r.read(200_000)
        code = r.status
except Exception as e:
    print(f"DOWN {URL} error={e!r}")
    sys.exit(2)

elapsed = time.time() - start
if code != 200 or KEYWORD not in body:
    print(f"DOWN {URL} code={code} keyword_found={KEYWORD in body}")
    sys.exit(2)
print(f"UP {URL} code={code} {elapsed:.2f}s")
Enter fullscreen mode Exit fullscreen mode

It covers DNS, TCP, TLS, HTTP status and content in one request. It's still a single location, though, which brings its own problem: your vantage point. If you've ever argued with a teammate about whether something is down, How to check if a website is down for everyone or just you goes through how to separate "my network" from "the site". A public checker like upordown.online gives you a second opinion from outside your own network.

When ping is still useful

I'm not saying uninstall it. Ping is a good diagnostic:

  • Is the host reachable at all at the network layer?
  • Is there packet loss on the path? (mtr example.com is better.)
  • Did a firewall change just drop ICMP? (Useful to know, not an outage.)

Just don't wire it to a pager for a website.

My take

"Up" should mean "a user can complete the thing they came to do". For most sites that's an HTTP request returning the right content within a few seconds. Anything lower in the stack is a hint, not a verdict. If you set up a health endpoint for this, read the mistakes in the previous post on health checks first, because a lazy /health route has the same problem as ping, just one layer higher.

Over to you

Is anyone still running ping-based uptime alerts in production, and if so, what's the reason? I'm curious whether there's a good use case I'm missing, especially for non-HTTP services.

Top comments (0)