In short. A refusal is a positive signal: a machine at that address received your connection attempt and actively answered "nothing here". That distinguishes it from a timeout, where nothing answers at all, and it narrows the cause to a short list — the service is not running, it is listening on the wrong interface, or a firewall is rejecting rather than dropping.
Refused, dropped and reset are three different answers
Browsers show similar messages for all three, but at the network level they are distinct events with distinct causes. Telling them apart takes one command and eliminates most of the possibilities.
| What happened | Network event | Meaning | Likely cause |
|---|---|---|---|
| Refused | Immediate reset on connect | Host is alive; nothing accepts on that port | Service stopped, wrong interface, firewall REJECT |
| Timed out | No answer at all | Packets are being discarded silently | Firewall DROP, wrong address, host gone |
| Reset mid-session | Reset after connecting | Connection accepted, then terminated | Application crash, proxy limit, inspection device |
nc -vz -w 5 example.com 443
# "succeeded" -> port is open; the problem is above TCP
# "Connection refused" -> this article
# hangs, then times out -> a different problem entirely
Refusal is the most informative of the three. Something is running at that address and it is reachable — the network path works, routing works, the host is up. Only the specific port is closed, which is a much smaller search space than a timeout gives you.
If you are not yet sure which layer is failing at all, the layer isolation guide covers the full sequence from DNS to application.

Is it you or the site?
Two checks, thirty seconds, and they split the problem cleanly.
- Does another site work? If everything is refused, look at your own machine or network — a local proxy setting, a security product, a captive portal.
- Does it fail from a second network? Mobile tethering is enough. Working elsewhere means the block is on your current network, not on the site.
The port checker answers this from outside your network entirely, and it reports closed and filtered as separate results — which is exactly the distinction the browser hides.
If it is your side
- A proxy configured that no longer exists. Uninstalled VPNs and security tools leave the setting behind; every connection is then attempted against a dead address.
- Local firewall or security suite rejecting outbound connections on that port.
- A hosts file entry pointing the name at
127.0.0.1— the connection reaches your own machine, which refuses because nothing is listening there.
# Is something redirecting this name locally?
grep -i example.com /etc/hosts # macOS, Linux
# Windows: C:\Windows\System32\drivers\etc\hosts
# Is a proxy set that you did not intend?
env | grep -i proxy
scutil --proxy 2>/dev/null | head
Server side: the four causes, in order of frequency
1. The service is not running
Simple, common, and worth confirming rather than assuming. A process that exited on an unhandled error or was killed for memory leaves the port closed while the host stays perfectly reachable.
systemctl status nginx --no-pager
sudo ss -tlnp | grep -E ':(80|443)\s' # what is actually listening
sudo journalctl -u nginx --since '1 hour ago' --no-pager | tail -20
sudo journalctl -k --since '1 hour ago' | grep -i 'killed process' # OOM
2. It is listening, but not where you can reach it
This is the cause that wastes the most time, because systemctl status reports the service as active and healthy. A process bound to 127.0.0.1 accepts connections from the machine itself and refuses everything from outside — so it works when you test over SSH and refuses every real visitor.
sudo ss -tlnp | grep ':443'
# LISTEN 0 511 127.0.0.1:443 -> loopback only: refuses external connections
# LISTEN 0 511 *:443 -> all interfaces: reachable
# LISTEN 0 511 [::]:443 -> IPv6 (often covers IPv4 too, depending on config)
The fix is in the service's own configuration — nginx listen, an application's bind address, a container's published port. Testing from the server itself cannot detect this, which is precisely why it survives.
If the service works when you
curlit on the server and refuses from anywhere else, stop reading logs. That exact combination is the signature of a loopback binding, and onessline confirms it.
3. A firewall rejecting rather than dropping
Firewalls can discard a packet silently or answer it with a refusal. Which one you configured decides whether the visitor gets a timeout or an instant refusal — and an instant refusal from a firewall looks exactly like a stopped service.
# Linux
sudo iptables -L -n --line-numbers | grep -E 'REJECT|DROP'
sudo ufw status verbose
sudo firewall-cmd --list-all
# Is the port allowed at all?
sudo ss -tlnp | grep ':443' # listening?
sudo iptables -L INPUT -n | grep 443
Cloud providers add another layer above the host: a security group or network ACL can reject before a packet ever reaches your firewall. Check both, because the host-level rules can be perfectly permissive while the cloud rule closes the port.
4. Containers and port mapping
A container listening correctly inside its own namespace is unreachable if the port is not published, or if it is published only on loopback. The application logs look healthy from inside and the outside world gets a refusal.
docker ps --format '{{.Names}}\t{{.Ports}}'
# 0.0.0.0:8080->80/tcp reachable externally
# 127.0.0.1:8080->80/tcp loopback only — external connections refused
# 80/tcp not published at all

