Ubuntu Port Connectivity: ss / lsof / nc / curl Troubleshooting
What You'll Learn
- How to isolate "can't connect" issues to network / server / application layer
- Avoid common mistakes like "assuming it's ufw" or "only checking if service is running"
- Master the command set (ss / lsof / nc / curl) for quick diagnosis
Quick Summary
When "can't connect", check in this order:
- DNS correct? (if needed)
- Can reach the port?
nc -vz HOST PORT - Server listening?
ss -lntp | grep :PORT - What process?
lsof -i :PORT - HTTP response?
curl -I http(s)://HOST - Service and logs
systemctl status/journalctl
Table of Contents
1. First, Clarify What's Not Connecting
Establish these 3 things first:
- HOST: Domain or IP
- PORT: 22 / 80 / 443 / 3000 / 8080 / 3306 etc.
- Protocol: SSH? HTTP? Database?
2. Client Side: Can You Reach It? (nc)
Key point: Test reachability from client BEFORE touching the server.
$ nc -vz example.com 22
Reading the results (crucial)
succeeded→ Network path works (now check server/app)timed out→ Can't reach (FW/SG/route/DNS/server down)refused→ Reached but nothing listening (service stopped/wrong port/wrong bind)
3. Server Side: Is It Listening? (ss)
When nc refused, this tells you definitively.
$ sudo ss -lntp
Options:
-l: Listening sockets-n: Numeric (no DNS lookup)-t: TCP-p: Show process (needs sudo)
Common trap: 127.0.0.1 only
If you see:
LISTEN 0 4096 127.0.0.1:3000 ...
This only accepts localhost connections. For external access, it needs to bind to 0.0.0.0:3000.
4. Who's Holding the Port? (lsof)
$ sudo lsof -i :80
If an unexpected process is holding the port, that's your conflict.
5. HTTP: Check Response (curl)
For web/API, "port open but 500 error" is common.
$ curl -I http://example.com $ curl -I https://example.com
Status code meanings
200: OK301/302: Redirect403: Forbidden (auth/WAF/IP restriction)404: Not found (routing/path)500: Internal error (check logs)502/503/504: Upstream/backend problem
6. DNS Troubleshooting
# Check what IP the domain resolves to $ dig example.com +short # Test with IP directly (bypasses DNS) $ nc -vz 203.0.113.10 80
If IP works but domain doesn't → DNS or CDN/WAF issue.
7. Service Check (systemctl / journalctl)
When nc succeeded but app isn't responding:
$ sudo systemctl status nginx $ sudo journalctl -u nginx -n 200
Don't stop at "it's running". Services can crash immediately after start or be in restart loops - check logs.
8. Error Messages Explained
nc: connect ... timed out
Causes: ufw, cloud FW (SG), corporate FW, routing, server down
nc: connect ... refused
Causes: Nothing listening, wrong port, process down
curl: (7) Failed to connect
Causes: Can't reach (timeout) or nothing listening
curl: (60) SSL certificate problem
Causes: Certificate/hostname/intermediate cert issue
curl -I returns 502 Bad Gateway
Causes: nginx/apache → upstream (app) is dead or wrong port
Copy-Paste Template
# Client side (reachability) nc -vz example.com PORT # Server side (listening check) sudo ss -lntp | grep ":PORT " # Server side (process holding port) sudo lsof -i :PORT # HTTP response check curl -I http://example.com curl -I https://example.com # Service/logs sudo systemctl status <service> sudo journalctl -u <service> -n 200
Test Environment
Commands in this article were tested on Ubuntu 24.04 LTS / bash 5.2.