Skip to content

Commit a869712

Browse files
Feature/fix unknown system ports (#46)
* fix: fixed unknown system ports * fix: fix inconsistent system ports indicator * chore: update version to 1.1.0 and document backend changes in changelog
1 parent 8c1dffd commit a869712

File tree

10 files changed

+302
-66
lines changed

10 files changed

+302
-66
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to Portracker will be documented in this file.
44

5+
## [1.1.0] - 2025-08-23
6+
7+
### Frontend & Backend
8+
- **System Port Name Fix**: Fixed the issue where system ports were incorrectly displayed as "unknown".
9+
- **Consistent Status Indicators**: Improved status indicators for system ports to ensure consistency.
10+
511
## [1.0.8] - 2025-08-20
612

713
### Frontend

README.md

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,21 @@ services:
5151
image: mostafawahied/portracker:latest
5252
container_name: portracker
5353
restart: unless-stopped
54-
pid: "host" # Required for comprehensive port detection
54+
pid: "host" # Required for port detection
55+
# Required permissions for system ports service namespace access
56+
cap_add:
57+
- SYS_PTRACE # Linux hosts: read other PIDs' /proc entries
58+
- SYS_ADMIN # Docker Desktop: allow namespace access for host ports (required for MacOS)
59+
security_opt:
60+
- apparmor:unconfined # Required for system ports
5561
volumes:
5662
# Required for data persistence
5763
- ./portracker-data:/data
5864
# Required for discovering services running in Docker
5965
- /var/run/docker.sock:/var/run/docker.sock:ro
6066
ports:
6167
- "4999:4999"
62-
environment:
63-
- DATABASE_PATH=/data/portracker.db
64-
- PORT=4999
68+
# environment:
6569
# Optional: For enhanced TrueNAS features
6670
# - TRUENAS_API_KEY=your-api-key-here
6771
```
@@ -79,11 +83,12 @@ docker run -d \
7983
--name portracker \
8084
--restart unless-stopped \
8185
--pid host \
86+
--cap-add SYS_PTRACE \
87+
--cap-add SYS_ADMIN \
88+
--security-opt apparmor=unconfined \
8289
-p 4999:4999 \
8390
-v ./portracker-data:/data \
8491
-v /var/run/docker.sock:/var/run/docker.sock:ro \
85-
-e DATABASE_PATH=/data/portracker.db \
86-
-e PORT=4999 \
8792
mostafawahied/portracker:latest
8893
```
8994

@@ -115,13 +120,16 @@ services:
115120
container_name: portracker
116121
restart: unless-stopped
117122
pid: "host"
123+
cap_add:
124+
- SYS_PTRACE
125+
- SYS_ADMIN
126+
security_opt:
127+
- apparmor:unconfined
118128
volumes:
119129
- ./portracker-data:/data
120130
ports:
121131
- "4999:4999"
122132
environment:
123-
- DATABASE_PATH=/data/portracker.db
124-
- PORT=4999
125133
- DOCKER_HOST=tcp://docker-proxy:2375
126134
depends_on:
127135
- docker-proxy
@@ -148,10 +156,11 @@ docker run -d \
148156
--name portracker \
149157
--restart unless-stopped \
150158
--pid host \
159+
--cap-add SYS_PTRACE \
160+
--cap-add SYS_ADMIN \
161+
--security-opt apparmor=unconfined \
151162
-p 4999:4999 \
152163
-v ./portracker-data:/data \
153-
-e DATABASE_PATH=/data/portracker.db \
154-
-e PORT=4999 \
155164
-e DOCKER_HOST=tcp://localhost:2375 \
156165
mostafawahied/portracker:latest
157166
```
@@ -192,4 +201,4 @@ Contributions are welcome! Please feel free to open an issue to report a bug or
192201

193202
## License
194203

195-
This project is licensed under the MIT License - see the [LICENSE](https://github.com/Mostafa-Wahied/portracker/blob/main/LICENSE)
204+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/Mostafa-Wahied/portracker/blob/main/LICENSE)

backend/collectors/docker_collector.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,10 @@ class DockerCollector extends BaseCollector {
605605
return ports;
606606
} catch (nsenterErr) {
607607
this.logInfo(`nsenter method failed: ${nsenterErr.message}, trying alternative methods`);
608+
const msg = String(nsenterErr?.message || '').toLowerCase();
609+
if (msg.includes('permission denied') || msg.includes('operation not permitted') || msg.includes('exit code 1')) {
610+
this.logWarn('Hint: nsenter requires cap_add: [SYS_ADMIN] to access the host network namespace on Docker Desktop (macOS/Windows).');
611+
}
608612

609613
try {
610614
const { stdout: netNsCheck } = await execAsync("readlink /proc/self/ns/net 2>/dev/null");

backend/collectors/truenas_collector.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,10 @@ class TrueNASCollector extends BaseCollector {
647647
}
648648
} catch (nsenterErr) {
649649
this.logWarn(`nsenter method failed: ${nsenterErr.message}`);
650+
const msg = String(nsenterErr?.message || '').toLowerCase();
651+
if (msg.includes('permission denied') || msg.includes('operation not permitted') || msg.includes('exit code 1')) {
652+
this.logWarn('Hint: nsenter requires cap_add: [SYS_ADMIN] to access the host network namespace on Docker Desktop (macOS/Windows).');
653+
}
650654
}
651655

652656
this.logError('All port collection methods failed');

backend/index.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,7 +1965,7 @@ app.post("/api/notes/batch", (req, res) => {
19651965
});
19661966

19671967
app.get("/api/ping", async (req, res) => {
1968-
const { host_ip, host_port, target_server_url, owner, internal, container_id } = req.query;
1968+
const { host_ip, host_port, target_server_url, owner, internal, container_id, source } = req.query;
19691969
const serverId = req.query.server_id;
19701970
const currentDebug = req.query.debug === "true";
19711971

@@ -1997,6 +1997,7 @@ app.get("/api/ping", async (req, res) => {
19971997
if (host_ip) params.set('host_ip', host_ip);
19981998
if (host_port) params.set('host_port', host_port);
19991999
if (owner) params.set('owner', owner);
2000+
if (source) params.set('source', source);
20002001
if (currentDebug) params.set('debug', 'true');
20012002
const url = `${base}/api/ping?${params.toString()}`;
20022003
const resp = await fetch(url, { headers: { 'accept': 'application/json' } });
@@ -2054,14 +2055,14 @@ app.get("/api/ping", async (req, res) => {
20542055
});
20552056
}
20562057

2057-
if (serviceInfo.type === 'system') {
2058+
if (serviceInfo.type === 'system' || source === 'system') {
20582059
return res.json({
20592060
reachable: true,
20602061
status: 'system',
20612062
color: 'gray',
2062-
title: serviceInfo.description,
2063-
serviceType: serviceInfo.type,
2064-
serviceName: serviceInfo.name
2063+
title: source === 'system' ? 'System service' : serviceInfo.description,
2064+
serviceType: 'system',
2065+
serviceName: source === 'system' ? 'System Service' : serviceInfo.name
20652066
});
20662067
}
20672068

0 commit comments

Comments
 (0)