No Route to Host - Diagnose and Fix Fast
Fix No route to host via ip route, gateway ping, and firewall checks.
20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.
- ✓Basic TCP/IP, subnets, and gateways
- ✓SSH access to source and target hosts
- ✓Familiarity with Docker networks
- No route to host (EHOSTUNREACH) means your kernel has no path to the target. Check ip route first
- Ping the gateway, then the target: gateway failure means local network trouble, target-only failure means remote or firewall
- Firewall DROP rules cause fake no-route symptoms; list them with iptables -L -n -v and firewall-cmd --list-all
- In Docker, a missing bridge route or custom network split causes it; inspect with docker network inspect
Think of your network like a road map. No route to host means your town has no road leading to the destination at all, so you never even leave home. Connection refused means you drove there but the shop door was locked. A timeout means you drove out and got stuck in traffic with no answer. Each needs a different fix: build the road, unlock the door, or clear the traffic jam. The first step is always reading which of the three the error actually says.
You try to SSH to a server and get No route to host. The server is up, your credentials are right, but packets never arrive. Most engineers jump straight to firewall rules, yet half the time the cause is simpler: a wrong subnet mask, a missing gateway, or a Docker bridge that does not span both containers. Reading the exact error saves you from fixing the wrong layer.
The three network errors look alike but point at different layers. EHOSTUNREACH means your own kernel found no path. ECONNREFUSED means you reached the host but nothing listened on that port. A timeout means packets left but nothing came back, which usually implicates a firewall DROP or a black hole route. Treating all three as a firewall problem wastes hours.
This guide gives you a fixed walkthrough: confirm the error type, check local routes with ip route, ping the gateway and target, trace the path, inspect listening sockets with ss, then examine firewalld and iptables for DROP vs REJECT. You will also fix the Docker bridge cases that mimic host routing failures.
EHOSTUNREACH vs Refused vs Timeout - Read the Error Right
These three errors describe three different network facts, and mixing them up sends you down the wrong path. EHOSTUNREACH, shown as No route to host, means your own kernel found no route to the destination. The packet never left the building. Your fix lives in ip route, netmask, gateway, or VPN routes. Do not touch the firewall yet. Connection refused, ECONNREFUSED, proves the opposite: routing worked, the SYN arrived, and the target sent back RST because nothing listens on that port. Your fix is the service, its bind address, or the port number you typed. A timeout means packets left and nothing returned. That is the signature of a firewall DROP, a black hole route, or a dead middlebox. Your fix is firewall rules or path tracing. Learn the fingerprints. ping prints From local-ip icmp_seq=1 Destination Host Unreachable for EHOSTUNREACH. curl prints Failed to connect: No route to host versus Connection refused versus a hang until timeout. SSH prints No route to host versus Connection refused versus Connection timed out. Match the string first, then pick the section below. Engineers who skip this step spend an hour tuning iptables for a service that simply is not running. Keep a small cheat card of the three strings on your desk until the mapping is reflex. The five minutes you spend learning them pays back on every future network ticket you touch.
Firewall DROP vs REJECT - Why Packets Vanish Silently
Firewalls cause the most confusion because DROP and REJECT look nothing alike on the wire. REJECT sends back an ICMP or TCP RST that says no, so your client fails fast with an error that resembles refused. DROP discards the packet and says nothing, so your client hangs until it times out. A timeout therefore points at DROP, while fast failures point at REJECT or a closed port. Know which chains to read. INPUT filters packets to the host itself, FORWARD filters packets passing through (Docker and routers live here), and OUTPUT filters locally generated traffic. Docker adds DOCKER-USER and DOCKER chains that can surprise you: a rule in DOCKER-USER drops container traffic before your INPUT logic ever sees it. firewalld zones add another layer: the wrong zone on an interface silently applies the wrong rule set. Diagnose by listing with line numbers, then watch counters increment as you retest. Add a temporary LOG rule above the suspect DROP to confirm the match in the journal. Never flush rules on a remote host over SSH unless you have console access: one flush can lock you out permanently. When counters do not move on any chain, the drop happens upstream, so move the same checks to the next hop. Packet counters never lie, so trust them over memory of what the rules should be.
Wrong Subnet, Gateway, or Netmask - Fix Local Routing
Local routing bugs are embarrassingly common and quick to fix once you look. A /24 mask where a /23 belongs splits one subnet into two unreachable halves. A missing default route after a DHCP flap leaves only link-local traffic working. A stale static route from a decommissioned VPN sends packets into a dead tunnel. All three print No route to host. Start with ip route get TARGET, which shows the exact route the kernel would use, or the RTNETLINK unreachable verdict when none matches. Compare against ip addr to see your addresses and masks. The classic tell: some hosts in a tier work and others do not, split exactly on a subnet boundary. That is always a mask mismatch. Fix the session with ip route add or ip route replace, then persist the fix where your distro keeps it: Netplan YAML on Ubuntu, nmcli on RHEL, or /etc/sysconfig/network-scripts on older hosts. Verify from both sides, because asymmetric routes fail in one direction only. Then add a canary ping so the next mask typo pages you in a minute. Record the corrected mask in the incident note with before and after ip route output. Future you will thank present you when the same subnet gets touched again next quarter. A screenshot of the fixed table helps too.
Docker Bridge Networking - When the Host Works but Containers Do Not
Docker adds a virtual network on top of host routing, and its failures mimic host no-route errors. Each bridge network owns a subnet like 172.18.0.0/16. Containers on the same bridge reach each other by IP or name. Containers on different bridges cannot, unless you connect them explicitly. From the host, container IPs are reachable only if the bridge route exists in ip route and FORWARD rules allow it. The usual breakage: two services placed on different default networks after a compose edit, a recreated network that changed subnets while app config still points at old IPs, or a DOCKER-USER DROP that kills inter-container traffic. Diagnose with docker network ls and docker network inspect to see which containers share a subnet and gateway. Compare with ip route on the host for the bridge route. Test from inside with docker exec container ping target. Fix by attaching both services to one user-defined network in compose, updating stale IPs to service names so Docker DNS resolves them, and allowing the traffic in DOCKER-USER. Prefer service names over hard-coded bridge IPs everywhere. After re-attaching networks, restart the affected containers so DNS and routes rebuild cleanly. Then re-run docker network inspect and save the output as the new known-good baseline.
The ip route, ping, traceroute, ss Walkthrough
When the cause is unclear, run this fixed sequence and let the outputs decide. First classify with ping and curl so you know whether you are chasing EHOSTUNREACH, refused, or timeout. Second run ip route get TARGET plus ip route show and ip addr: this either names the broken route or clears routing entirely. Third ping the gateway, then the target, then traceroute -n TARGET to find the last responding hop. A failure at hop one is your local link. A failure at the last hop is the destination or its firewall. Stars mid-path with success at the end are normal: some routers deprioritize ICMP. Fourth, on the target run ss -tuln and confirm the port is LISTEN on the right address. A service bound to 127.0.0.1 is invisible to the LAN no matter what the firewall says. Fifth, check firewall counters and logs on both ends. Work the list top to bottom without skipping: each step eliminates a whole layer. Write down each result as you go, because flapping networks change answers between runs and you will want the history. If results flip between runs, suspect DHCP flaps, ECMP imbalance, or a dying NIC, and watch dmesg plus journalctl while you repeat the sequence. Document each run with timestamps.
Harden the Network So Routes Survive Change
Routing fixes that live only in the terminal die at the next reboot. Every ip route add must have a persistent twin in Netplan, NetworkManager, or your IaC network module, or the incident will return after patching. Keep a source of truth for subnets, masks, and gateways, and generate host configs from it instead of hand-editing boxes. Review DHCP lease behavior too: short leases plus slow reconnection can flap the default route and produce intermittent EHOSTUNREACH that looks like a firewall. For Docker, define networks explicitly in compose with names and subnets, and never rely on default bridge IPs that change on recreate. Add monitoring that matches the failure: a canary ping per subnet pair for routing, a TCP connect check per critical port for listeners, and firewall counter alerts for sudden DROP growth. After any network change, run the walkthrough from both directions before closing the ticket. Document the working ip route output in the incident note so the next engineer has a known-good baseline to compare against. Schedule a quarterly review of static routes and firewall rules against the source of truth. Stale entries accumulate silently and turn the next small change into a confusing outage.
Wrong Netmask on New Subnet Cut API From Workers for 38 Min
- When only some hosts in a tier fail, compare netmasks before firewall rules: a split-brain subnet is the classic pattern.
- Re-IP checklists must verify ip addr output on hosts, not just the spreadsheet value that was intended.
- Keep a canary ping across every subnet pair so routing splits alert in a minute instead of 38 minutes.
| File | Command / Code | Purpose |
|---|---|---|
| classify-error.sh | ping -c 3 10.0.2.15 | EHOSTUNREACH vs Refused vs Timeout - Read the Error Right |
| firewall-check.sh | iptables -L -n -v --line-numbers | Firewall DROP vs REJECT - Why Packets Vanish Silently |
| route-fix.sh | ip route get 10.4.1.20 | Wrong Subnet, Gateway, or Netmask - Fix Local Routing |
| docker-net-check.sh | docker network ls | Docker Bridge Networking - When the Host Works but Container |
| net-walkthrough.sh | ping -c 3 10.0.2.15 | The ip route, ping, traceroute, ss Walkthrough |
Key takeaways
Common mistakes to avoid
5 patternsTreating every failure as a firewall problem
Flushing iptables over SSH to test
Fixing routes only with ip route add
Binding services to localhost by default
Hard-coding Docker bridge IPs in config
Interview Questions on This Topic
How do you tell No route to host apart from Connection refused and timeout?
Frequently Asked Questions
20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.
That's Linux. Mark it forged?
5 min read · try the examples if you haven't