How to Find the Port Opened By a Process on Linux

In this tutorial you will learn how to find the port of a process running on a Linux system.

This is a very common thing we need to know when we manage applications on Linux, especially if they have been configured by someone else.

How do you find the port of a process running on Linux?

The netstat command allows to see the connections from and to our current Linux systems and it provides flags that also show which process a specific connection is related to. In the netstat output you can also see the port opened by a specific process. You can also see which ports are opened on a Linux system using the lsof, ss and fuser commands.

You will learn which netstat flags to use to show the port opened by a process on Linux and other tricks that can be very useful to manage a Linux system.

We will also go through alternatives to netstat like lsof, ss and fuser.

Let’s go for it!

What Ports Are Listening on Linux?

I see often that the concept of port is not easy to grasp for those who start learning about Linux.

A port is a communication channel opened on a Linux system when a process starts, ports allow users or programs outside of the Linux system to communicate with it.

All the examples in this tutorial are based on a common application running on Linux systems, an Apache Web Server.

When started, Apache opens ports (usually 80 or 443) that allow users to access static content or web pages hosted on our Linux system.

Ports are represented by numbers from 0 to 65535. The following table shows the meaning of different port ranges:

Port RangeHow these ports are used
0 to 1023Well known ports or system ports.
Used by system processes to provide standard network services.
Only processes with superuser privileges can open a port in this range on a Linux system.
1024 to 49151Registered ports.
These ports are assigned by IANA for specific applications (e.g. 1521 for Oracle).
They can be opened on a system without superuser privileges.
49152 to 65535Dynamic or private ports.
They cannot be registered with IANA and they are used for automatically allocating ephemeral ports.

The file /etc/services on Linux contains the details of all the reserved ports.

For example, using the grep command let’s find the port assigned to the SMTP protocol:

[ec2-user@ip-172-31-1-2 ~]$ grep -i "^smtp" /etc/services 
smtp            25/tcp          mail
smtp            25/udp          mail

As you can see port 25 is used by the SMTP protocol, it’s one of the well-known ports considering that its value is lower than 1023 (do you remember the previous table?)

Another concept related to the concept of port is the socket.

What is a Linux socket?

A Linux socket is the combination of IP address, protocol (e.g. TCP or UDP) and port. TCP stands for Transmission Control Protocol, UDP stands for User Datagram Protocol.

Let’s start with the first command!

Netstat Command to Check Ports Listening on Linux

The main command to check open ports on a Linux system is netstat.

If I want to verify which ports are open, I can use the command netstat -na together with the grep command to filter only ports that are in listening state:

[ec2-user@ip-172-31-1-2 ~]$ netstat -na | grep -w "LISTEN"
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp6       0      0 :::111                  :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     

The grep command uses the -w flag to match the exact word “LISTEN”. It wouldn’t match a line that contains the word “LISTENING”.

But something is missing in the output, I would like to see what each column means…

[ec2-user@ip-172-31-1-2 ~]$ netstat -na | egrep -w "Local Address|LISTEN"
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp6       0      0 :::111                  :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     

Using egrep I can filter the output using a OR logic that shows the lines that match either “Local Address” (one of the column names) or “LISTEN”.

Here is the meaning of the main columns:

  • Proto: protocol used by the socket (tcp, udp, etc..)
  • Local Address: address and port number of the local end of the socket.
  • Foreign Address: address and port number of the remote end of the socket.
  • State: state of the socket (LISTEN, ESTABLISHED, etc..)

When I look at the output of the netstat command I can see a list of sockets (protocol, IP address and port). And I can also quickly see that there is no Apache Web Server running on this Linux server.

How?

Because I don’t see a TCP port that I could associate to a web server, for example 80 or 443.

Let’s verify the status of Apache using the systemctl command:

[ec2-user@ip-172-31-1-2 ~]$ sudo systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: man:httpd.service(8)

As you can see Apache is inactive, let’s start it!

[ec2-user@ip-172-31-1-2 ~]$ sudo systemctl start httpd
[ec2-user@ip-172-31-1-2 ~]$ sudo systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: active (running) since Mon 2020-08-03 11:10:54 UTC; 13s ago
     Docs: man:httpd.service(8)
 Main PID: 5256 (httpd)
   Status: "Total requests: 0; Idle/Busy workers 100/0;Requests/sec: 0; Bytes served/sec:   0 B/sec"
   CGroup: /system.slice/httpd.service
           ├─5256 /usr/sbin/httpd -DFOREGROUND
           ├─5257 /usr/sbin/httpd -DFOREGROUND
           ├─5258 /usr/sbin/httpd -DFOREGROUND
           ├─5259 /usr/sbin/httpd -DFOREGROUND
           ├─5260 /usr/sbin/httpd -DFOREGROUND
           └─5261 /usr/sbin/httpd -DFOREGROUND

Aug 03 11:10:54 ip-172-31-1-2.....compute.internal systemd[1]: Starting The Apache HTTP Server...
Aug 03 11:10:54 ip-172-31-1-2.....compute.internal systemd[1]: Started The Apache HTTP Server.

