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
-c 4limits the ping to 4 packets instead of running indefinitely, which is important in scripts (you don’t want to hang forever waiting forCtrl+C).
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
-W 2sets a 2-second timeout for a response, so the check fails fast instead of hanging.> /dev/null 2>&1suppresses both standard output and error output, since we only care about the exit status.$?(implicitly checked by theif) is 0 if the ping succeeded, non-zero otherwise.
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
-ztellsncto just scan for a listening service without sending any actual data.-vgives verbose output so you can see the result clearly.
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
-w 3sets a 3-second timeout for the connection attempt.
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
-sruns silently, suppressing the progress meter.-o /dev/nulldiscards the response body since we only care about the status code.-w "%{http_code}"prints just the HTTP status code returned.
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
--max-time 5ensures the request gives up after 5 seconds rather than hanging indefinitely on a slow or dead connection.
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
- Always set timeouts (
-W,-w,--max-time) on network checks in scripts, since an unresponsive host without a timeout can hang your script indefinitely. - Check the exit status (
$?or theifconstruct directly) rather than parsing human-readable text output, which can change between tool versions. - Distinguish between checking basic reachability (ping), a specific service (nc), and an actual application-level response (curl) — they answer different questions.
- Build retries with exponential backoff for transient network issues rather than failing immediately on the first failed check.
- Log connectivity check results with timestamps so you can spot patterns (e.g., failures that correlate with a specific time of day).
Security Considerations
- Be mindful that
pingand port scans can be flagged by intrusion detection systems on networks you don’t control; only test hosts you have permission to check. - Avoid embedding sensitive endpoint URLs or credentials directly in connectivity-check scripts that might be logged or shared.
- When checking HTTPS endpoints with
curl, avoid using-k/--insecure(which skips certificate validation) in production scripts, since this defeats the purpose of using HTTPS in the first place. - Rate-limit your own health checks so you don’t inadvertently cause load issues on services you’re monitoring, especially if checks run very frequently.
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
- Not setting a timeout on network checks, causing scripts to hang on unreachable hosts.
- Relying solely on
pingwhen the actual concern is whether a specific application or port is reachable. - Ignoring the difference between local network and internet connectivity when diagnosing “network is down” reports.
- Hardcoding IP addresses instead of hostnames, which breaks if the underlying infrastructure changes.
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.
