How to Check Network Connectivity in Bash

How to Check Network Connectivity in Bash

How to Check Network Connectivity in Bash

A few years ago I was debugging a deployment pipeline that kept failing intermittently, and it took embarrassingly long to realize the root cause was a flaky network connection to a remote API, not a bug in the code itself. Since then, checking network connectivity has become one of the first things I build into any script that depends on an external service — a database, an API, a remote server, or even just the internet in general.

This guide covers the practical ways to check network connectivity in Bash, from simple ping tests to more advanced port and DNS checks, along with how to build these checks into resilient automation scripts.

Why Network Connectivity Checks Matter

Scripts that assume network access is always available tend to fail in confusing ways — a hung curl request, a cryptic timeout, or a script that silently proceeds with no data. Building explicit connectivity checks into your scripts means you fail fast, with a clear error message, instead of leaving whoever’s watching to guess what went wrong.

The Basic Tool: ping

The most familiar way to check if a host is reachable is ping, which sends ICMP echo requests and waits for a response.

ping -c 4 google.com

Output looks like:

PING google.com (142.250.premises.14): 56 data bytes
64 bytes from 142.250.premises.14: icmp_seq=0 ttl=113 time=12.4 ms
64 bytes from 142.250.premises.14: icmp_seq=1 ttl=113 time=11.8 ms
...
--- google.com ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss

To use this in a script and check success programmatically, rely on the exit status rather than parsing the text output:

if ping -c 1 -W 2 google.com > /dev/null 2>&1; then
  echo "Network is up"
else
  echo "Network is down"
fi

Keep in mind that some networks and firewalls block ICMP traffic entirely, so a failed ping doesn’t always mean the host is actually unreachable — it might just mean ICMP is blocked while the actual service (like a web server) is perfectly reachable.

Checking Specific Ports with nc (netcat)

Since ping only tests basic reachability, not whether a specific service is actually listening, nc (netcat) is a better tool when you care about a specific port — for example, checking if a database or web server is actually accepting connections.

nc -zv google.com 443

Output:

Connection to google.com port 443 [tcp/https] succeeded!

For scripting purposes:

if nc -z -w 3 db.example.com 5432 2>/dev/null; then
  echo "Database port is reachable"
else
  echo "Cannot reach database port"
fi

This is far more accurate than ping when you specifically care about whether an application (not just the host) is reachable.

Using curl to Check HTTP/HTTPS Endpoints

For web services and APIs, curl is often the most practical tool, since it tests the actual protocol you care about rather than just low-level connectivity.

curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health

You can wrap this in a script for a clean pass/fail check:

status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 https://api.example.com/health)

if [ "$status" -eq 200 ]; then
  echo "API is healthy"
else
  echo "API returned status: $status"
fi

Checking DNS Resolution

Sometimes the network itself is fine, but DNS is broken — a surprisingly common cause of “the internet is down” reports. You can test DNS resolution specifically using dig or nslookup:

dig +short google.com

This returns just the resolved IP address(es):

142.250.premises.14

If this returns nothing, DNS resolution is failing even if the network itself is otherwise working — a very useful distinction when troubleshooting.

For a scriptable check:

if dig +short google.com | grep -q '.'; then
  echo "DNS resolution working"
else
  echo "DNS resolution failed"
fi

Checking Internet Connectivity vs. Local Network

It’s important to distinguish between local network connectivity (your gateway/router) and actual internet access, since these can fail independently.

# Check gateway (local network)
gateway=$(ip route | awk '/default/ {print $3}')
if ping -c 1 -W 2 "$gateway" > /dev/null 2>&1; then
  echo "Local network OK"
else
  echo "Local network problem — cannot reach gateway"
fi

# Check external connectivity
if ping -c 1 -W 2 8.8.8.8 > /dev/null 2>&1; then
  echo "Internet connectivity OK"
else
  echo "Internet connectivity problem"
fi

Here, ip route | awk '/default/ {print $3}' extracts the default gateway’s IP address from the routing table, so you can test connectivity to your router separately from testing broader internet access. If the gateway check fails but the router is otherwise visibly working, the issue is more likely with your own network interface configuration; if the gateway succeeds but the internet check fails, the problem lies further upstream (ISP, or a broader outage).

