Fix ERR_CONNECTION_TIMED_OUT When Connecting to a Server

intermediate🌐 Networking2026-03-22| Linux (Ubuntu/Debian/CentOS), Windows Server, macOS β€” any server accessible via HTTP/HTTPS or TCP

Error Message

This site can't be reached. ERR_CONNECTION_TIMED_OUT
#networking#timeout#connection#firewall

The Error

You open a browser or fire off a request and get:

This site can't be reached. ERR_CONNECTION_TIMED_OUT

This is different from ERR_CONNECTION_REFUSED. Refused means something actively rejected the connection. Timeout means the TCP handshake never completed β€” your packets went out, nothing came back, and eventually the client gave up waiting.

Root Causes

  • Firewall (server-side or network-level) silently dropping packets on the target port
  • Server process not listening on the expected port
  • Wrong IP or DNS resolving to the wrong host
  • Security group / cloud ACL blocking inbound traffic
  • Routing issue β€” packets never reach the server
  • Server overloaded and not accepting new connections

Step 1 β€” Confirm the Server Is Reachable at All

First, try a plain ping to see if the host is reachable at the network level:

ping your-server-ip

Ping timing out means the problem is at the network or routing layer β€” before your app even gets involved. Ping succeeding but the port still failing points to a firewall or service issue.

From there, check whether the specific port is open:

# Check if port 80 or 443 is reachable
telnet your-server-ip 80

# Or with netcat
nc -zv your-server-ip 443

Hangs with no output? The port is being filtered β€” the firewall is silently dropping packets. Connection refused is actually better news: it means the port is reachable, but no service is listening on it.

Step 2 β€” Check What's Listening on the Server

SSH in and confirm your service is running and bound to the right address:

# Check listening ports
ss -tlnp

# Or with netstat
netstat -tlnp | grep LISTEN

This is where a lot of setups go wrong. A service bound to 127.0.0.1:80 only accepts local connections β€” it ignores anything coming in from outside. You need 0.0.0.0:80 to accept external traffic.

Fix the binding in nginx:

server {
    listen 0.0.0.0:80;  # Was: listen 127.0.0.1:80;
    ...
}

For Node.js apps:

// Wrong β€” only localhost
app.listen(3000, '127.0.0.1');

// Correct β€” all interfaces
app.listen(3000, '0.0.0.0');

Step 3 β€” Check the Firewall

Linux (iptables / ufw)

# Check ufw status
sudo ufw status

# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
# Check raw iptables rules
sudo iptables -L INPUT -n -v

# Allow port 80 if missing
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Save rules
sudo iptables-save > /etc/iptables/rules.v4

CentOS / RHEL (firewalld)

sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Cloud Providers β€” Security Groups

On AWS, GCP, Azure, or DigitalOcean, the OS firewall might be wide open β€” but the cloud-level security group is still blocking traffic. These are separate layers and both need to allow the port. Check inbound rules in the cloud console:

  • AWS: EC2 β†’ Security Groups β†’ Inbound Rules β†’ Add port 80/443 from 0.0.0.0/0
  • GCP: VPC Network β†’ Firewall β†’ Add rule for tcp:80,443
  • DigitalOcean: Networking β†’ Firewalls β†’ Inbound Rules

Step 4 β€” Check DNS Resolution

A stale DNS record can send traffic to an old server IP β€” one that no longer exists or belongs to someone else entirely:

# See what IP the domain resolves to
nslookup yourdomain.com
dig yourdomain.com A

# Compare with actual server IP
curl ifconfig.me  # run on the server

Mismatched IPs mean your DNS A record needs updating. Propagation typically takes under an hour with a low TTL (300 seconds or less), though worst-case scenarios can stretch to 48 hours.

Step 5 β€” Trace the Route

Still stuck? Traceroute will show you exactly where in the network path packets stop getting responses:

# Linux/macOS
traceroute your-server-ip

# Windows
tracert your-server-ip

Watch for where hops stop replying. That's your block. Whether it's your ISP, a transit provider, or the server's own network interface β€” traceroute narrows it down fast.

Step 6 β€” Check Server Load and Resource Limits

An overloaded server can silently drop new connections β€” no error, just silence:

# Check CPU and memory
top
free -m

# Check if the connection queue is full (for nginx)
ss -s

# Check nginx/apache error logs
tail -f /var/log/nginx/error.log
tail -f /var/log/apache2/error.log

Seeing accept4() failed (24: Too many open files) in your logs? That's the Linux file descriptor limit hitting. The default is 1024 on many systems β€” way too low for a busy server. Raise it:

# /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536

# Also in nginx.conf
worker_rlimit_nofile 65536;

Verification

Once you've made changes, test from a client machine β€” not from the server itself:

# Test HTTP response
curl -v http://your-server-ip
curl -v https://yourdomain.com

# Check response time
curl -w "Connect: %{time_connect}s\nTotal: %{time_total}s\n" -o /dev/null -s https://yourdomain.com

A HTTP/1.1 200 OK means you're good. Connect time under 200ms is normal for a nearby server β€” if it's still a second or more, something upstream is still slow.

Prevention Tips

  • Open firewall rules before deploying a service, not after you've already lost time debugging
  • Bind services to 0.0.0.0 (or a specific external interface) when external access is needed β€” never 127.0.0.1
  • Set explicit connection timeouts on your reverse proxy (e.g., proxy_connect_timeout 10s in nginx) so clients fail fast instead of hanging for 30+ seconds
  • Monitor your server's connection queue and file descriptor limits β€” set alerts before they become incidents

When subnetting or trying to figure out whether an IP falls within an allowed CIDR range in your firewall rules, the Subnet Calculator on ToolCraft is handy β€” it runs entirely in the browser with no data uploaded, so it's safe to paste internal IP ranges into it.

Related Error Notes