Home › DevOps › No Route to Host - Diagnose and Fix Fast
Intermediate 5 min · September 23, 2026

No Route to Host - Diagnose and Fix Fast

Fix No route to host via ip route, gateway ping, and firewall checks.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
✓ Production
production tested
September 24, 2026
last updated
1,942
articles · all by Naren
Before you start⏱ 10 min
  • ✓Basic TCP/IP, subnets, and gateways
  • ✓SSH access to source and target hosts
  • ✓Familiarity with Docker networks
 ● Production Incident 🔎 Debug Guide
⚡Quick Answer
  • 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
✦ Definition~90s read
What is No Route to Host Fix?

No route to host is the EHOSTUNREACH error from the Linux kernel. It means the local routing table has no entry that matches the destination IP, and no default gateway to send it to. The kernel drops the packet before it ever hits the wire. You will see it from ping, SSH, curl, and any tool that opens a connection.

★
Think of your network like a road map.

It is a routing verdict, not a firewall verdict, though firewalls can produce lookalike symptoms.

Every Linux host routes by longest-prefix match. It checks the destination against each route in ip route output, picks the most specific match, and sends the packet out that interface to that gateway. If nothing matches and no default route exists, you get EHOSTUNREACH.

Common triggers: a wrong netmask that puts the target outside your subnet, a deleted default route after a DHCP hiccup, a VPN that hijacked routes, or a Docker container on a bridge your host does not know.

Contrast with its cousins. Connection refused (ECONNREFUSED) proves routing worked: your SYN reached the host and the host sent back RST because no process listened on that port. A timeout proves nothing came back: either a firewall DROP swallowed the packets silently or the path is broken mid-way.

This article teaches you to separate the three in seconds, then fix routes, gateways, firewall rules, and Docker bridge setups with commands you can trust.

Plain-English First

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.

classify-error.shBASH
1
2
3
4
ping -c 3 10.0.2.15
curl -v --connect-timeout 5 http://10.0.2.15:8080/
ssh -o ConnectTimeout=5 user@10.0.2.15 true
ss -tuln | grep 8080
📊 Production Insight
Most escalations that stall do so because refused was treated as no-route. Reading the exact string first cuts diagnosis time in half.
🎯 Key Takeaway
No route means fix routing, refused means fix the service and port, timeout means suspect firewall DROP or a broken path.

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.

firewall-check.shBASH
1
2
3
4
iptables -L -n -v --line-numbers
firewall-cmd --list-all
iptables -I INPUT 1 -j LOG --log-prefix FW-DROP:
journalctl -kf | grep FW-DROP
📊 Production Insight
Timeouts after a firewall push almost always mean a new DROP. Fast refused errors after the same push mean REJECT or a stopped service instead.
🎯 Key Takeaway
DROP causes silent timeouts, REJECT fails fast. Check INPUT, FORWARD, and Docker chains with counters before changing anything.

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.

route-fix.shBASH
1
2
3
4
5
ip route get 10.4.1.20
ip route show
ip addr show dev eth0
ip route replace default via 10.4.0.1 dev eth0
ping -c 3 10.4.1.20
📊 Production Insight
Half-a-tier failures split on a subnet boundary are masks, not firewalls. Compare ip addr masks across the tier before touching any rule.
🎯 Key Takeaway
Use ip route get to see the kernel verdict, fix masks and gateways, persist in Netplan or nmcli, and verify both directions.

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.

docker-net-check.shBASH
1
2
3
4
docker network ls
docker network inspect app_default
ip route show | grep 172
docker exec app_web ping -c 3 app_api
📊 Production Insight
Compose edits silently move services onto different default networks. After any compose change, inspect networks before debugging host routes.
🎯 Key Takeaway
Put dependent services on one user-defined network, use service names not bridge IPs, and check DOCKER-USER FORWARD rules.

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.

net-walkthrough.shBASH
1
2
3
4
5
ping -c 3 10.0.2.15
ip route get 10.0.2.15
ping -c 3 10.0.2.1
traceroute -n 10.0.2.15
ss -tuln | grep 8080
📊 Production Insight
Engineers who run the full five-step sequence in order resolve routing tickets faster than those who jump to the step that feels right.
🎯 Key Takeaway
Classify, check routes, ping gateway then target, trace the path, verify the listener, then read firewall counters.

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.

