<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luca Padovan</title>
    <description>The latest articles on DEV Community by Luca Padovan (@senseipado).</description>
    <link>https://dev.to/senseipado</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4133536%2F237d6baf-c526-4b64-877d-3ca9b3936bb9.png</url>
      <title>DEV Community: Luca Padovan</title>
      <link>https://dev.to/senseipado</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/senseipado"/>
    <language>en</language>
    <item>
      <title>I got tired of checking which process was using my ports, so I built Portop</title>
      <dc:creator>Luca Padovan</dc:creator>
      <pubDate>Sun, 20 Sep 2026 00:53:03 +0000</pubDate>
      <link>https://dev.to/senseipado/i-got-tired-of-checking-which-process-was-using-my-ports-so-i-built-portop-3n9</link>
      <guid>https://dev.to/senseipado/i-got-tired-of-checking-which-process-was-using-my-ports-so-i-built-portop-3n9</guid>
      <description>&lt;p&gt;If you work with Linux long enough, you've probably seen this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bind: address already in use
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then the usual routine starts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ss &lt;span class="nt"&gt;-tlnp&lt;/span&gt;
lsof &lt;span class="nt"&gt;-i&lt;/span&gt; :8080
ps ...
systemctl status ...
docker ps ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are great tools and I use them all the time.&lt;/p&gt;

&lt;p&gt;But on systems with lots of services running, I found myself doing this over and over again just to answer a very simple question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is actually using this port?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Portop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/padovanl/portop" rel="noopener noreferrer"&gt;https://github.com/padovanl/portop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Portop is an open source TUI written in Go that gives you a live view of your network ports and tries to connect each socket with the process, service or container behind it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4ur57814w9ff9tvjs1q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4ur57814w9ff9tvjs1q.gif" alt="Portop demo" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It started as a tool for myself
&lt;/h2&gt;

&lt;p&gt;I work with Linux systems where having a lot of services and ports in use is normal.&lt;/p&gt;

&lt;p&gt;Knowing that port 8080 is listening is useful, but usually that's only the beginning.&lt;/p&gt;

&lt;p&gt;I want to know which process owns it.&lt;/p&gt;

&lt;p&gt;I want to know the PID and user.&lt;/p&gt;

&lt;p&gt;I want to know whether it belongs to a systemd service.&lt;/p&gt;

&lt;p&gt;I want to know whether Docker is involved.&lt;/p&gt;

&lt;p&gt;And sometimes I just want to kill the process without opening another terminal and running three more commands.&lt;/p&gt;

&lt;p&gt;That's basically where Portop came from.&lt;/p&gt;

&lt;p&gt;The original version was pretty small.&lt;/p&gt;

&lt;p&gt;Then I published it, people started trying it, and the feedback gave me quite a few ideas for things I hadn't originally planned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;

&lt;p&gt;The main interface is intentionally simple.&lt;/p&gt;

&lt;p&gt;You get a live table of network activity with information about the socket and the process behind it.&lt;/p&gt;

&lt;p&gt;Portop can show both listening ports and established connections.&lt;/p&gt;

&lt;p&gt;From the same interface you can search and filter entries, inspect a process, open a local web service in your browser, copy information or terminate a process.&lt;/p&gt;

&lt;p&gt;Pressing Enter on a process opens more details such as its command line, executable, working directory, user, memory usage, thread count and start time.&lt;/p&gt;

&lt;p&gt;There is mouse support too, although I still use it mostly from the keyboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mapping ports back to processes
&lt;/h2&gt;

&lt;p&gt;On Linux, Portop doesn't just parse the output of &lt;code&gt;ss&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It reads the kernel socket tables from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/proc/net/tcp
/proc/net/tcp6
/proc/net/udp
/proc/net/udp6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It then maps socket inodes back to processes by walking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/proc/&amp;lt;pid&amp;gt;/fd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there it can associate the process with additional information.&lt;/p&gt;

&lt;p&gt;Systemd and Docker associations are primarily derived from cgroups.&lt;/p&gt;

&lt;p&gt;For Docker, container names can also be resolved through read only calls to the Docker Engine Unix socket when available.&lt;/p&gt;

&lt;p&gt;There is no privileged background daemon running just to make Portop work.&lt;/p&gt;

&lt;p&gt;Of course Linux permissions still apply. If your user cannot inspect another process, Portop cannot magically bypass that. Running it with &lt;code&gt;sudo&lt;/code&gt; gives it the additional visibility when needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  One feature I didn't originally plan: Docker Compose auditing
&lt;/h2&gt;

&lt;p&gt;This one came directly from feedback after I shared the project.&lt;/p&gt;

&lt;p&gt;Someone asked whether Portop could look at a Docker Compose project and tell you whether the ports configured there were actually being used.&lt;/p&gt;

&lt;p&gt;I liked the idea, so I added it.&lt;/p&gt;

&lt;p&gt;You can now run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portop &lt;span class="nt"&gt;--compose&lt;/span&gt; ./my-stack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Portop reads the published ports from the Compose configuration and compares them with what is actually listening on the machine.&lt;/p&gt;

