Open source Β· htop, but for ports

Every port on your machine,

A live terminal UI for the TCP and UDP sockets on your machine. Each row shows the process, its systemd unit or Windows service and its Docker container, and one key lets you inspect or stop it.

$ curl -fsSL https://raw.githubusercontent.com/padovanl/portop/main/install.sh | sh
🐧 Linux🍎 macOSπŸͺŸ Windows

Green is listening, blue is established, amber is a port that just opened.

Features

Everything ss leaves out

The context that ss, netstat and lsof don't give you, in one view that refreshes on its own.

Live port table

Listening and established sockets, colored by state, with per-process CPU and port names from /etc/services. Columns drop out as the terminal narrows.

Who can reach it

Each listening port is colored by exposure: every interface, one address or loopback only. The host firewall's verdict says whether traffic actually gets in.

Process, service and container

The systemd unit or Windows service, and the Docker, Podman or Kubernetes container behind each port, read from cgroups with no daemon of its own.

Masters and workers

A socket shared by nginx, gunicorn or php-fpm shows as one row owned by the master, nginx +3, with its workers listed.

Inspect and stop

enter shows the command line, user, memory and start time. k confirms, re-checks the process identity, then sends SIGTERM or SIGKILL.

Per-connection traffic

Bytes per second for every established TCP connection, on Linux from the kernel's socket diagnostics and on macOS from nettop.

Wait for and free ports

--wait 5432 blocks until a service listens; --free 3000 stops whatever holds a port and waits until it is released.

Baseline drift detection

--save-baseline, then --diff from cron: exit code 3 when a port appears, disappears or becomes reachable from the network.

Compose port audit

--compose DIR checks a Compose project's published ports, with ${VARIABLES} resolved, against what actually listens.

New-port alerts

Ports that start listening are highlighted live, with an optional desktop notification on Linux, macOS and Windows.

JSON and Prometheus

--json for scripts and jq; the web dashboard serves /metrics for Prometheus, with basic auth when sign-in is on.

Themes and key bindings

The settings screen (,) previews 13 themes live and lets you rebind any of 20 actions. Changes are saved automatically.

In action

A real session

Filtering to a port, opening the process details and confirming a kill, recorded as it happened.

portop
portop filtering to a port, showing the process details, the kill confirmation and the help overlay
Beyond the terminal

Web dashboard and Cockpit

The same live view of ports and processes, for when a terminal is not at hand.

Signing in to the portop web dashboard, filtering to nginx and opening its details, with exposure and firewall badges

Web dashboard --web

portop --web serves a dashboard on 127.0.0.1:8088 with search, process details and confirmed SIGTERM/SIGKILL. With --web-auth it adds a sign-in page, can listen beyond loopback and serves HTTPS via --web-tls-cert and --web-tls-key.

Opening Tools, Ports (portop) in Cockpit and inspecting the redis-server process

Cockpit add-on Tools β†’ Ports

On Linux, copy cockpit/portop to ~/.local/share/cockpit/portop and open Tools β†’ Ports (portop). It runs through Cockpit's bridge with your login and permissions, so there is no extra service to expose. Setup steps.

Install

Get portop

Packages for Debian and Ubuntu, Snap, Homebrew, winget and the Microsoft Store, plus archives for every supported architecture.

Linux and macOS. Detects the architecture, verifies the release checksum and installs to /usr/local/bin, or ~/.local/bin if that is not writable.

curl -fsSL https://raw.githubusercontent.com/padovanl/portop/main/install.sh | sh

To override detection, download the script and set PORTOP_ARCH to amd64, arm64, armv7 or armv6 (macOS accepts amd64 and arm64). On ARM64 kernels, getconf LONG_BIT is used to spot a 32-bit userland.

curl -fsSL https://raw.githubusercontent.com/padovanl/portop/main/install.sh -o install.sh
PORTOP_ARCH=armv7 sh install.sh

Debian, Ubuntu and derivatives on amd64, arm64 and armhf. The signed repository at apt.lucapadovan.dev is rebuilt on every release, so updates arrive with apt upgrade.

sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://apt.lucapadovan.dev/lucapadovan.gpg | sudo tee /etc/apt/keyrings/lucapadovan.gpg >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/lucapadovan.gpg] https://apt.lucapadovan.dev stable main" \
  | sudo tee /etc/apt/sources.list.d/lucapadovan.list
sudo apt update && sudo apt install portop

Any Linux distribution with snapd, on amd64 and arm64. Snaps update automatically. Snap Store page.

sudo snap install portop

macOS (Apple Silicon and Intel) and Linux, from homebrew-core.

brew install portop

Windows 10 1809 or later and Windows 11, on x64 and ARM64. Each option puts portop on your PATH.

winget install padovanl.portop

Or install it from the Microsoft Store, which keeps it up to date.

Install from the release zip

Download portop_<version>_windows_amd64.zip (or windows_arm64) from the latest release and put portop.exe in a folder on your PATH. In PowerShell:

# <version> is the release number without the leading "v"
$zip = "portop_<version>_windows_amd64.zip"   # ARM64: windows_arm64
Invoke-WebRequest "https://github.com/padovanl/portop/releases/latest/download/$zip" -OutFile $zip
$dir = "$env:LOCALAPPDATA\Programs\portop"
Expand-Archive $zip -DestinationPath $dir -Force
# add it to your user PATH, then open a new terminal
[Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";$dir", "User")

