Self-hosted service
mostafa-wahied/portracker avatar
mostafa-wahied/portracker

portracker review: self-hosted port monitoring with Docker and TrueNAS collectors

An open source, self-hosted, real-time port monitoring and discovery tool.

2,466 stars105 forksJavaScriptMIT

At a glance

What is it?
portracker maps which services hold which ports on your hosts and containers, using host PID access, the Docker socket and an optional TrueNAS API key. It is a small single-process tool, but the permissions it asks for are the whole story.
Who is it for?
Adopt portracker if you run several Docker hosts or a TrueNAS box and keep losing track of which service owns which port, and you accept running a container with pid: host, SYS_PTRACE and SYS_ADMIN. Do not adopt it if you cannot grant those permissions, or if you only need container log streaming, where Dozzle is the smaller tool.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 19 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What portracker actually solves, and for whom

Every host accumulates listeners. A reverse proxy on 443, a database on 5432, a leftover test container on 8080. The README frames the problem plainly: it helps eliminate manual tracking in spreadsheets and prevents deployment failures caused by port conflicts. That is the whole value proposition, and it is a narrow one. portracker is not an uptime monitor, not a log viewer, not a metrics pipeline. It answers one question: what is listening where, right now.

The target user is someone running a handful of self-hosted machines, often a home lab or a small office rack. The topics on the repository list open-source, self-hosted and truenas, which matches the feature set: platform-specific collectors for Docker and TrueNAS, plus peer-to-peer monitoring so several portracker instances report into one dashboard. If you manage one laptop, a port scan from the shell is enough. The tool earns its place when the inventory is spread across a physical host, the VMs on it, and the containers inside those VMs.

How discovery works: host PID namespace, Docker socket, TrueNAS API

portracker runs as a single Node process with an embedded SQLite database, so there is no PostgreSQL or Redis to operate. Discovery happens through three separate channels, and each has its own permission requirement.

The first channel is the host process table. The compose file sets pid: "host" so the container shares the host PID namespace, then adds SYS_PTRACE so the process can read other PIDs' /proc entries on Linux hosts, and SYS_ADMIN so it can enter namespaces on Docker Desktop for macOS and Windows. apparmor:unconfined is listed as required for the system ports service. This is why the deployment looks heavier than a typical web app: the collector is reading kernel-level process data, not an API.

The second channel is the Docker socket, mounted read-only at /var/run/docker.sock. From it the tool discovers containers and, per the feature list, distinguishes internal container ports from published host ports. The .env.example exposes cache TTLs for that path, including DOCKER_CACHE_CONTAINERS_TTL_MS=4000 and DOCKER_CACHE_INSPECT_TTL_MS=5000, which tells you the dashboard is not re-querying the daemon on every page load. A global CACHE_TIMEOUT_MS defaults to 60000.

The third channel is optional. Supplying TRUENAS_API_KEY enables TrueNAS discovery, including running VMs and enhanced system information such as OS version and uptime. The README notes a sharp edge here: VMs found this way appear in read-only mode, and full monitoring means deploying a portracker instance on each VM and adding it as a separate server. The .env.example also warns that systems with many apps or VMs may need TRUENAS_TIMEOUT_MS raised from its 90000 default, which suggests the TrueNAS path is the slowest and most failure-prone of the three.

Installing portracker with Docker Compose and running the first scan

The README gives Docker Compose as the primary path. Create a docker-compose.yml with the service definition below. The pid setting and the two capabilities are marked required for port detection, and the /data volume is marked required for persistence of the SQLite database.

yaml
services:
  portracker:
    image: mostafawahied/portracker:latest
    container_name: portracker
    restart: unless-stopped
    pid: "host"
    cap_add:
      - SYS_PTRACE
      - SYS_ADMIN
    security_opt:
      - apparmor:unconfined
    volumes:
      - ./portracker-data:/data
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - "4999:4999"

Bring it up with the command from the README:

sh
docker-compose up -d

After that, the dashboard is served on port 4999 on the host, which is the value of PORT in .env.example and the default in the configuration table. You should see the discovered services listed with their ports. The README describes live filtering and three layout views: list, grid and table.

If you would rather not hand the container the Docker socket, the README documents a proxy setup. The proxy runs with POST=0, restricting it to read-only Docker API operations, and portracker reaches it through DOCKER_HOST.

yaml
  docker-proxy:
    image: tecnativa/docker-socket-proxy:latest
    environment:
      - CONTAINERS=1
      - IMAGES=1
      - INFO=1
      - NETWORKS=1
      - POST=0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - "2375:2375"