&lt;p&gt;It can identify ports that are behaving as expected, conflicts where another process owns the port, unused ports and dynamic mappings.&lt;/p&gt;

&lt;p&gt;When Docker information is available, it can also check whether the listener actually belongs to the expected Compose service.&lt;/p&gt;

&lt;p&gt;And because I didn't want this to be useful only interactively, you can combine it with JSON output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portop &lt;span class="nt"&gt;--compose&lt;/span&gt; ./my-stack &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Baselines and unexpected ports
&lt;/h2&gt;

&lt;p&gt;Another thing I wanted was a simple way to answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What changed?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can save the current listening ports as a baseline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portop &lt;span class="nt"&gt;--save-baseline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then compare the machine against it later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portop &lt;span class="nt"&gt;--diff&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reports ports that appeared or disappeared.&lt;/p&gt;

&lt;p&gt;There is also:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portop &lt;span class="nt"&gt;--watch-new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which watches for newly opened listening ports and can send a desktop notification when something new appears.&lt;/p&gt;

&lt;p&gt;Because the diff command can return a nonzero exit code when changes are found, it can also be used from scripts, cron or systemd timers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sometimes I don't want a TUI
&lt;/h2&gt;

&lt;p&gt;Portop can output the current state as JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portop &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So it can also be combined with &lt;code&gt;jq&lt;/code&gt; or used as part of another script.&lt;/p&gt;

&lt;p&gt;For example, the TUI is useful when I'm investigating something manually, while JSON is much more convenient if I want another tool to consume the same information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linux, ARM and macOS
&lt;/h2&gt;

&lt;p&gt;Portop started as a Linux project.&lt;/p&gt;

&lt;p&gt;It currently has Linux builds for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;amd64
arm64
armv7
armv6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are &lt;code&gt;.deb&lt;/code&gt; and &lt;code&gt;.rpm&lt;/code&gt; packages as well.&lt;/p&gt;

&lt;p&gt;More recently I added macOS support for both Intel and Apple Silicon.&lt;/p&gt;

&lt;p&gt;The implementation there is necessarily different because macOS doesn't have Linux's &lt;code&gt;/proc&lt;/code&gt; filesystem. Portop uses the native &lt;code&gt;lsof&lt;/code&gt; and &lt;code&gt;ps&lt;/code&gt; tools instead.&lt;/p&gt;

&lt;p&gt;Some Linux specific information, such as systemd metadata, obviously isn't available there, but the main Portop workflow still works.&lt;/p&gt;

&lt;h2&gt;
  
  
  And yes, there are themes
&lt;/h2&gt;

&lt;p&gt;I like TUIs.&lt;/p&gt;

&lt;p&gt;So at some point one theme became two, then three, and now Portop has 12 built in themes.&lt;/p&gt;

&lt;p&gt;You can switch between them directly from the settings screen without restarting the application.&lt;/p&gt;

&lt;p&gt;The same screen lets you remap the keybindings, with changes saved automatically.&lt;/p&gt;

&lt;p&gt;This part wasn't exactly necessary to solve the original problem.&lt;/p&gt;

&lt;p&gt;But I regret nothing :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing it
&lt;/h2&gt;

&lt;p&gt;The quick installer is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/padovanl/portop/main/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with Go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/padovanl/portop/cmd/portop@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also start with a filter immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portop 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;portop redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Releases are available here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/padovanl/portop/releases" rel="noopener noreferrer"&gt;https://github.com/padovanl/portop/releases&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I want Portop to be
&lt;/h2&gt;

&lt;p&gt;I'm not trying to replace &lt;code&gt;ss&lt;/code&gt;, &lt;code&gt;lsof&lt;/code&gt;, Wireshark, Docker tooling or the other networking tools that already exist.&lt;/p&gt;

&lt;p&gt;They solve much bigger problems than Portop does.&lt;/p&gt;

&lt;p&gt;The idea is much simpler:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;See a port. Understand what's behind it. Act on it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Portop started as something I built for myself in my spare time.&lt;/p&gt;

&lt;p&gt;Publishing it has been fun because several of the features it has today came from people trying it and saying "this would be useful if..."&lt;/p&gt;

&lt;p&gt;So I'm curious where it goes next.&lt;/p&gt;

&lt;p&gt;If you work with Linux, containers, servers, embedded devices or just regularly find yourself wondering what stole port 8080, I'd love to hear what you think.&lt;/p&gt;

&lt;p&gt;The project is MIT licensed and contributions are welcome.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/padovanl/portop" rel="noopener noreferrer"&gt;https://github.com/padovanl/portop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try it and find a bug, or have an idea for something that would be useful when investigating ports and connections, feel free to open an issue.&lt;/p&gt;

</description>
      <category>tui</category>
      <category>linux</category>
      <category>networking</category>
      <category>ubuntu</category>
    </item>
  </channel>
</rss>
