How to Find Process IDs on ports with `lsof`
tl;dr
To kill a process running on a specific port use lsof
as so:
lsof -i :<process port number>
I want to tell you how to find the server process ID that is running a on a specific port. This is useful in a micro-service based development when you want to kill a server, not all of them.
I will apply this to a practical example of finding a server’s process ID and stopping the server.
You will understand a new Unix tool: lsof
and understand how to
incorporate it into your work-flow.
This article will take you about four minutes to read.
Introduction
Ever have to stop a server process? It froze and you need to reset it, at no fault of your own?! :-)
Easy, use ps -aef
to list all the process names and associated
IDs. Put the output into grep
to find the server name, and stop it
using the command: kill -9 <pid value from ps -aef>
Here’s how to kill the jekyll
web server:
vagrant@ubuntu-xenial:~/rgr$ ps -aef | grep jekyll
vagrant 29511 5837 29 09:16 pts/2 00:00:54 ruby /home/vagrant/.rvm/gems/ruby-2.4.6/bin/jekyll s
Enter Micro-services
What if you’re running a micro-service based application or multiple versions of the same application in parallel and needed to kill only one of them?
ps -aef
would list process by their application name. If the process
had the same options, this would be the result:
Example
vagrant 29511 5837 17 09:16 pts/2 00:01:15 ruby /home/vagrant/.rvm/gems/ruby-2.4.6/bin/jekyll s
vagrant 29568 29539 12 09:21 pts/3 00:00:13 ruby /home/vagrant/.rvm/gems/ruby-2.4.6/bin/jekyll s
Now, which process to stop? Stop them all and restart every other one? That might not be painful if the number of services is less than a handful.
As n
Gets Large, so does Pain
It does get painful when there are two handfuls or more of services or applications.
With micro-services, there’s a good chance the only thing you can differentiate between the services are the port number each service is running on.
Is there a tool that can list which process is running on each port?
Yes, there is!
Enter: lsof
The tool is: lsof
- short for: list open files. The specific option
needed is the -i
option, which lists open files that match an
Internet address.
Seems like overkill, right?
These are the reasons for this:
- Everything in UNIX is a file, running a micro-service requires running files.
- Micro-services are listening to ports, connecting files to ports.
Using lsof
, we are essentially asking: what files are open on which
port?
Running lsof
by itself:
vagrant@ubuntu-xenial:~/rgr$ lsof
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root cwd unknown /proc/1/cwd (readlink: Permission denied)
systemd 1 root rtd unknown /proc/1/root (readlink: Permission denied)
systemd 1 root txt unknown /proc/1/exe (readlink: Permission denied)
systemd 1 root NOFD /proc/1/fd (opendir: Permission denied)
kthreadd 2 root cwd unknown /proc/2/cwd (readlink: Permission denied)
kthreadd 2 root rtd unknown /proc/2/root (readlink: Permission denied)
...
lsof 29509 vagrant mem REG 8,1 1668976 29183 /usr/lib/locale/locale-archive
lsof 29509 vagrant 4r FIFO 0,10 0t0 149674 pipe
lsof 29509 vagrant 7w FIFO 0,10 0t0 149675 pipe
ruby 29511 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
ruby-time 29511 29512 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
thread_po 29511 29522 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
thread_po 29511 29523 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
serve.rb: 29511 29525 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
To find out what process is on port 4000 (the jekyll server):
vagrant@ubuntu-xenial:~/rgr$ lsof | grep 4000
ruby 29511 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
ruby-time 29511 29512 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
thread_po 29511 29522 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
thread_po 29511 29523 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
serve.rb: 29511 29525 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
And to find out the PID of the jekyll server running on port 4001:
vagrant@ubuntu-xenial:~/rgr$ lsof | grep 4001
ruby 29568 vagrant 14u IPv4 151277 0t0 TCP *:4001 (LISTEN)
ruby-time 29568 29569 vagrant 14u IPv4 151277 0t0 TCP *:4001 (LISTEN)
thread_po 29568 29579 vagrant 14u IPv4 151277 0t0 TCP *:4001 (LISTEN)
thread_po 29568 29580 vagrant 14u IPv4 151277 0t0 TCP *:4001 (LISTEN)
serve.rb: 29568 29582 vagrant 14u IPv4 151277 0t0 TCP *:4001 (LISTEN)
To stop the server, just pick the one I want to stop based on the port.
Can I do better?
lsof
is the right tool, using it with grep
does work. Is there a
better way to use it?
Yes there is.
Looking at the lsof
man page more, there’s an -i
switch,
specifically for IP addresses and ports.
-i [i] selects the listing of files any of whose Internet address matches the address specified in i. If no address is specified, this option selects the listing of all Internet and x.25 (HP-UX) network files.
Using lsof -i
instead:
vagrant@ubuntu-xenial:~/rgr$ lsof -i :4000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ruby 29511 vagrant 14u IPv4 148658 0t0 TCP *:4000 (LISTEN)
vagrant@ubuntu-xenial:~/rgr$ lsof -i :4001
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ruby 29568 vagrant 14u IPv4 151277 0t0 TCP *:4001 (LISTEN)
Produces the same result as lsof
with grep
. lsof -i
produces a
result faster as lsof
by processes for every port, which can be
over a 1000.
vagrant@ubuntu-xenial:~/rgr$ lsof | wc -l
1503
Conclusion
On Unix systems, Stopping servers can be as easy as using ps -aef
and grep
to figure out which process ID to kill.
When there are more than one server that runs with the same name,
lsof -i
will help you out more than ps -aef
, if you know the port
number.