Browser ERR_CONNECTION_REFUSED — Site Cannot Be Reached
Diagnose browser ERR_CONNECTION_REFUSED for localhost and remote hosts by checking listeners, ports, IPv6 vs IPv4 binding, and dev-server config.
Symptoms
- This site can’t be reached — ERR_CONNECTION_REFUSED
- localhost:3000 refuses immediately while the terminal shows the dev server running
- It works in one browser or on one machine but not another
Possible causes
- No process is listening on the requested port
- The dev server binds 127.0.0.1 only and the browser tries the IPv6 ::1
- The port in the URL differs from the one the server actually uses
- A firewall or proxy blocks the connection
Diagnosis steps
Confirm the listener and address family
ss -ltnp | grep 3000Interpretation
If the bind is 127.0.0.1:3000, requests to ::1 or the LAN IP are refused; bind 0.0.0.0 or use localhost consistently.
Test from the command line
curl -v http://localhost:3000Interpretation
A curl failure reproduces the browser error and rules out browser extensions as the cause.
Check the URL against the server port
Interpretation
A dev server on 5173 accessed on 3000 is a frequent mismatch after tooling changes.
Root cause
ERR_CONNECTION_REFUSED means the TCP connection was actively rejected with a reset, so nothing accepted it at that address and port. For localhost this is often an address-family mismatch: the server binds IPv4 while the browser resolves localhost to IPv6 ::1, or vice versa.
Fix
Start the server and bind it to an address the browser will reach, choosing 0.0.0.0 to accept all interfaces or matching the exact host the browser uses. Verify the port, and prefer the same hostname form (localhost) everywhere. For remote hosts, open the firewall and confirm the service is running on the expected interface.
Verify the fix
Reload the page; it loads without ERR_CONNECTION_REFUSED, and curl -v from the same shell returns a 200 response from the expected port.
Symptoms
The browser shows ERR_CONNECTION_REFUSED and fails immediately, unlike a timeout. The dev server may print “ready” in the terminal, which makes the refusal confusing.
Diagnosis
Check the exact bind address and test independently:
ss -ltnp | grep 3000
curl -v http://localhost:3000
If the bind is 127.0.0.1 and the browser resolves localhost to ::1, the connection is refused even though the server runs.
Fix
Bind a reachable address and keep host forms consistent:
# Vite
vite --host 0.0.0.0 --port 5173
Use http://localhost:5173 in the browser, not the LAN IP unless you bound 0.0.0.0.
Verification
Reload the page; it renders and no connection error appears. curl -v returns a 200 from the same port, confirming the listener and the browser agree on address and port.