⚠ Never Flush Firewall Rules Over SSH
Flushing iptables on a remote host can lock you out instantly if the default policy is DROP. Always keep a console session or an at-job that restores rules before testing changes.
📊 Production Insight
Reboot-reverted routes are the classic repeat incident. If the fix is not in IaC or Netplan, it is not done.
🎯 Key Takeaway
Persist every route in IaC, pin Docker networks and names, monitor subnet pairs, and save known-good route output.
● Production incidentPOST-MORTEMseverity: high

Wrong Netmask on New Subnet Cut API From Workers for 38 Min

Symptom
Workers logged No route to host reaching the API tier at 10:02. The API was healthy and other subnets connected fine. Roughly half the API IPs failed consistently while the other half worked. No deploy had gone out and firewall rules were untouched.
Assumption
The team blamed the firewall because the error appeared right after a firewalld policy push. They spent 15 minutes listing zones and rich rules. The firewall change was a red herring: it touched logging only. Nobody rechecked the netmask from the weekend re-IP because the spreadsheet said /23.
Root cause
The weekend re-IP moved workers to 10.4.0.0/23 but one config template still wrote /24. Workers believed 10.4.1.x was off-subnet and sent it to a gateway that had no route back. Hosts in 10.4.0.x worked, 10.4.1.x failed with EHOSTUNREACH. ip route showed the /24 on workers versus /23 everywhere else.
Fix
Fixed the template to /23, re-ran the network role, and verified with ip route and ping across both halves. Added a post-change check that compares ip addr masks against the source-of-truth inventory. Kept a canary worker pinging both halves every minute with an alert on any EHOSTUNREACH.
Key lesson
  • 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.
Production debug guideRun these in order: error type, routes, gateway, path, then firewall and sockets.5 entries
Symptom · 01
Unsure whether it is no-route, refused, or timeout
→
Fix
Run ping -c 3 TARGET and curl -v --connect-timeout 5 http://TARGET:PORT. EHOSTUNREACH prints No route to host. Refused prints Connection refused. Silence until timeout means DROP or black hole. Knowing which decides the whole investigation.
Symptom · 02
Suspected local routing problem
→
Fix
Run ip route get TARGET and ip route show. If get says RTNETLINK answers: Network is unreachable, no route matches. Compare the interface and gateway against ip addr. Fix with ip route add TARGET/24 via GATEWAY dev ETH0, then persist it in Netplan or nmcli.
Symptom · 03
Need to tell gateway failure from target failure
→
Fix
Run ping -c 3 GATEWAY then ping -c 3 TARGET, plus traceroute -n TARGET. If the gateway fails, fix local link, cable, or DHCP. If only the target fails at the last hop, the remote net or its firewall is the suspect.
Symptom · 04
Firewall may be swallowing packets
→
Fix
Run iptables -L -n -v --line-numbers and firewall-cmd --list-all. Look for DROP on INPUT, FORWARD, or DOCKER-USER chains. DROP is silent (timeout), REJECT answers (refused-like). Test by logging with iptables -I CHAIN 1 -j LOG --log-prefix FW-DROP: then tail journalctl -kf.
Symptom · 05
Port may simply have nothing listening
→
Fix
Run ss -tuln | grep PORT on the target and curl -v from the source. If ss shows no LISTEN line, start the service or fix its bind address. If ss listens on 127.0.0.1 only, rebind to 0.0.0.0 or the LAN IP so remote hosts can reach it.
No Route to Host Causes Compared
Root CauseHow to ConfirmFixPrevention
Missing route or wrong maskip route get says unreachable; masks differ across tierFix mask; add route via correct gatewayGenerate net config from IaC source of truth
Firewall DROPTimeout; DROP counters rise; LOG rule matchesAllow port in correct zone and chainReview rule diffs; alert on DROP growth
Nothing listening (refused)ss shows no LISTEN; fast refused errorStart service; bind 0.0.0.0; fix portTCP connect checks per critical port
Docker bridge splitContainers on different networks; exec ping failsJoin one user-defined network; use namesPin compose networks; inspect after edits
⚙ Quick Reference
5 commands from this guide
FileCommand / CodePurpose
classify-error.shping -c 3 10.0.2.15EHOSTUNREACH vs Refused vs Timeout - Read the Error Right
firewall-check.shiptables -L -n -v --line-numbersFirewall DROP vs REJECT - Why Packets Vanish Silently
route-fix.ship route get 10.4.1.20Wrong Subnet, Gateway, or Netmask - Fix Local Routing
docker-net-check.shdocker network lsDocker Bridge Networking - When the Host Works but Container
net-walkthrough.shping -c 3 10.0.2.15The ip route, ping, traceroute, ss Walkthrough