Building a Complete Connectivity Check Script

Here’s a script I use that combines several of these checks into a single health report:

#!/bin/bash
set -uo pipefail

check_host() {
  local host="$1"
  local port="$2"
  if nc -z -w 3 "$host" "$port" 2>/dev/null; then
    echo "OK: $host:$port is reachable"
    return 0
  else
    echo "FAIL: $host:$port is not reachable"
    return 1
  fi
}

check_dns() {
  local domain="$1"
  if dig +short "$domain" | grep -q '.'; then
    echo "OK: DNS resolution for $domain succeeded"
    return 0
  else
    echo "FAIL: DNS resolution for $domain failed"
    return 1
  fi
}

echo "Running network connectivity checks..."
check_dns "google.com"
check_host "google.com" 443
check_host "db.example.com" 5432
check_host "api.example.com" 443

echo "Checks complete."

Each function returns a clear pass/fail status and prints a readable message, making this easy to plug into a monitoring cron job or a pre-deployment health check.

Real-World Use Cases

1. Pre-deployment checks. Before deploying, verifying that the database, cache, and any third-party APIs are reachable prevents deployments from failing halfway through due to a network issue unrelated to the code itself.

2. Monitoring and alerting. A cron job that periodically checks critical endpoints and sends an alert (email, Slack webhook) if any of them become unreachable.

3. CI/CD pipeline reliability. Retrying network-dependent steps (like downloading dependencies) with a connectivity check first can distinguish between “the network is genuinely down” and “this particular request failed,” leading to smarter retry logic.

4. IoT and remote devices. Devices operating on unreliable networks (cellular, rural broadband) often need to detect connectivity loss and queue data locally until the connection is restored.

Best Practices

Security Considerations

Troubleshooting Common Issues

ping succeeds but the application still can’t connect: The host is reachable, but the specific port or service might be down, blocked by a firewall, or the application itself may have crashed. Use nc -zv to check the exact port.

curl request hangs indefinitely: Always add --max-time or --connect-timeout to prevent this. Without it, a stalled connection can block your script forever.

DNS resolution works with dig but not in your application: Check whether your application is using a different DNS resolver or a cached/stale entry — clearing your local DNS cache or checking /etc/resolv.conf can help isolate the issue.

Connectivity check passes locally but fails in CI: CI environments often have different network policies or egress restrictions than your local machine — check your CI provider’s documentation for any required network allowlisting.

Common Mistakes to Avoid

FAQs

Q: What’s the difference between checking with ping and nc? ping tests basic host reachability at the network layer (ICMP), while nc tests whether a specific port is actually open and accepting connections — much more relevant when you care about a particular service like a database or web server.

Q: Why does ping sometimes fail even though a website works fine in the browser? Many servers and firewalls block ICMP traffic (used by ping) for security reasons, even while normal web traffic on ports 80/443 works perfectly fine.

Q: How do I check network connectivity without any external tools like curl or nc? Bash has a built-in trick using /dev/tcp: timeout 3 bash -c "echo > /dev/tcp/google.com/443" attempts a raw TCP connection without needing any external binary, though it’s less flexible than dedicated tools.

Q: How can I retry a network check automatically if it fails? Wrap your check in a loop with a counter and a sleep between attempts, ideally increasing the delay each time (exponential backoff) to avoid hammering a struggling service.

Q: Is checking DNS resolution really necessary if the network is up? Yes — DNS failures are one of the most common causes of “the network is broken” issues, and they can happen independently of actual network connectivity, so it’s worth checking separately.

Summary

Checking network connectivity in Bash goes well beyond a single ping command. Understanding the difference between host reachability, port-level checks, DNS resolution, and application-level responses gives you the tools to diagnose network issues precisely instead of guessing. Building these checks into your deployment scripts, monitoring jobs, and CI pipelines turns vague, hard-to-diagnose failures into clear, actionable error messages.

References

Exit mobile version