How to diagnose a host you cannot reach¶
Use this guide when ssh, curl or another client on a Linux machine can't connect to a remote host and you need to find out where the connection breaks.
You work from the local machine outward: interface, address, route, gateway, name resolution, the path, the port, and finally the local firewall.
Each check either clears a layer or tells you where the fault is.
Before you begin¶
- You have a shell on the machine where the connection fails, and
sudorights. -
Write down the exact failure first: the command, the target, the port and the full error message. The error alone often points at a layer:
ssh: Could not resolve hostname app.example.com: Name or service not known <- name resolution ssh: connect to host 203.0.113.10 port 22: Network is unreachable <- local routing ssh: connect to host 203.0.113.10 port 22: No route to host <- gateway, neighbour or a reject rule ssh: connect to host 203.0.113.10 port 22: Connection timed out <- path or a firewall dropping packets ssh: connect to host 203.0.113.10 port 22: Connection refused <- nothing listening, or a reject rule -
The commands use these placeholders. Replace them with your own values:
Placeholder Meaning Example <TARGET>The name of the host you can't reach app.example.com<ADDRESS>The IP address you expect <TARGET>to have203.0.113.10<PORT>The TCP port of the service 22<INTERFACE>Your machine's network interface enp0s3<GATEWAY>Your default gateway 192.0.2.1<DNS_SERVER>A DNS server you are configured to use 192.0.2.53 -
Install the diagnostic tools used below (
dig,mtr,ncandnft) if they're missing:On these distributions
ncis Ncat, from the Nmap project. It accepts the options used in this guide.
Steps¶
-
Check that your interface is up and has an address:
Look for your interface in state
UPwith an address in the subnet you expect.DOWNorNO-CARRIERmeans a link problem: a cable, a virtual switch, or an interface that was never brought up. No IPv4 address usually means DHCP failed. Look at the error and drop counters too:Counters under
errorsordroppedthat grow each time you run the command point at the link or the driver. -
Ask the kernel which route it would use to reach the target address:
The output shows the gateway (
via), the outgoing interface (dev) and the source address (src). Check that they're the ones you expect.RTNETLINK answers: Network is unreachablemeans there is no route at all: usually a missing default route. If the target is on your own subnet, there is noviaand the packets go straight to the target. -
Check that the gateway answers:
If
pingfails, look at the neighbour entry.REACHABLEwith a link-layer address (lladdr) means the gateway answered ARP (or IPv6 neighbour discovery) just now, so it exists on the link even if it ignores pings.STALEmeans it answered at some point but hasn't been confirmed recently; runpingagain and recheck, and the entry should turnREACHABLE(orDELAYwhile it's being confirmed).FAILEDorINCOMPLETEmeans nothing on the link answers for that address: wrong gateway, wrong VLAN or subnet, or a link fault. -
Check that the name resolves, and to the address you expect:
getentresolves the name the way most programs do, through/etc/nsswitch.conf, so it includes/etc/hosts.digasks DNS only. If the two disagree, look for an entry in/etc/hosts. If neither returns an address, query a DNS server directly to separate "the resolver is unreachable" from "the record doesn't exist":In the
digoutput,status: NXDOMAINmeans the name doesn't exist on that server,status: SERVFAILmeans the server couldn't get an answer, andconnection timed out; no servers could be reachedmeans the DNS server itself is unreachable.Then check which DNS servers your machine uses:
These work when
systemd-resolvedis running, which is the default on Ubuntu and on Debian cloud images. Otherwise the servers are listed in/etc/resolv.conf.NetworkManager writes
/etc/resolv.conf.systemd-resolvedisn't installed by default; it's a separate package of the same name, soresolvectl(which comes withsystemd) reportsThe name is not activatable. Look at theIP4.DNSlines in thenmclioutput.These work when
systemd-resolvedis running. Ifresolvectl statuslists onlyFallback DNS Servers, the network configuration hasn't supplied any DNS servers and resolved is using its built-in fallbacks.With OpenRC,
systemd-resolvedisn't used. The DNS servers are in/etc/resolv.conf. For an interface configured withconfig_<INTERFACE>="dhcp"in/etc/conf.d/net, netifrc startsdhcpcd, and its20-resolv.confhook writes the file from the DHCP lease:With the systemd profile (not verified):
-
Trace the path towards the target:
Use the address rather than the name, so the trace works even if name resolution is broken.
mtrsends probes with increasing TTL values and lists each router that answers, with its packet loss and latency. Read it from the top: the last hop that answers, and the first hop after which every line shows???or 100% loss, bracket the place where packets stop. Loss shown at one intermediate hop but not at the hops after it is usually that router rate-limiting its replies, not real loss. -
Test the port itself:
If
ncisn't available, Bash can open a TCP connection itself:Read the result:
The wording depends on the tool: OpenBSD netcat (Debian, Ubuntu, Arch, Gentoo) prints
succeeded!,failed: Connection refusedortimed out; Ncat (RHEL family) printsConnected to,Connection refused.orTIMEOUT.; Bash printsConnection refused, or nothing whentimeoutstops it (exit status 124).- Succeeded or open: the network path and the service's listening socket are fine. The problem is in the application or its configuration (for example authentication, TLS or the HTTP response).
- Connection refused: nothing listens on that port, or a firewall rule on the target or along the path rejects the connection. Either way, routing works up to the point that answered.
- Timed out: packets are dropped somewhere, by a firewall on the target, on the path or on your own machine.
To see what a refusal looks like, test a port on your own machine that nothing listens on. This is the OpenBSD netcat output; Ncat prints
Ncat: Connection refused.: -
If you can reach the target another way (a console, or
sshfrom another host), check that the service listens on the expected address and port there:A service listening on
127.0.0.1only accepts connections from the target itself. It needs to listen on0.0.0.0,[::]or the target's own address to accept connections from you. -
Check your machine's own firewall rules:
Look for
droporrejectrules in output chains, or a restrictive output policy (policy drop), that match the target address or port. An empty output means no nftables rules are loaded.Rules created with
iptablesappear in this output only wheniptablesuses thenf_tablesbackend; they show up in tables namedip filterandip6 filter. Rules created with the legacy backend (iptables-legacy) don't appear, so list them as well:iptablesuses thenf_tablesbackend by default (sudo iptables -Vreportsnf_tables), so these rules also appear in thenftoutput; listing them here also catches rules added withiptables-legacy.iptablesisn't installed by default. The onlyiptablesavailable is thenf_tablesvariant (iptables-nft), whose rules already appear in thenftoutput. Iffirewalldis in use,sudo firewall-cmd --list-allshows its configuration in its own terms.iptablesuses thenf_tablesbackend by default (sudo iptables -Vreportsnf_tables), so these rules also appear in thenftoutput; listing them here also catches rules added withiptables-legacy.Run the same commands on the target, if you can, to check its input chains.
Verify¶
The diagnosis is complete when you can name the layer at which the connection fails, with the command output that proves it. After you fix the cause, run the client command that originally failed; it should now connect. Then repeat the port test from step 6:
Troubleshooting¶
pingfails butsshorcurlworks- Many hosts and firewalls drop ICMP echo requests.
A failed
pingproves nothing on its own; use the port test from step 6. - The name resolves with
getentbut not withdig(or the reverse) getentalso reads/etc/hostsand other sources in/etc/nsswitch.conf;digreads only DNS. An old/etc/hostsentry pointing at a previous address is a common cause.mtrshows???for every hop after the first- Some networks drop the ICMP time-exceeded replies
mtrrelies on. Try TCP probes to the service port withsudo mtr --report --tcp --port <PORT> -n <ADDRESS>. ncreports success but the client still fails- The network is fine.
Run the client with verbose output (
ssh -v,curl -v) and check the service's logs on the target.
Related¶
- Explanation: A troubleshooting method
- Reference: Diagnostic commands by layer