RDP Monster

Check Open Ports in Linux: ss, netstat, lsof, nmap

Check Open Ports in Linux: ss, netstat, lsof, nmap

Check open ports with ss, the modern standard

Every open port on a Linux system exists because a process asked the kernel to listen on it. The tool that shows you those sockets today is ss (socket statistics), part of the iproute2 suite installed on every modern distribution. One command covers most situations:

sudo ss -tulpn

Each flag does one job:

  • -t: include TCP sockets
  • -u: include UDP sockets
  • -l: show only listening sockets (drop it to also see established connections)
  • -p: show the process that owns each socket; this is why you want sudo, since without it you only see your own processes
  • -n: numeric output; print :22 instead of :ssh and skip reverse DNS lookups, which also makes the command faster

A typical line of output looks like this:

Netid State  Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
tcp   LISTEN 0      128          0.0.0.0:22         0.0.0.0:*    users:(("sshd",pid=712,fd=3))

The Local Address column is the one that matters for security. 0.0.0.0:22 means the socket accepts connections on every IPv4 interface, [::]:22 is the IPv6 equivalent, and 127.0.0.1:5432 means the service answers on loopback only and cannot be reached from the network at all.

A few variations worth memorizing:

ss -tlnp                      # TCP listeners only
ss -ulnp                      # UDP listeners only
sudo ss -tlnp 'sport = :22'   # who is listening on port 22
ss -tn state established      # active TCP connections right now

netstat still works, but it is legacy

Millions of tutorials still say netstat -tulpn, and the flags map one to one onto the ss command above, so the muscle memory transfers in both directions. The difference is under the hood: netstat belongs to the maintenance-mode net-tools package and reads /proc files, while ss queries the kernel directly over netlink, which is noticeably faster on machines juggling thousands of sockets.

Most current distributions no longer ship net-tools by default. If you need it anyway:

sudo netstat -tulpn

# if the command is missing:
sudo apt install net-tools    # Debian / Ubuntu
sudo dnf install net-tools    # RHEL / Fedora

There is no reason to install it on a new server. Treat netstat as a compatibility fallback for older systems you inherit, and use ss everywhere else.

lsof: ports through the lens of processes

On Linux everything is a file, including network sockets, so lsof (list open files) doubles as a port inspector. It shines when you already think in terms of processes rather than ports:

sudo lsof -i -P -n                  # every process with a network socket
sudo lsof -iTCP -sTCP:LISTEN -P -n  # TCP listeners only
sudo lsof -i :443                   # everything touching port 443

-P and -n disable port-name and hostname resolution, the same idea as the -n in ss -tulpn. The third form is the everyday one: point it at a port and you get the command name, PID, user and file descriptor in one readable table. Unlike ss, lsof also lists the established connections of each process alongside its listeners, which helps when you want to know who is currently talking to a service, not just that the service exists.

nmap: listening is not the same as reachable

Everything so far answers one question: what is listening on this machine. A different question matters more for security: what can actually be reached from outside. The two lists are rarely identical, because host firewalls, provider-level filtering and loopback-only binds all create gaps between them. This is also why scanning yourself from yourself proves little: nmap localhost travels over the loopback interface, bypasses your external firewall rules entirely, and happily reports services that no attacker could ever reach.

Run the scan from a different machine, pointed at the server's public IP:

nmap 203.0.113.10                            # top 1000 TCP ports
nmap -p- 203.0.113.10                        # all 65535 TCP ports
sudo nmap -sU --top-ports 100 203.0.113.10   # common UDP ports (slow)

nmap reports three states worth understanding: open means a service answered, closed means the packet arrived but nothing listens there, and filtered means the packet was silently dropped, almost always by a firewall. A port that ss shows as LISTEN but a remote nmap reports as filtered is exactly what a working firewall looks like. One rule applies without exception: only scan hosts you own or are explicitly authorized to test.

Find exactly which process holds a port

Suppose something is squatting on port 8080 and your application cannot bind. Three roads lead to the PID:

sudo ss -tlnp 'sport = :8080'
sudo lsof -i :8080
sudo fuser -v 8080/tcp

fuser is the most compact: it prints the PID, and -v adds the user and command name. It can even kill the offender directly with fuser -k 8080/tcp, but that sends a signal without any service-level cleanup, so treat it as a last resort. Once you have a PID, ps -fp PID shows the full command line, and systemctl status PID tells you which systemd unit spawned it.

When you have no tools at all (a stripped-down container image, for instance), the kernel's own table is always there: cat /proc/net/tcp. Ports appear in hexadecimal (0016 is 22) and state 0A means LISTEN. This raw table is the very data the other tools parse and format for you.

Everything that binds a socket shows up in these listings the same way, whether it is a database or a proxy stack. A V2Ray inbound, for example, is just another listener on whatever port you configured, as explained in our V2Ray protocol guide.

Close an open port: kill vs firewall

A port is open because a process listens on it, which gives you two distinct levers: remove the listener, or block reachability. They are not interchangeable, and on anything important you should usually pull both.

The clean fix is to stop and disable the service that owns the socket. Killing the PID looks quicker but rarely sticks: systemd restarts supervised services automatically, and the port is back before you re-run ss. Reserve kill for processes you started by hand. To see what is running and switch off what you do not need, our guide to listing services with systemctl covers that workflow end to end.

