Skip to content
ohsudo, Home
Networking

"No route to host": usually a firewall saying no, sometimes a machine that isn't there

Fix "No route to host" from ssh, curl or nc: check the firewall on the other machine (firewalld rejects by default), then whether the host is up.

Beginner4 min readApplies to Linux · RHEL / Rocky / AlmaLinux (firewalld) · Ubuntu · Debian · Docker

by OhSudo ··

Not sure this is your cause?Find it step by step: Can't connect over SSH →

ssh: connect to host 203.0.113.20 port 22: No route to host
nc: connect to 203.0.113.20 port 8080 (tcp) failed: No route to host
Ncat: No route to host.

Recent versions of curl hide the reason, and only say Failed to connect to 203.0.113.20 port 8080 after 3 ms: Couldn't connect to server. To see which error it really is, try the same port with nc or ssh, as below.

The name suggests a routing problem, and that’s rarely it. In practice, this message has two causes:

  • A firewall rejected you, and said so. The best-known source is firewalld, the default on RHEL, Rocky and AlmaLinux: its default zone answers anything it doesn’t allow with “host prohibited”, which Linux shows as No route to host.
  • The machine isn’t there. On your own local network, nothing answered for that address.

A quick test tells them apart: does ping work?

  1. Clientconnects to 203.0.113.20:22
  2. firewalld on the serverrejects: host prohibited(breaks here)
  3. Client seesNo route to host
The name suggests routing, and that's rarely it. Usually a firewall rejected the connection and said so (firewalld does by default), or nothing on your local network has that address.

TL;DR

Terminal window
ping -c 2 203.0.113.20
nc -zv -w 5 203.0.113.20 8080

Ping works, and the port says No route to host? It’s a firewall: on the other machine, open the port.

Terminal window
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload

1. A firewall on the other machine

Practice this in the terminal: on the Rocky tab, the server has firewalld as installed, which allows only a few services.

Terminal window
nc -zv -w 5 app01 8080
Terminal window
ssh app01
sudo firewall-cmd --list-all

ports: is empty, and services: lists only ssh, cockpit and dhcpv6-client. So port 8080 is rejected, while SSH works. That’s the telltale sign: some ports work, and others say No route to host. Open the one you need:

Terminal window
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
exit
nc -zv -w 5 app01 8080

Now the answer changes to Connection refused, which is progress: the firewall lets you through, and nothing listens on that address. In this scenario, the app only listens on 127.0.0.1. That’s the next step, explained in “Connection timed out” vs “Connection refused”.

Other firewalls. An iptables or nftables rule with REJECT --reject-with icmp-host-prohibited gives the same result. On Ubuntu, ufw drops by default, which gives a timeout instead. Network firewalls and cloud security groups usually drop as well, so they give timeouts.

2. The machine isn’t there

If ping fails too, and the address is on your local network, then nothing answered when your machine asked who has that address:

Terminal window
ip neigh show 192.168.1.50

FAILED or INCOMPLETE means no reply. The machine is off, has another address, or is on a different network segment or VLAN. Check its address from its console, and look for a typo. A virtual machine whose network adapter is disconnected, or on a different virtual switch, does this too.

3. Your own routes

Now the name fits: your machine doesn’t know where to send packets for that address.

Terminal window
ip route get 203.0.113.20
ip route

No default via line means no gateway, so only the local network is reachable. A VPN can add routes that capture traffic, and send it nowhere. Check the subnet mask too: with a wrong mask, a machine believes a remote address is local, and asks for it on the local network, where nothing answers. The Subnet Calculator shows which addresses a mask includes.

4. Docker networks

Docker creates networks such as 172.17.0.0/16 and 172.18.0.0/16. If your company network, or a VPN, uses the same range, then traffic for those addresses goes into Docker instead, and you get this error for real machines. Check:

Terminal window
ip route | grep -E 'docker|br-'

Move Docker to another range in /etc/docker/daemon.json, with default-address-pools, then restart Docker and recreate the networks.

5. Check the firewall on your own side

Your outgoing rules can reject too. On RHEL, sudo firewall-cmd --list-all on the client, and on any machine, sudo nft list ruleset | grep -i reject shows reject rules.

Warning

Don’t stop firewalld to fix this: systemctl stop firewalld opens every port on the machine. Open the one port you need, and only to the addresses that need it, with a rich rule or a zone. The Port Lookup says which ports should never face the internet.

Shell, we have a problem!

Similar, but different: Connection refused means you reached the machine, and nothing listens on that port. Connection timed out means packets disappear without an answer, usually a firewall that drops. Network is unreachable means you have no route at all, not even a gateway. And Temporary failure in name resolution happens before any connection: see that article.

$ ./practice.sh

Practice this in the terminal

Open the Terminal Playground with this article’s scenario loaded. It is safe and runs in your browser.

Open the terminal →

Found this useful? Share it.

Found a mistake? Let us know at contact@ohsudo.com.

Tools

Try it yourself

Articles

Related articles