In that variant the portracker service gets environment: - DOCKER_HOST=tcp://docker-proxy:2375 and depends_on the proxy. Note that the proxy still mounts the socket; you are narrowing the API surface, not removing the mount. Authentication is off unless you set ENABLE_AUTH=true, and SESSION_SECRET is only needed when auth is enabled. The README says it prevents logout on container restart.

The permission model is the real adoption cost

The compose file is honest about what it wants, and that honesty is the main thing to weigh. SYS_PTRACE plus apparmor:unconfined plus the host PID namespace means this container can inspect processes it does not own. The README's own security section exists precisely because that combination is uncomfortable, and the docker-socket-proxy path only addresses the Docker half of it. There is no documented equivalent for the /proc half. If your platform blocks unconfined AppArmor profiles, or your policy forbids SYS_ADMIN, portracker will not do its main job, and the README does not describe a degraded mode that works without them.

The Docker Desktop case is worth calling out separately. SYS_ADMIN is described as required for macOS, which means the Mac deployment is the one carrying the broadest capability. Anyone running portracker on a laptop should read that line twice before copying the compose file.

A second limitation is scope. Discovery is host-local plus peers. There is no documented agentless remote scanning of arbitrary subnets; to see another machine you add another portracker instance and register it as a peer. That is a reasonable design, but it means the tool does not replace a network scanner, and the README does not claim it does.

portracker compared with Dozzle and a plain port scan

Dozzle appears in the related searches, and the comparison is clean. Dozzle is a container log viewer: it attaches to the Docker socket and streams logs to a browser. portracker does not stream logs; it enumerates listeners and their owning services. If your actual problem is "why did this container crash," Dozzle is the right tool and portracker is the wrong one. If your problem is "which of these forty containers is holding 8080," portracker answers it and Dozzle does not.

The other alternative is the shell. ss -tulpn or lsof -i gives you the same host-level truth on one machine, with no container, no capabilities and no daemon. It falls short exactly where portracker's collectors add value: correlating a listening port back to a named Docker container, separating an internal container port from its published host port, and keeping a persistent inventory across several machines. For a single host, the shell command is faster and safer. For a fleet with containers, the manual approach is what the README is arguing against.

Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-07-17. Releases are dense: v1.3.8, v1.3.9 and v1.3.10 all landed on 2026-05-05, and package.json carries version 1.3.13, so the project ships often. Frequent small releases are good for fixes and less good for operators who pin versions, because the changelog is the only place the differences are recorded. The Dockerfile copies CHANGELOG.md into the image, which the comment ties to a What's New feature, so the running container can show you what changed.

The licence is MIT, which is permissive and imposes no copyleft obligation on how you deploy or modify it. That is a statement about the licence text, not legal advice; if you redistribute it inside a product, read the LICENSE file rather than this paragraph.

Upgrade cost is low in the ordinary case: pull mostafawahied/portracker:latest and recreate the container, and the SQLite file under ./portracker-data survives because it lives on a bind mount. The risk sits in the environment surface. The .env.example lists roughly a dozen tuning variables across Docker cache TTLs, internal port limits and TrueNAS timeouts, and the README's configuration table is truncated in the repository listing. Before upgrading, diff your environment against .env.example rather than assuming defaults stayed put.

Editorial conclusion

Adopt portracker if you run several Docker hosts or a TrueNAS box and keep losing track of which service owns which port, and you accept running a container with pid: host, SYS_PTRACE and SYS_ADMIN. Do not adopt it if you cannot grant those permissions, or if you only need container log streaming, where Dozzle is the smaller tool. Before deploying, verify that your host allows apparmor:unconfined and decide whether you will mount /var/run/docker.sock directly or put tecnativa/docker-socket-proxy:latest in front of it with POST=0.

Frequently asked questions

How does portracker compare with dotpeek?

The repository material does not describe dotpeek, so no comparison can be drawn from it. portracker's own documentation covers host, Docker and TrueNAS port discovery, and names no dotpeek integration.

What is the portracker dashboard?

It is the web interface served on port 4999 by default, showing discovered services and their ports. The README describes live filtering and three layout views: list, grid and table, with light and dark modes.

How do I install portracker with Docker?

The README gives a docker-compose.yml with pid: "host", the SYS_PTRACE and SYS_ADMIN capabilities, apparmor:unconfined, a ./portracker-data:/data volume and a read-only mount of /var/run/docker.sock. Run docker-compose up -d and open port 4999.

What port does portracker use?

The default is 4999, both in the compose port mapping and as the PORT variable in .env.example. The configuration table lists PORT as the port the web application runs on, with 4999 as its default.

Official sources

  1. Issues
  2. License: MIT
  3. mostafa-wahied/portracker on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mostafa-wahied-portracker.svg)](https://hysenlabs.com/projects/mostafa-wahied-portracker)