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:80or*: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 configtestThe 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 nginxOnce it is running, make a stop less painful next time:
systemctl edit nginx # add, under [Service]: Restart=on-failureStep 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.1Working 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 serversOn 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 blockFail2Ban does the same thing with its own store:
fail2ban-client status
fail2ban-client set sshd unbanip VISITOR_IPIf 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 serverIf 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.