And now the output of the netstat command is:

[ec2-user@ip-172-31-1-2 ~]$ netstat -na | egrep -w "Local Address|LISTEN"
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp6       0      0 :::111                  :::*                    LISTEN     
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     

This time port 80 is in LISTEN state.

Confirming The Apache Port with Netstat

I’m pretty sure this is the port for the Apache Web Server, but how can I confirm that?

The netstat command provides an additional flag to show the PID and the name of the program a specific socket relates to. The -p flag, where p stands for program:

[ec2-user@ip-172-31-1-2 ~]$ netstat -nap | egrep -w "Local Address|LISTEN"
(No info could be read for "-p": geteuid()=1000 but you should be root.)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::111                  :::*                    LISTEN      -                   
tcp6       0      0 :::80                   :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   

Hmmm, I was expecting to see something next to LISTEN that would give me more details about the programs opening each port.

As you can see, the values of the column PID/Program name (ID and name of the process that owns the socket) are not visible.

Why I can’t see anything?

That’s because…

Only the process owner and the root user can retrieve detailed informations about processes running on a Linux system.

So, who is the owner of the Apache process? The ps command can help us find this out:

[ec2-user@ip-172-31-1-2 ~]$ ps -aef | grep httpd
root      5256     1  0 11:10 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5257  5256  0 11:10 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5258  5256  0 11:10 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5259  5256  0 11:10 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5260  5256  0 11:10 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5261  5256  0 11:10 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND

The parent process with PID 5256 has been started by root and the child processes by the apache user.

The reason why I can’t see any details about the PID of the processes using the netstat command, is that I’m running the command as the ec2-user.

To see more details in the output I have to provide the sudo command before the netstat command.

[ec2-user@ip-172-31-1-2 ~]$ sudo netstat -nap | egrep -w "Local Address|LISTEN"
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      2675/rpcbind        
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      3322/sshd           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      3160/master         
tcp6       0      0 :::111                  :::*                    LISTEN      2675/rpcbind        
tcp6       0      0 :::80                   :::*                    LISTEN      5256/httpd          
tcp6       0      0 :::22                   :::*                    LISTEN      3322/sshd           

This time the output is a lot better!

I can see that the httpd process with PID 5256 has opened port 80.

The -n flag in our netstat command shows addresses in a numerical form, this applies to both IP addresses and ports.

Have a look at output if we remove the -n flag:

[ec2-user@ip-172-31-1-2 ~]$ sudo netstat -ap | egrep -w "Local Address|LISTEN"
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:sunrpc          0.0.0.0:*               LISTEN      2675/rpcbind        
tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN      3322/sshd           
tcp        0      0 localhost:smtp          0.0.0.0:*               LISTEN      3160/master         
tcp6       0      0 [::]:sunrpc             [::]:*                  LISTEN      2675/rpcbind        
tcp6       0      0 [::]:http               [::]:*                  LISTEN      5256/httpd          
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN      3322/sshd                 

Can you see the difference?

The netstat command is one of the most used commands to verify network connections on a Linux system.

Check If a Port is Open with Lsof

The lsof command stands for “List of open files” and it’s used to list all the files opened by processes on Linux.

But, what have files to do with open ports?

As I mentioned before…

Everything in Linux is a file and sockets are special types of files.

Let’s see how to use the lsof command to see which port is being opened by our Apache Web Server…

…don’t forget the sudo command as I explained before. Also remember that the PID for Apache on my Linux system is 5256:

[ec2-user@ip-172-31-1-2 ~]$ sudo lsof -p 5256 | grep LISTEN
httpd   5256 root    4u  IPv6           11070402      0t0      TCP *:http (LISTEN)

The -p flag takes as argument the PID of the process for which we want to find out the port, and the TCP *:http part of the output shows that the port opened by that process is the http port.

What if I want to know the port number mapped to http?

You can add the -P flag that disables the conversion from port numbers to port names:

[ec2-user@ip-172-31-1-2 ~]$ sudo lsof -p 5256 -P | grep LISTEN
httpd   5256 root    4u  IPv6           11070402      0t0      TCP *:80 (LISTEN)

This shows that the Apache process has opened port 80 on my Linux host.

And what if I want to find the process opening a different port?

I can use the -i flag that retrieves the list of files that match the Internet address specified after the flag.

The generic syntax is:

lsof -i :port_number

Let’s see it in practice:

[ec2-user@ip-172-31-1-2 ~]$ sudo lsof -i :80
COMMAND  PID   USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
httpd   5256   root    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd   5257 apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd   5258 apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd   5259 apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd   5260 apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd   5261 apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)

In the output of the lsof command you can see useful details like process name, PID and user owner.

You can also pass multiple ports to the lsof command:

