Panoptes › Wi-Fi: no internet
WiFi connected but no internet on Linux
NetworkManager says you are connected. You can reach the router, maybe even a printer or NAS on the LAN, but no website loads, and rebooting does not help. This page walks the problem one layer at a time with read-only checks, so you find the broken layer before you change anything, then gives the fix for each.
Run the checks in order. Each one assumes the one before it passed. Replace wlan0 with your Wi-Fi interface name, which nmcli device status lists in the DEVICE column.
Quick triage: which layer is broken?
| Layer | Read-only check | If it fails |
|---|---|---|
| Link | nmcli device status | Not associated, or the radio is blocked |
| Address and gateway | ip -4 route show default | No default route: DHCP or the connection profile |
| Upstream by IP | ping -c 3 1.1.1.1 | Routing or firewall, often a leftover VPN |
| TCP by IP | timeout 5 bash -c 'exec 3<>/dev/tcp/1.1.1.1/443' && echo open | If this works but ping fails, ICMP is just filtered |
| DNS | resolvectl query example.com | The resolver, not the network |
If the TCP check prints open but names do not resolve, skip straight to DNS. If even the TCP check fails while the gateway answers, go to the route and leftover VPN state.
Layer 1: is the Wi-Fi link really up?
nmcli device status
rfkill list
nmcli -f GENERAL.STATE,IP4.ADDRESS,IP4.GATEWAY device show wlan0- The Wi-Fi device should be
connected. Ifrfkill listshowsSoft blocked: yes, runsudo rfkill unblock wifi. - No
IP4.ADDRESS, or one starting169.254., means DHCP never completed. That is an association or DHCP problem, not an internet one. - No
IP4.GATEWAYmeans no default route, so nothing beyond the LAN can work.
Next, check the gateway itself. Some access points (hotel and guest networks with client isolation, in particular) drop ping to the gateway while working normally, so do not judge layer 2 by ping alone. Check the neighbour table too:
ip -4 route show default
ping -c 3 -W 2 192.168.1.1
ip neigh show dev wlan0The address after via in the first command is your gateway; use it in place of 192.168.1.1. An entry for it in ip neigh with a MAC address (lladdr) and a state such as REACHABLE or STALE means layer 2 works. FAILED or INCOMPLETE means the router is not answering at all.
Layer 2: where are packets actually going?
This is the check people skip, and it catches the most confusing failure: the default route is fine, but something more specific is stealing your traffic.
ip route get 1.1.1.1
ip -4 route show | grep linkdown
ip rule showip route getprints the route the kernel will really use. It should name your gateway anddev wlan0. If it namestun0,wg0,CloudflareWARPor another tunnel while you believe the VPN is off, you have found the problem.- Routes marked
linkdownpoint into an interface that is down. They still take part in route selection, and traffic matched by them goes nowhere. ip rule shownormally has three rules: priority 0 (local), 32766 (main) and 32767 (default). Extra rules sending traffic to a numbered table usually belong to a VPN client.
Why the LAN still works. The kernel picks the most specific matching route. A VPN in split-tunnel mode can install hundreds of routes such as 0.0.0.0/5, 8.0.0.0/7 and 32.0.0.0/3, each more specific than default via 192.168.1.1. If those routes outlive the VPN, every internet packet goes into a dead tunnel. Your LAN subnet route, 192.168.1.0/24 for example, is more specific still, so local traffic keeps working. That is why this looks like a DNS or ISP fault when it is neither.
Leftover VPN or killswitch state that survives a reboot
A real case: Wi-Fi associated, LAN worked, the internet was gone, and it stayed gone across reboots. Stopping, disabling and masking the Cloudflare WARP daemon changed nothing. The cause was NetworkManager. It had adopted WARP's CloudflareWARP tunnel device as an external connection, and a later nmcli con mod on that connection (setting its firewall zone) saved it to /etc/NetworkManager/system-connections/, with autoconnect on and WARP's ~314 split-tunnel routes stored as static routes. From then on, NetworkManager recreated the tunnel and its routes on every network change, with the WARP daemon dead.
So check three places: the firewall, the routing tables, and NetworkManager's saved profiles.
nftables tables left by a VPN client
sudo nft list tables
sudo nft list table inet cloudflare-warpYour firewall's own tables belong there. A table belonging to a VPN you have disconnected does not. Cloudflare WARP's table is inet cloudflare-warp.
Tunnel interfaces and the routes on them
ip -br link
ip route show table all | grep -E 'dev (tun|wg|CloudflareWARP)'NetworkManager profiles that persist a tunnel
nmcli -f NAME,TYPE,DEVICE,FILENAME connection show
sudo grep -cE '^route[0-9]+=' /etc/NetworkManager/system-connections/NAME.nmconnectionLook for a tun, wireguard or vpn profile whose FILENAME is under /etc/NetworkManager/system-connections/ and that you did not create. In the second command, use that FILENAME path. A VPN profile does not normally need a list of static routes, because the VPN daemon installs its routes when it connects. A tunnel profile holding dozens or hundreds of routeN= lines is a saved snapshot of a live tunnel.
Fix: remove the leftovers
For Cloudflare WARP (for another VPN, use its service, nftables table and interface names instead):
warp-cli disconnect
sudo systemctl disable --now warp-svc
sudo nft delete table inet cloudflare-warp
sudo ip -4 route flush dev CloudflareWARP
sudo ip -6 route flush dev CloudflareWARP
sudo ip link delete CloudflareWARPIf systemctl list-units 'warp-svc*' shows a socket unit, stop that too, or it can start the daemon again. Flush routes by device as shown, and do not paste lines from ip route show into ip route del: those lines end in status flags such as linkdown, which ip route del does not accept, so the deletes fail.
If NetworkManager has saved the tunnel as a profile, delete the profile, then tell NetworkManager to leave the device alone in future:
sudo nmcli connection delete "NAME"
printf '[keyfile]\nunmanaged-devices=interface-name:CloudflareWARP\n' | sudo tee /etc/NetworkManager/conf.d/99-warp-unmanaged.conf
sudo nmcli general reload confA reboot also picks up the new file. An unmanaged device never gets a profile, so NetworkManager cannot save one. Run ip route get 1.1.1.1 again: it should now name your gateway.
Layer 3: the network works, DNS does not
If the TCP check printed open, the internet is up and the resolver is the problem. Compare systemd-resolved with a direct query that bypasses it:
resolvectl query example.com
dig +short example.com @1.1.1.1
resolvectl statusIf dig answers and resolvectl does not, the fault is in the resolver configuration. The usual causes:
- Strict DNS-over-TLS. With
DNSOverTLS=yes, lookups fail if the server cannot be reached over TLS. There is no plain-DNS fallback.opportunisticfalls back.resolvectl statusshows the mode on itsProtocols:line. - Failures cached after a VPN toggle. Bringing a tunnel up or down kills DNS lookups that were in flight through it. With DNSSEC on, those can fail validation (
failed-auxiliary), andsystemd-resolvedcaches the failure. Routing works again immediately, but the browser still says you are offline. Clear the cache:
resolvectl flush-caches
resolvectl reset-server-featuresRestarting systemd-resolved has the same effect. One related trap: FallbackDNS= in resolved.conf is not a failover. It is only used when no other DNS server is known at all. If you want a second resolver to take over when the first goes quiet, list it in DNS=.
Captive portals: the login page never appears
On hotel, airport and café Wi-Fi, "connected, no internet" usually means a captive portal you cannot see. Check what NetworkManager thinks, and probe for a redirect:
nmcli networking connectivity check
curl -sS -o /dev/null -w '%{http_code} %{redirect_url}\n' http://connectivitycheck.gstatic.com/generate_204portal from the first command means NetworkManager has detected one. From the second, 204 means you are online. Any other result, typically a redirect with a URL or a 200 login page, means something intercepted the request: the portal.
A hardened setup hides the portal. Each of these blocks it:
| Setting | Why the portal fails |
|---|---|
| A VPN or WARP tunnel | Your traffic goes past the portal, so it never sees a request to redirect. |
| DNS-over-TLS | The portal redirects you by hijacking plain DNS and cannot touch encrypted queries. |
ipv4.ignore-auto-dns | The network's own resolver, which does the redirecting, is discarded. |
| Random MAC address | Each reconnect looks like a new client, so your login does not stick. |
| Connectivity checking off | NetworkManager never probes, so the "sign in to network" prompt never fires. |
To get through, take those down for this one network, log in, then put them back:
warp-cli disconnect
sudo nmcli connection modify "SSID" ipv4.ignore-auto-dns no
sudo nmcli connection modify "SSID" 802-11-wireless.cloned-mac-address permanent
sudo nmcli connection up "SSID"If /etc/systemd/resolved.conf sets DNSOverTLS=yes, set it to no for now and run sudo systemctl restart systemd-resolved. If the file will not save, check lsattr /etc/systemd/resolved.conf: some hardening setups lock it with chattr +i. Then open http:// followed by your gateway address in a browser and log in.
Reconnect the VPN only after the portal has let you on, and check that it has. If the tunnel comes up first, the portal cannot see your traffic and you are back where you started.
Automated: netmaster from Panoptes was written after the outage described above. sudo netmaster diagnose runs the checks on this page as one read-only report: a gateway, ping, TCP 443 and DNS ladder; routes into downed interfaces; NetworkManager tunnel profiles carrying static routes; stale WARP tables and interfaces; firewalld drop-zone pinning; and a "portal-blind" warning when your own hardening is hiding a login page. netmaster fix --dry-run previews its repair ladder, which backs up what it touches, checks connectivity after every rung and stops as soon as the internet is back. netmaster portal and netmaster restore handle the captive-portal sequence. For WARP alone, sudo warp-killswitch down removes its nftables table, routing table and interface, switches to plain DNS and disables the daemon so it stays down across reboots; warp-killswitch up puts it back. Note that netmaster was built on Fedora Asahi, and its last-resort driver reload targets the brcmfmac Wi-Fi driver.
FAQ
Why does my LAN work when the internet does not?
The kernel uses the most specific matching route. A leftover VPN route such as 0.0.0.0/5 beats your default route, so internet traffic goes into a dead tunnel, while your LAN subnet route is more specific still and keeps working. Run ip route get 1.1.1.1 to see which interface really carries internet traffic.
Why does "connected, no internet" survive a reboot?
Because whatever breaks it is saved on disk: a NetworkManager profile that stored a tunnel and its routes, a VPN service that is still enabled, or a resolver setting such as strict DNS-over-TLS. Look for tunnel profiles under /etc/NetworkManager/system-connections/ and for enabled VPN services.
I can ping 1.1.1.1 but websites do not load. What is wrong?
Your connection works and DNS is failing. Compare resolvectl query example.com with dig +short example.com @1.1.1.1. If only dig answers, check resolvectl status for strict DNS-over-TLS, then clear cached failures with resolvectl flush-caches.
My browser says I am offline right after I turned the VPN off. Why?
Lookups that were in flight when the tunnel went down can fail DNSSEC validation, and systemd-resolved caches those failures. Routing is already fine. Run resolvectl flush-caches, or restart systemd-resolved.
Why does the hotel Wi-Fi login page never appear?
Usually your own hardening hides it. A VPN tunnels past the portal, encrypted DNS cannot be redirected, ignoring the network's DNS discards the redirecting resolver, and a random MAC makes the login not stick. Disconnect the VPN, accept the network's DNS and pin your real MAC for that network, log in, then restore everything, with the VPN last.
Sources
- resolvectl(1)
- resolved.conf(5):
DNSOverTLS=,FallbackDNS= - ip-route(8) and ip-rule(8)
- nmcli(1): connectivity states
- NetworkManager.conf(5):
unmanaged-devices, connectivity checking - nm-settings-nmcli(5):
ipv4.ignore-auto-dns,connection.zone - nft(8), nftables 1.1.6 manual:
list tables,delete table