# How to check open ports on Linux with ss and nmap

> List the ports your server listens on with ss, find which program owns each one, then scan the server from outside with nmap to see what the internet can reach.

Source: https://vpsnine.com/tutorials/check-open-ports-linux · Updated: 2026-10-21

Difficulty: beginner · Time: about 10 minutes · Tested on: Ubuntu 24.04 LTS

Prerequisites:

- A Linux server
- Root or a user with sudo
- A second machine (your computer) for the outside scan

To check which ports are open on a Linux server, run `sudo ss -tulpn`: it lists every TCP and UDP port the server listens on, the address it's bound to, and the program behind it. To see which of those the internet can actually reach through your firewalls, scan the server from another machine with `nmap 203.0.113.10`.

You need both views. `ss` shows what's listening; `nmap` from outside shows what gets through. A database listening on `0.0.0.0:5432` with the firewall blocking it is fine; the same database reachable from the internet isn't. Only scan servers you own or have permission to scan: scanning other people's machines can break your provider's terms and, in some places, the law.

We ran every command here on Ubuntu 24.04 with nginx and OpenSSH installed. `ss` is part of `iproute2` and preinstalled on every current distribution.

## List listening ports with ss

```bash
sudo ss -tulpn
```

The letters: `t` TCP, `u` UDP, `l` listening only, `p` show the process (needs `sudo`), `n` numeric ports instead of names. Trimmed output:

```text
Netid State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp   UNCONN 0      0      127.0.0.53%lo:53        0.0.0.0:*    users:(("systemd-resolve",pid=68,fd=14))
tcp   LISTEN 0      511          0.0.0.0:80        0.0.0.0:*    users:(("nginx",pid=1456,fd=5))
tcp   LISTEN 0      4096         0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=1108,fd=3))
tcp   LISTEN 0      5          127.0.0.1:8000      0.0.0.0:*    users:(("python3",pid=3187,fd=3))
tcp   LISTEN 0      511             [::]:80           [::]:*    users:(("nginx",pid=1456,fd=6))
```

The column that matters is **Local Address**:

| Bound to | Who can connect |
| --- | --- |
| `0.0.0.0:80` or `[::]:80` (or `*:80`) | Any address, IPv4 or IPv6: the internet, unless a firewall stops it |
| `203.0.113.10:80` | Only via that one address |
| `127.0.0.1:8000` or `[::1]:8000` | Only programs on the server itself |
| `127.0.0.53%lo:53` | The local DNS resolver; normal on Ubuntu |

On a fresh server you'll typically see SSH on 22 and the local resolver. Everything else should be something you installed on purpose. Anything that doesn't need outside connections, such as a database used only by an app on the same server, an admin dashboard or a metrics endpoint, is safer bound to `127.0.0.1`.

Only TCP ports:

```bash
sudo ss -tlnp
```

## Find out what owns a port

Filter `ss` on one port:

```bash
sudo ss -tlnp 'sport = :80'
```

Or ask `lsof`:

```bash
sudo lsof -i :80 -sTCP:LISTEN
```

With the PID, find the program and the systemd service it belongs to:

```bash
ps -o pid,user,cmd -p 1108
systemctl status 1108
```

`systemctl status` accepts a PID and shows the unit that owns it, which is the one to stop, disable or reconfigure.

## Check from outside with nmap

Run this from your own computer, not from the server: a scan from the server itself goes around the firewall and tells you nothing about what the internet sees. Install nmap (`sudo apt install nmap`, `brew install nmap`, or the Windows installer from nmap.org), then:

```bash
nmap -Pn 203.0.113.10
```

`-Pn` skips the "is the host up?" ping, which a firewall may block. Without a port list, nmap checks the 1,000 most common TCP ports:

```text
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
```

What the states mean:

| State | Meaning |
| --- | --- |
| `open` | Something listens and the firewall lets you in |
| `closed` | Nothing listens there, but the packet reached the server |
| `filtered` | No answer at all: a firewall dropped the packet |

Check specific ports, including ones outside the top thousand:

```bash
nmap -Pn -p 22,80,443,5432,8080 203.0.113.10
```

UDP ports (WireGuard, DNS) need a UDP scan, which needs root on your computer and is slower:

```bash
sudo nmap -Pn -sU -p 51820,53 203.0.113.10
```

UDP results are less clear-cut: `open|filtered` is common, because a service like WireGuard doesn't answer packets it doesn't recognise. `ss -ulpn` on the server is the better check for UDP.

Scan IPv6 too, if the server has an address; the firewall rules are separate:

```bash
nmap -6 -Pn 2001:db8::10
```

## A quick single-port test

To check one TCP port without nmap, `nc` (netcat) is enough:

```bash
nc -zv 203.0.113.10 443
```

`succeeded` means open; `Connection refused` means closed; no answer until the timeout means filtered.

## Close what shouldn't be open

For each port that's open but shouldn't be, pick one:

1. **Stop the service** if you don't need it: `sudo systemctl disable --now SERVICE`.
2. **Bind it to localhost** in its configuration (`bind-address = 127.0.0.1` for MySQL and MariaDB, `listen_addresses = 'localhost'` for PostgreSQL), and restart it.
3. **Block it in the firewall**: [ufw](https://vpsnine.com/help/firewall-with-ufw) on Ubuntu and Debian, [firewalld](https://vpsnine.com/tutorials/firewalld-almalinux-rocky) on AlmaLinux and Rocky Linux.

Then scan again from outside to confirm.

## Troubleshooting

**`ss` shows no process names.** You ran it without `sudo`; other users' processes are hidden.

**A port is open in `nmap` but `ss` doesn't show it.** You might be scanning the wrong address, or Docker published the port: Docker's forwarding happens in the firewall, so `docker-proxy` or nothing at all appears in `ss`. `docker ps` shows the published ports.

**Everything shows `filtered`.** A firewall in front of the server drops all traffic from your address: the panel firewall, a cloud security group, or your own network blocking outgoing scans. Check from a second connection, such as a phone hotspot.

**SSH shows as `systemd` in `ss` on Ubuntu 24.04.** SSH is socket-activated there: systemd holds port 22 and hands connections to `sshd`. It's normal.

## Next steps

- Lock down what's left with [ufw](https://vpsnine.com/help/firewall-with-ufw) or [firewalld](https://vpsnine.com/tutorials/firewalld-almalinux-rocky).
- Measure the connection itself: [test your server's network](https://vpsnine.com/help/test-your-network).

## Doing it on VPSNine

On VPSNine, the [panel firewall](https://vpsnine.com/help/server-firewall) filters traffic before it reaches the server. Ports it denies don't show as `open` in `nmap`, even when `ss` shows something listening on them, which is what you want for anything private. Outbound port 25 is blocked on new servers; that doesn't affect inbound scans ([details](https://vpsnine.com/help/open-port-25)). Works on [Ubuntu 24.04](https://vpsnine.com/os/ubuntu-24.04) and every other image, on all [plans](https://vpsnine.com/plans).