[ec2-user@ip-172-31-1-2 ~]$ sudo lsof -i :80 -i :22
COMMAND   PID     USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
sshd     3322     root    3u  IPv4    20024      0t0  TCP *:ssh (LISTEN)
sshd     3322     root    4u  IPv6    20026      0t0  TCP *:ssh (LISTEN)
httpd    5256     root    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd    5257   apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd    5258   apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd    5259   apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd    5260   apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
httpd    5261   apache    4u  IPv6 11070402      0t0  TCP *:http (LISTEN)
sshd    10877     root    3u  IPv4 11166512      0t0  TCP ip-172-31-1-2.mydomain:ssh->31.127.78.158:57775 (ESTABLISHED)
sshd    10895 ec2-user    3u  IPv4 11166512      0t0  TCP ip-172-31-28-249.mydomain:ssh->31.127.78.158:57775 (ESTABLISHED)

Makes sense?

Using The SS Command To Find Open Ports on Linux

What is the ss command?

The ss command is similar to the netstat command and it can be used to retrieve details about sockets on Linux.

You will notice similar flags to the netstat ones.

The following command shows listening sockets ( -l flag ), the name of the process (or processes) opening the socket ( -p flag ) and filters only based on TCP sockets ( -t flag).

[ec2-user@ip-172-31-1-2 ~]$ sudo ss -tlp
State  Recv-Q  Send-Q    Local Address:Port      Peer Address:Port                                                                                                                                                            
LISTEN 0       128             0.0.0.0:sunrpc         0.0.0.0:*      users:(("rpcbind",pid=2675,fd=8))                                                                                                                        
LISTEN 0       128             0.0.0.0:ssh            0.0.0.0:*      users:(("sshd",pid=3322,fd=3))                                                                                                                           
LISTEN 0       100           127.0.0.1:smtp           0.0.0.0:*      users:(("master",pid=3160,fd=13))                                                                                                                        
LISTEN 0       128                [::]:sunrpc            [::]:*      users:(("rpcbind",pid=2675,fd=11))                                                                                                                       
LISTEN 0       128                   *:http                 *:*      users:(("httpd",pid=5261,fd=4),("httpd",pid=5260,fd=4),("httpd",pid=5259,fd=4),("httpd",pid=5258,fd=4),("httpd",pid=5257,fd=4),("httpd",pid=5256,fd=4))  
LISTEN 0       128                [::]:ssh               [::]:*      users:(("sshd",pid=3322,fd=4))                               

The format of the output has also something similar to the netstat output, have a look at the column names…

To also see any UDP port in listening state, you can add the -u flag:

sudo ss -tulp

Now, I want to see just the process (or processes) that listen on port 80.

How do I do it with ss?

Here is the generic syntax of the ss command:

ss [options] [ FILTER ]

The second argument is a filter, let’s see an example of the filter for port 80:

[ec2-user@ip-172-31-1-2 ~]$ sudo ss -tlp 'sport = :80'
State                        Recv-Q                        Send-Q                                                 Local Address:Port                                                 Peer Address:Port                        
LISTEN                       0                             128                                                                *:http                                                            *:*                            users:(("httpd",pid=5261,fd=4),("httpd",pid=5260,fd=4),("httpd",pid=5259,fd=4),("httpd",pid=5258,fd=4),("httpd",pid=5257,fd=4),("httpd",pid=5256,fd=4))

You can see the word sport in the filter, it stands for source port.

As with every command, you can use the man command to see more details about ss.

And this is not the end, there’s another command!

Use the Linux Fuser Command to Find a TCP Port

It’s very cool how Linux allows to do the same thing in many different ways!

Another option you have is the fuser command.

The fuser command identities processes using files or sockets on a Linux system.

Its syntax is:

fuser <port_name>/<protocol>

So, to find the PID of the processes that are opening TCP port 80 you can use the following command:

[ec2-user@ip-172-31-1-2 ~]$ sudo fuser http/tcp
http/tcp:             5256  5257  5258  5259  5260  5261

You can also replace http with 80:

[ec2-user@ip-172-31-1-2 ~]$ sudo fuser 80/tcp
80/tcp:               5256  5257  5258  5259  5260  5261

You can then use the ps command to see more details about the PIDs returned by the fuser command.

But there’s also a quicker option…

Try to pass the -v flag to the fuser command:

[ec2-user@ip-172-31-1-2 ~]$ sudo fuser 80/tcp -v
                     USER        PID ACCESS COMMAND
80/tcp:              root       5256 F.... httpd
                     apache     5257 F.... httpd
                     apache     5258 F.... httpd
                     apache     5259 F.... httpd
                     apache     5260 F.... httpd
                     apache     5261 F.... httpd

And voilà!

You also get details about the processes opening port 80. Very useful!

Conclusion

We went through so many options to get the port opened by a Linux process and also to get the PIDs starting from a port number.

It’s critical to know all the ports that are open on your Linux system to keep your system secure.

Why?

Because services running on well-known ports can be exploited to get access to your Linux system in case the version of your service is subject to vulnerabilities.

So, keeping an eye to ports in LISTEN state on your machine is the first step to keep it secure.

Which command do you prefer to find the port opened by a process? Netstat, lsof, ss or fuser?

Let me know in the comments 🙂

Leave a Comment