sudo systemctl stop cups
sudo systemctl disable cups

The firewall handles the second lever. On Ubuntu, allow SSH before enabling ufw, or you will lock yourself out of the box:

sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw enable

On RHEL-family systems, firewalld's default zone already drops unsolicited traffic; remove anything you previously opened with firewall-cmd --permanent --remove-port=8080/tcp followed by firewall-cmd --reload. One thing that is not a fix: moving a service to a non-standard port. It hides you from the laziest scans and quiets your logs, but nmap -p- finds the new port in minutes. Obscurity is not security — close the port or firewall it.

A five-minute port audit for a new server

First login on a freshly provisioned box, run the inventory with sudo ss -tulpn. A clean minimal install should show very little: sshd on 22 and, on distributions using systemd-resolved, a DNS stub on 127.0.0.53:53. Anything else deserves an explanation. Then work down this checklist:

  1. Identify every listener by process name and PID; disable any service you did not ask for.
  2. Challenge every 0.0.0.0 or [::] bind: databases and admin panels belong on 127.0.0.1 unless they genuinely serve the network.
  3. Recognize common ports on sight: 22 SSH, 80/443 web, 3306 MySQL, 5432 PostgreSQL, 6379 Redis. Port 3389 is remote desktop. On Linux it means xrdp is running, and that port's exposure and hardening rules are the subject of our RDP port 3389 guide.
  4. Scan the public IP from your own machine with nmap -p- and diff the result against the ss list; every mismatch is either a firewall doing its job or a loopback bind.
  5. Finish with a default-deny firewall that allows only the ports you consciously chose to expose.

Here is the whole toolbox on one line each:

CommandShowsUse it when
sudo ss -tulpnListening TCP/UDP sockets with owning processEveryday first look on any machine
netstat -tulpnSame view via legacy net-toolsOlder systems where ss is absent
sudo lsof -i :PORTProcesses and connections on one portTying a port to a process and its files
sudo fuser -v PORT/tcpPIDs bound to a portFast PID lookup, scripting
nmap SERVER_IP (remote)Ports actually reachable from outsideVerifying firewall and real exposure
cat /proc/net/tcpRaw kernel socket table (hex)Minimal containers with no tools installed

Commands only become reflexes on a machine where you hold real root and nothing that matters can break. A Linux VPS from rdp.monster gives you exactly that sandbox: full admin access, dedicated CPU and RAM, unlimited (fair-use) bandwidth, no KYC, and the server is online about 10 seconds after payment confirms, quick enough to run your first ss -tulpn on it before your coffee cools.

Frequently Asked Questions

Do I need root to check open ports on Linux?

No for listing ports, yes for seeing which process owns them.
Any user can run ss -tuln or read /proc/net/tcp, so the list of listening ports is never hidden. The -p flag is where the limit sits: without root, ss, lsof and fuser only reveal processes belonging to your own user, and other sockets appear with an empty process column. With nmap, the default SYN scan (-sS) requires root; the unprivileged fallback is the connect scan (-sT), which works fine but is a little noisier.

How do I check if a specific port is open on a remote server?

Use netcat: nc -zv host port gives an instant answer.
nc -zv example.com 443 attempts a TCP connection and reports success or failure without sending data. If netcat is missing, plain Bash can do it: timeout 3 bash -c '</dev/tcp/example.com/443' && echo open. Both only prove that something accepted the connection; they say nothing about which service answered or whether it is healthy. For UDP there is no reliable quick test, because a silent port can be open or filtered; use nmap -sU there.

Why does ss show a port as listening but I cannot connect from outside?

The socket is bound to loopback or a firewall is dropping the traffic.
Check the Local Address column first: 127.0.0.1:PORT or [::1]:PORT means the service accepts local connections only, which is deliberate and common for databases. If it is bound to 0.0.0.0, packets are being filtered somewhere on the path: a host firewall such as ufw, firewalld or raw nftables, or your provider's edge filtering. An external nmap scan reporting the port as filtered confirms a firewall; closed means traffic arrives but nothing listens on that interface.

What ports should be open on a fresh Linux server?

One: SSH. Anything else on a clean install deserves an explanation.
A minimal Debian, Ubuntu or Rocky install should expose only sshd on port 22 to the network. A stub DNS resolver on 127.0.0.53:53 (systemd-resolved) is normal and unreachable from outside. Cloud images sometimes add an agent or monitoring daemon, so identify each listener with ss -tulpn and disable anything you did not ask for. Every service you install afterwards should default to loopback unless it genuinely needs to serve the network, with the firewall allowing only what is public.

Adrien Roche, Infrastructure & Hosting Editor

Systems engineer with 10+ years operating Windows Server and Linux fleets. Adrien runs the rdp.monster infrastructure documentation and writes our guides on RDP, VPS hosting, server administration, networking and privacy tooling.

Register to our reseller program

Your information

If you have any question, contact us by clicking here !
Name(Required)
Enter your email address, you must have an account on manager.rdp.monster !

Your company

Enter your website address if you have one
Quickly explain how you're going to sell services to your customers. For example, talk to people on forums.

We're using cookies!

We use cookies to enhance your browsing experience, serve personalized ads or content, and analyze our traffic. By clicking "Accept", you consent to our use of cookies.