Port 80 works and 443 does not (or the reverse)
When one port answers and the other refuses, the network is proven fine and the problem is a specific listener. That is a useful and frequently overlooked result.
for p in 80 443; do
printf 'port %-4s ' "$p"
nc -vz -w 5 example.com "$p" 2>&1 | tail -1
done
Refused on 443 with 80 open usually means TLS was never configured, the configuration failed to load, or the certificate file the server points at is missing — many servers refuse to start their TLS listener entirely rather than start without a valid certificate. Check the configuration test output rather than only the service status:
nginx -t # names the failing directive and file
apachectl configtest
The "it works locally" trap
Nearly every cause above is invisible from the server. Loopback bindings, host firewalls, cloud security groups and unpublished container ports all permit local connections and refuse external ones, so the entire class survives any test run on the machine itself.
Test from outside, always. The port checker connects from an unrelated network and distinguishes open, closed and filtered — the three outcomes that map exactly onto the three causes in the table at the top.
Preventing the recurrence
A refusal means a total outage for that service, with no partial state and no gradual degradation. Two things reduce the time it lasts:
- Watch the port from outside. An internal health check running on the same host cannot detect a loopback binding or a firewall rule — it is on the wrong side of both.
- Alert on the transition, not on a threshold. There is no "slightly refused"; the state changes in one step, so the first failed external check is the signal.
Scheduled monitoring connects from outside on the ports you register and records every result, which turns "the site was down for a while last night" into a start time, an end time and a duration you can line up against a deploy or a restart.

A working order
- Confirm it is refusal, not timeout —
nc -vzdistinguishes them immediately. - Check whether other sites fail, to split your side from the server's.
- Test both 80 and 443. One working proves the network path.
- On the server, check what is listening and on which interface — this is where the loopback case is caught.
- Check the firewall, host-level and cloud-level.
- Check container port publishing, if containers are involved.
- Verify from outside after every change, never from the server.
How to check right now
Use the port checker to see open, closed and filtered from outside your network — the fastest way to confirm a refusal is real and not local. Ping and TCP checks confirm the host is reachable at all, and traceroute shows whether the path completes. If the port is open and the failure is above TCP, the SSL checker and the header checker continue from there.

Frequently asked questions
How is this different from a timeout?
A refusal is an answer: the host received your packet and replied that nothing accepts on that port. A timeout is silence, which usually means a firewall discarding packets or an address that no longer hosts anything. Opposite causes, similar-looking messages.
Is it my problem or the site's?
If other sites load and a second network gives the same refusal, it is the site's. If everything is refused on one network only, it is that network — a proxy setting, a security product or a captive portal.
The service is running but connections are refused.
Check which interface it is bound to. A process on 127.0.0.1 reports as healthy, accepts local connections and refuses every external one. One ss -tlnp line settles it.
Will restarting the router help?
Rarely, and only if a captive portal or a stale local setting is involved. A refusal coming from the destination is unaffected by anything on your network.
Why does port 80 work while 443 is refused?
The network path is fine and the TLS listener is not running. Most often the configuration failed to load or the certificate file it references is missing — many servers decline to start the TLS listener at all rather than serve without a valid certificate.
How do I find out quickly next time?
Monitor the port from outside the host. Internal checks sit inside the firewall and inside the loopback boundary, so they pass through exactly the conditions that cause this error.
Checklist
- Confirm refusal rather than timeout before investigating anything.
- Check whether other sites fail, and whether a second network behaves differently.
- Test 80 and 443 separately — one working proves the path.
- Look at the listening interface, not just the service status.
- Remember that a loopback binding passes every test run on the server.
- Check host firewall and cloud security rules separately.
- Verify container ports are published beyond loopback.
- Read the configuration test output when a TLS listener will not start.
- Test from outside after every change.
- Monitor the port externally; internal checks cannot see this class of failure.