You type in your domain and instead of your site loading, Chrome throws ERR_CONNECTION_REFUSED or ERR_CONNECTION_TIMED_OUT — no page, no error message from your app, nothing. This is different from a 502 or 504, where at least something answered and then failed. Here, nothing answers at all. That narrows the list of suspects a lot, and this guide walks through them in the order you should actually check them.

Symptom: The Browser Never Gets a Response

ERR_CONNECTION_REFUSED means a device on the way to your server actively rejected the connection attempt — usually a firewall or a service that isn't listening on that port. ERR_CONNECTION_TIMED_OUT means the request went out and nobody replied at all, which usually points to a network-level block (a firewall silently dropping packets instead of rejecting them, or the wrong IP entirely).

Both are different from:

  • DNS_PROBE_FINISHED_NXDOMAIN — the domain didn't even resolve to an IP. That's a DNS problem, not a connectivity one.
  • 502/504 errors — a proxy (Nginx, Cloudflare) did connect to your app but got a bad or slow response. The network path is fine; the app isn't.

If you're seeing refused/timed-out, the network path itself — firewall, service, or routing — is the problem.

Step 1: Confirm the Domain Points Where You Think It Does

Before touching firewall rules, rule out the obvious: the domain might be resolving to an old IP after a migration, or a DNS record might have reverted.

dig +short yourdomain.com

Compare that IP to your VPS's actual public IP (curl -4 ifconfig.me run on the server itself). If they don't match, this isn't a connection issue — it's a DNS issue, and no amount of firewall work will fix it. Update the A record and wait for propagation before continuing.

Step 2: Check Whether the Service Is Even Listening

SSH into the VPS and check what's actually bound to ports 80 and 443:

sudo ss -tlnp | grep -E ':80|:443'

If nothing shows up, your web server isn't running or isn't configured to listen on those ports at all — that alone produces ERR_CONNECTION_REFUSED from outside, no firewall involved. Check the service:

sudo systemctl status nginx
# or
sudo systemctl status httpd

A crashed worker, a bad config reload, or an OOM kill can all leave the process dead. Start it, then re-check ss -tlnp before moving on — don't assume a "started" message means it's actually bound to the port.

Step 3: Check the VPS's Own Firewall

This is the single most common cause of "site works from my SSH session but not in a browser." If you've got UFW:

sudo ufw status verbose

Make sure 80 and 443 are explicitly allowed. It's easy to lock down SSH and forget the web ports entirely, especially right after a fresh server setup.

If you're running CSF (common on cPanel VPS servers):

sudo csf -l | grep -E '80|443'

And check /etc/csf/csf.conf for TESTING = "1" — if CSF is stuck in testing mode, it auto-disables itself and its rules on a cron interval, which can look like intermittent connection failures that come and go every few minutes.

Step 4: Check the Cloud Provider's Firewall Too

This is the step people forget: the VPS's own firewall (UFW/CSF/iptables) can be wide open, and you'll still get ERR_CONNECTION_TIMED_OUT if the provider's network-level firewall — a security group, cloud firewall, or "VPC firewall rule" — is blocking the port upstream. This lives outside the server, in your provider's control panel, not in anything you can see over SSH.

If you're on a SkyServer VPS, check the firewall section of your VPS control panel and confirm inbound rules for 80/443 (and 22 for SSH) are present, not just outbound. A timeout with an otherwise healthy server almost always traces back to this layer or the one below it.

Step 5: Rule Out an IP-Level or ISP Block

If everything above checks out but the timeout is inconsistent — works on mobile data, fails on office Wi-Fi, or vice versa — you may be looking at a block further upstream: a corporate proxy, an ISP-level filter, or (rarely) the VPS's IP range being null-routed after an abuse complaint on a previous tenant of that IP. Test from a completely different network and from an online tool like check-host.net to see if the timeout is universal or localized to one network path.

Step 6: Check for a Reverse Proxy Misconfiguration

If you're running Nginx in front of an app (Node, PHP-FPM, Docker container) and the reverse proxy itself is up but the backend it forwards to isn't, you'd normally get a 502 — but if Nginx's own listen directive is bound to the wrong interface or the wrong port entirely, external requests get refused before they ever reach the proxy logic. Confirm the server block:

sudo nginx -T | grep -A3 "server_name yourdomain.com"

and make sure listen 80; and listen 443 ssl; are actually present in that block, not just in a default server block that isn't being matched.

Quick Reference Table

SymptomLikely CauseWhere to Look
Refused instantly, every timeNothing listening on the port, or firewall actively rejectsss -tlnp, UFW/CSF rules
Times out after a long waitCloud provider firewall dropping packets silentlyVPS control panel network/firewall settings
Works on SSH, fails in browserPort 80/443 not allowed even though 22 isFirewall rule list, not just "is the firewall on"
Works from one network, not anotherISP/corporate proxy block, not a server issueTest from check-host.net or mobile data
Intermittent, comes and goesCSF stuck in testing mode, service crashing/restartingcsf.conf TESTING flag, systemd logs

Prevention

Most of these incidents happen right after a change: a fresh server build where 80/443 were never opened, a firewall rule reorder that accidentally removed a web port, or a cloud security group edited for one project that quietly affected another. A couple of habits save the panic later:

  • After any firewall change, immediately test both 80 and 443 from an external network — not just from the server itself, since local checks can pass even when the outside world is blocked.
  • Keep a one-line note of your intended open ports somewhere outside the server (a README, a ticket, anything) so you can diff against it when something breaks six months later.
  • If you use CSF, disable testing mode explicitly once you've confirmed rules work — don't rely on it timing out on its own schedule.

Frequently Asked Questions

Why does the site work over SSH but not in a browser?

SSH uses port 22, which is almost always allowed by default. If 80/443 were never explicitly opened — common on a freshly hardened VPS — SSH keeps working while the web ports stay blocked. Check your firewall rule list for those specific ports, not just whether the firewall is "on."

Is ERR_CONNECTION_REFUSED always a firewall problem?

No. It also happens when nothing is actually listening on the port — a crashed Nginx/Apache process, a wrong listen directive, or a service bound to 127.0.0.1 instead of all interfaces. Run ss -tlnp before assuming it's the firewall.

What's the difference between this and a 502 Bad Gateway?

A 502 means a proxy successfully connected to your backend and got an invalid response back — the network path is fine. ERR_CONNECTION_REFUSED/TIMED_OUT means the connection attempt itself failed before any HTTP response was possible.

My provider's firewall and my server's firewall both look fine — what else could it be?

Check DNS first (is the domain even pointing at this server?), then test from a different network to rule out an ISP or corporate proxy block, and finally check if the IP was previously used by another customer and picked up a bad reputation or block somewhere upstream.

Can Cloudflare cause this even if my server is fine?

Yes — if Cloudflare's proxy (orange cloud) is enabled and your origin server's firewall only allows traffic from specific IPs, make sure Cloudflare's IP ranges are whitelisted, otherwise Cloudflare itself will see connection failures reaching your origin.