ERR_CONNECTION_REFUSED: Causes and the Fix

· 5 min read · 45 views · Getwebup

The short answer

ERR_CONNECTION_REFUSED means the packet reached the server and something actively rejected it - nothing is listening on that port, or a firewall sent back a hard reset rather than dropping the packet silently. Run ss -tlnp | grep -E ':(80|443)\s' on the server. Nothing bound means the web server is stopped; bound to 127.0.0.1 rather than 0.0.0.0 means it is running and unreachable from outside.

Getting silence instead of a refusal? That is the other error — ERR_CONNECTION_TIMED_OUT: Causes and the Fix

ERR_CONNECTION_REFUSED is the most informative failure in this family, because a refusal is an answer. Something at that address received your packet and actively rejected it, which means the machine is reachable and running. That eliminates DNS, routing and half the usual suspects before you start.

Refused versus timed out

The two errors look similar and mean opposite things.

  • Refused - a TCP reset came back. The packet arrived somewhere alive, and nothing was listening on the port you asked for, or a firewall rule chose to reject rather than drop.
  • Timed out - nothing came back at all. Something dropped the packet silently, or the address is not reachable from where you are.

Getting a refusal is good news relative to the alternative. It tells you the server is up, and it moves the whole investigation to one question: what should be listening on that port, and why is it not?

Step 1: what is actually bound?

On the server, this one command answers the question most of the time:

ss -tlnp | grep -E ':(80|443)\s'

Read the address on the left of each line carefully. There are three outcomes and they have three different fixes.

  • Nothing at all - no web server is running. Start it, and read the log to find out why it stopped.
  • 127.0.0.1:80 - the service is running and bound to localhost. It works perfectly for anything on the machine and is invisible from the internet. This is a configuration change, not a restart, and it is one of the most common causes after a fresh install or a container migration.
  • 0.0.0.0:80 or *:80 - the service is listening correctly on all interfaces. The refusal is coming from a firewall instead. Skip to step 3.

Step 2: if nothing is listening

systemctl status nginx
systemctl status httpd
systemctl status php-fpm
journalctl -u nginx --since '30 minutes ago'

A service that will not start almost always says why in its own log. The usual reason is a configuration error introduced by the last edit - a missing semicolon, a certificate path that does not exist after a renewal, or a duplicate listen directive. Test the config before you keep restarting:

nginx -t
apachectl configtest

The other frequent cause is a reboot with the service not enabled. It ran fine for months, the machine restarted, and nothing brought it back:

systemctl enable --now nginx

Once it is running, make a stop less painful next time:

systemctl edit nginx     # add, under [Service]:  Restart=on-failure

Step 3: if a firewall is rejecting

Most firewalls drop by default, which produces a timeout. A refusal means something is configured to reject explicitly - or the connection is reaching a different machine than you think.

Test from the server itself first, which takes the network out of the picture entirely:

curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1

Working locally and refusing remotely confirms the fault is between the internet and the port, not in the application. Then check both firewall layers, because they are independent and either can be the one saying no:

ufw status verbose
iptables -L INPUT -n --line-numbers | grep -E 'REJECT|dpt:(80|443)'
csf -l                       # cPanel servers

On a cloud VPS, the provider's own network firewall or security group sits in front of the OS firewall. A rule can look perfect in ufw and still be overridden a layer up, so check the provider's console as well as the machine.

Step 4: the block that only affects some people

If the site loads for you and refuses for a particular visitor, the cause is usually an automatic IP ban rather than anything global. CSF's Login Failure Daemon blocks addresses after repeated failed logins, aggressive crawling, or a false positive - and shared office IPs and monitoring services trip it regularly.

csf -g VISITOR_IP
grep VISITOR_IP /etc/csf/csf.deny
csf -dr VISITOR_IP           # remove the block

Fail2Ban does the same thing with its own store:

fail2ban-client status
fail2ban-client set sshd unbanip VISITOR_IP

If a legitimate visitor keeps getting caught, whitelist the address rather than loosening the rule for everyone.

Step 5: the wrong server entirely

After a migration, a rebuild, or an IP reassignment, a stale record can point your domain at an address that now belongs to someone else - or to nothing. Their machine refuses your connection and the error looks exactly like your own server being down.

dig +short yourdomain.com @1.1.1.1
curl -sS https://api.ipify.org; echo      # run this ON the server

If those two do not match, the domain is not pointing at the machine you are debugging, and nothing you change on it will help.

When it is your own machine

If one device gets refused and everything else on the same network works, the site is fine. A local proxy setting, a VPN, an HTTPS-inspecting antivirus, or a leftover entry in the hosts file will all produce this. Check the hosts file first - /etc/hosts, or C:\Windows\System32\drivers\etc\hosts - because it overrides DNS entirely and survives every cache flush you can run.

Questions people actually ask