Key takeaways

1
No route to host is a routing verdict from your own kernel. Read the exact error before touching anything.
2
Classify first
EHOSTUNREACH means routes, refused means service and port, timeout means DROP or black hole.
3
Walk ip route, gateway ping, traceroute, and ss in order without skipping layers.
4
DROP is silent and REJECT answers; check INPUT, FORWARD, and Docker chains with counters.
5
Persist routes in Netplan or IaC, and never flush remote firewall rules over SSH.
6
Put dependent containers on one user-defined network and address them by service name.

Common mistakes to avoid

5 patterns
×

Treating every failure as a firewall problem

Symptom
Hours spent tuning iptables while ip route shows no path. The error string said EHOSTUNREACH from the start, which firewalls rarely produce.
Fix
Classify first with ping and curl. If the string is No route to host, work routes and masks before any firewall rule.
×

Flushing iptables over SSH to test

Symptom
Session freezes mid-command and the host is unreachable. Default DROP policy plus flush equals lockout with no remote recovery.
Fix
Test with targeted LOG rules and zone queries. Keep console access or a timed restore job before touching remote rules.
×

Fixing routes only with ip route add

Symptom
Incident returns after the next reboot or DHCP renew. The terminal fix never reached Netplan, nmcli, or IaC.
Fix
Persist every route in Netplan YAML, NetworkManager, or IaC, then reboot-test one host to prove it survives.
×

Binding services to localhost by default

Symptom
Local curl works but every remote host gets refused. ss shows LISTEN on 127.0.0.1 only.
Fix
Bind to 0.0.0.0 or the LAN IP in app config. Verify with ss -tuln from another host, not just locally.
×

Hard-coding Docker bridge IPs in config

Symptom
Works until the next network recreate, then fails with no-route. Bridge subnets change and stale IPs die.
Fix
Use compose service names so Docker DNS resolves current IPs. Define user networks explicitly in compose.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
How do you tell No route to host apart from Connection refused and timeo...
Q02JUNIOR
What does ip route get TARGET tell you that ip route show does not?
Q03SENIOR
Why does firewall DROP cause timeouts while REJECT fails fast?
Q04SENIOR
Two containers on one host cannot reach each other. Host networking is f...
Q05SENIOR
Half the hosts in a tier are unreachable along a subnet boundary. Firewa...
Q01 of 05JUNIOR

How do you tell No route to host apart from Connection refused and timeout?

ANSWER
No route (EHOSTUNREACH) means the local kernel has no path; fix routing. Refused (ECONNREFUSED) means the SYN arrived and got RST; nothing listens on that port. Timeout means packets left with no reply, usually firewall DROP or a black hole. ping, curl -v, and ssh each print distinct strings for the three.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
Does No route to host always mean the firewall blocked me?
02
Why can I ping the gateway but not the target?
03
What is the difference between DROP and REJECT?
04
Why do containers fail while the host connects fine?
05
How do I make an added route survive reboot?
06
Service runs but remote hosts get refused. Why?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
✓ Verified
production tested
September 24, 2026
last updated
1,942
articles · all by Naren
🔥

That's Linux. Mark it forged?

5 min read · try the examples if you haven't

←
Previous
sudo Command Not Found Fix
18 / 19 · Linux
Next
Too Many Open Files Fix
→