Socket owners are visible without elevation. Open an Administrator terminal to see details of elevated or other users' processes.

Apple Silicon and Intel. Homebrew keeps portop up to date with brew upgrade; the install script also works.

brew install portop
Install from the release archive

Use darwin_arm64 for Apple Silicon or darwin_amd64 for Intel.

archive="portop_<version>_darwin_arm64.tar.gz"   # Intel: darwin_amd64
curl -fLO "https://github.com/padovanl/portop/releases/latest/download/$archive"
tar -xzf "$archive"
sudo mkdir -p /usr/local/bin
sudo install -m 755 portop /usr/local/bin/portop
If macOS blocks the first launch

The release binaries are not notarized, so a browser download may trigger Gatekeeper. After checking that the binary comes from this repository's release:

  1. Run portop. If macOS shows β€œportop” Not Opened, click Done.
  2. Open System Settings β†’ Privacy & Security, find the message about portop and click Open Anyway (or Allow Anyway).
  3. Run portop again, confirm Open Anyway and authenticate.

See Apple's instructions for your macOS version.

portop uses the system's lsof and ps. Run sudo portop to include other users' processes. Systemd, Docker Desktop VM process metadata and thread counts are not available on macOS; containers are recognised by the ports Docker Desktop publishes.

Single packages from the latest release. They do not update on their own; on Debian and Ubuntu, prefer the APT repository. Replace linux_amd64 with your target from the table below.

# Debian, Ubuntu
curl -fLO https://github.com/padovanl/portop/releases/latest/download/portop_<version>_linux_amd64.deb
sudo dpkg -i portop_<version>_linux_amd64.deb

# Fedora, RHEL (openSUSE: sudo zypper install ...)
sudo dnf install ./portop_<version>_linux_amd64.rpm

Static binaries with no runtime dependencies. Replace linux_amd64 with your target.

curl -fLO https://github.com/padovanl/portop/releases/latest/download/portop_<version>_linux_amd64.tar.gz
tar -xzf portop_<version>_linux_amd64.tar.gz
sudo install -m 755 portop /usr/local/bin/portop

Builds from source with a recent Go toolchain. Package documentation.

go install github.com/padovanl/portop/cmd/portop@latest

Supported platforms

SystemArchitectureTargetAvailable asRequirements
🐧 Linuxx86-64linux_amd64APT, Snap, Homebrew, .deb, .rpm, .tar.gzamd64 baseline (v1).
🐧 LinuxARM64linux_arm64APT, Snap, Homebrew, .deb, .rpm, .tar.gz64-bit OS, ARMv8.0 baseline.
🐧 LinuxARMv7linux_armv7APT (armhf), .deb, .rpm, .tar.gzHardware floating point (VFPv3).
🐧 LinuxARMv6linux_armv6APT (armhf), .deb, .rpm, .tar.gzHardware floating point (VFP); Raspberry Pi 1 and Zero.
🍎 macOSInteldarwin_amd64Homebrew, .tar.gz64-bit Intel Mac.
🍎 macOSApple Silicondarwin_arm64Homebrew, .tar.gzNative ARM64, no Rosetta.
πŸͺŸ Windowsx64windows_amd64winget, Microsoft Store, .zipWindows 10 1809 or later.
πŸͺŸ WindowsARM64windows_arm64winget, Microsoft Store, .zipWindows 11 on ARM.
Compatibility notes
  • Pick the target for your OS, not just the CPU. A 64-bit ARM board running a 32-bit OS needs armv7, or armv6 for older CPUs.
  • Not supported: ARMv5, soft-float armel, big-endian ARM, 32-bit x86 and 32-bit Windows.
  • ARM32 packages: the ARMv6 and ARMv7 DEBs both carry armhf metadata; install only one. The APT repository serves the ARMv6 build, which also runs on ARMv7. RPM labels are x86_64, aarch64, armv6hl and armv7hl.
  • Old systems: the binaries need no Go or C runtime, but a very old kernel may be below Go's minimum requirements.
  • Linux: /proc/net must be readable. Inside a container portop sees that container's network namespace. Root may be needed to identify other users' processes.
  • Compose audit: with access to Docker, portop confirms the Compose service behind published ports and docker-proxy; without it, the port is still reported but the expected service may be unknown.
  • Windows: sockets and owners come from the IP Helper API. The SYSTEMD column becomes SERVICE, Docker Desktop containers are matched by published port through the docker CLI, and both kill choices end the process.
  • Testing: see the validation report for what has been run on real hardware and what only under emulation.
Keyboard

Key bindings

Also in the app with ?. Every binding can be changed from the settings screen or in config.yml.

↑ ↓Move the cursor
PgUp PgDnMove one page
g GJump to top or bottom
enterProcess details
kStop the process, after confirming
oOpen the port in the browser
f /Filter by port, process or PID
vIPv4, IPv6 or both
eShow or hide established
sChange the sort column
cCopy the selected row
nClear the new-port highlight
rRefresh now
,Settings: themes and keys
?Help
qQuit
πŸ–±οΈ MouseSelect, scroll and sort by heading