{"id":50251536,"url":"https://github.com/ubhits/netryx","last_synced_at":"2026-05-27T02:01:26.149Z","repository":{"id":360394788,"uuid":"1249926882","full_name":"UbhiTS/netryx","owner":"UbhiTS","description":"Self-hosted, web-based network scanner \u0026 discovery dashboard for your LAN — device discovery, port scanning, an interactive map, and clickable web links. Pure-Python (zero dependencies); runs locally, as a Windows .exe, or in Docker on a NAS.","archived":false,"fork":false,"pushed_at":"2026-05-27T01:09:53.000Z","size":1362,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T01:16:31.292Z","etag":null,"topics":["device-discovery","docker","homelab","ip-scanner","mdns","nas","network-discovery","network-mapping","network-scanner","networking","port-scanner","python","self-hosted","snmp","wake-on-lan","web-ui"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/UbhiTS.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-26T06:41:47.000Z","updated_at":"2026-05-27T01:09:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/UbhiTS/netryx","commit_stats":null,"previous_names":["ubhits/netscanner"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/UbhiTS/netryx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UbhiTS%2Fnetryx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UbhiTS%2Fnetryx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UbhiTS%2Fnetryx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UbhiTS%2Fnetryx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/UbhiTS","download_url":"https://codeload.github.com/UbhiTS/netryx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UbhiTS%2Fnetryx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33546836,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["device-discovery","docker","homelab","ip-scanner","mdns","nas","network-discovery","network-mapping","network-scanner","networking","port-scanner","python","self-hosted","snmp","wake-on-lan","web-ui"],"created_at":"2026-05-27T02:01:21.228Z","updated_at":"2026-05-27T02:01:26.123Z","avatar_url":"https://github.com/UbhiTS.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Netryx — Signal Cartography\n\nA feature-rich, **web-based** network scanner and discovery tool. It finds every\ndevice on your network, identifies what each one is, maps their open ports and\nservices, and gives you a **clickable URL** for anything running a web interface.\nThe UI is a polished dark \"constellation atlas\" dashboard with card, table, and\ninteractive topology-map views.\n\nThe engine is a single Python file with **zero external dependencies** (standard\nlibrary only). It runs a small local web server and serves the dashboard in your\nbrowser. Nothing is sent to the cloud — all scanning and data stay on your machine.\n\nIt's also **scriptable and agent-ready**: a one-shot JSON CLI, a Model Context\nProtocol (MCP) server for AI assistants, a documented HTTP/OpenAPI surface, and\nproactive rogue-device alerts. See [Automation \u0026 AI agents](#automation--ai-agents).\n\n---\n\n## Files\n\n| File | Purpose |\n|------|---------|\n| `netryx.py` | The scanning engine + local web server + HTTP/MCP API |\n| `ui.html` | The dashboard (served by the engine — **keep it next to `netryx.py`**) |\n| `netryx_mcp.py` | Stdio MCP server for AI agents (keep next to `netryx.py`) |\n| `openapi.yaml` | OpenAPI 3.0 description of the HTTP API (also served at `/openapi.json`) |\n| `run.bat` | Double-click launcher for Windows |\n| `build.bat` | Builds a standalone `Netryx.exe` (bundles `ui.html`) |\n| `Dockerfile`, `docker-compose.yml`, `.dockerignore` | Run it as a container on a NAS/server |\n| `DESIGN_PHILOSOPHY.md`, `signal_cartography.png/.pdf` | The visual design language behind the UI |\n\n\u003e `netryx.py` and `ui.html` must live in the same folder. Keep\n\u003e `netryx_mcp.py` alongside them too if you want the MCP server. Everything\n\u003e else is optional.\n\n---\n\n## Why it's \"a local web app\" and not pure in-browser JavaScript\n\nA scanner running *entirely* inside a browser tab physically cannot probe your\nLAN — browsers sandbox raw network access for security (no ICMP ping, no ARP, no\narbitrary TCP scans). Netryx uses the standard, capable design: a tiny local\nengine does the real scanning and serves the web UI you open in your browser.\n\n---\n\n## Option A — run locally (easiest, no install)\n\n1. Install **Python 3.8+** (https://www.python.org/downloads/ — tick *\"Add Python to PATH\"*).\n2. Double-click **`run.bat`** (or run `python netryx.py`).\n3. Your browser opens at `http://127.0.0.1:8765`; your subnet is auto-detected — press **Scan network**.\n\n```\npython netryx.py                # launch + open browser\npython netryx.py --port 9000    # choose a port\npython netryx.py --no-browser   # don't auto-open the browser\npython netryx.py --host 0.0.0.0 # listen on all interfaces (use with care)\npython netryx.py --scan 192.168.1.0/24 --json   # one-shot scan, no server\n```\n\n## Option B — standalone Windows .exe (no Python on the target PC)\n\nRun **`build.bat`** once on a Windows machine with Python. It uses PyInstaller to\nproduce `dist\\Netryx.exe` — a single file (the UI **and** the MCP server are\nbundled inside) you can copy to any Windows PC and double-click. (A Windows\n`.exe` must be built on Windows.)\n\n## Option C — Docker on your NAS / server\n\nThe app is container-ready. From this folder:\n\n```\ndocker compose up -d --build\n```\n\nThen open **`http://\u003cyour-NAS-IP\u003e:8765`** from any browser on your network.\n\n**Host networking is required.** A bridged container sits on its own virtual\nnetwork and cannot see your real LAN — no device discovery, no ARP, no mDNS/SNMP.\nThe provided `docker-compose.yml` sets `network_mode: host` and adds the `NET_RAW`\ncapability so ICMP ping works.\n\n**You do not need `--privileged`.** Netryx only uses ordinary sockets and the\n`ping` command — it never reconfigures the network or sends raw packets. `NET_RAW`\nis the only capability it benefits from (for ICMP), and even that is optional:\nwithout it, discovery still works via TCP connect probing — you just lose ICMP\nping and the TTL-based OS guess. (`NET_ADMIN` is not needed.)\n\n- On **Synology** (Container Manager) or **QNAP** (Container Station), import this\n  project and make sure the container uses **host** network mode. If your NAS UI\n  won't allow host mode, the app will still load but device discovery will be\n  limited to the container's own network.\n- Data (scan history, device names/notes, the downloaded vendor DB, baseline and\n  events) persists in `./netryx-data` on the host via the mounted volume.\n- Change the port with the `NETRYX_PORT` env var if 8765 is taken.\n\nPlain `docker` equivalent:\n\n```\ndocker build -t netryx .\ndocker run -d --name netryx --network host \\\n  --cap-add NET_RAW \\\n  -e NETRYX_PORT=8765 -v \"$PWD/netryx-data:/data\" \\\n  --restart unless-stopped netryx\n```\n\n---\n\n## Features\n\n**Discovery \u0026 identification**\n- Auto-detects your subnet (editable — scan any CIDR, e.g. `10.0.0.0/24`)\n- Concurrent ping sweep **plus a TCP fallback**, so it finds devices that block ping\n- MAC address resolution from the ARP table\n- Vendor lookup from the MAC, with a **one-click \"Download full\" button** that\n  fetches the complete IEEE OUI database for exhaustive vendor names\n- Reverse-DNS hostnames\n- **mDNS / Bonjour** discovery — surfaces Chromecasts, AirPlay, printers, Apple\n  devices, Sonos, HomeKit, etc., with friendly names and service types\n- **SNMP** (v2c) queries managed switches, printers and access points for their\n  system name and description\n- **NetBIOS** and **SSDP/UPnP** probing for Windows names and smart-device models\n- OS guess (TTL) and device-type guess (ports + vendor + mDNS + SNMP)\n- Round-trip latency\n\n**Ports, services \u0026 exposure**\n- Parallel TCP connect scanning — **Quick** (~90 ports), **Extended** (1–1024),\n  **Full** (1–65535) — with service names and banner grabbing\n- **Web URL detection** — HTTP/HTTPS ports become clickable links that open the\n  device's web UI (80 → `http://ip`, 443 → `https://ip`, plus 8080/8443/8123/…)\n- **Exposure scoring** — each device gets a risk tier (none → critical) based on\n  risky open ports (Telnet, RDP, SMB, VNC, exposed databases, unauth Docker, …)\n\n**Views \u0026 workflow**\n- **Table** (default), **Cards**, and an interactive **Topology map** with\n  multiple layouts and Obsidian-style floating physics\n- Search, filter (web-only / open-ports / new / named), and sort\n- **Live monitoring**: auto re-scan on a timer with **new-device detection** and\n  **desktop notifications** (browser Notification API)\n- **Scan history + change detection** — every scan is saved; reload and compare\n- **Wake-on-LAN**, **custom names/notes** per device, **CSV/JSON export**\n\n---\n\n## Automation \u0026 AI agents\n\nEverything below is pure standard library — no extra installs.\n\n### One-shot CLI scan (no server)\n\nRun a single scan and print the result — perfect for cron jobs and scripts:\n\n```\npython netryx.py --scan 192.168.1.0/24                          # table output\npython netryx.py --scan 192.168.1.0/24 --json                   # machine-readable JSON\npython netryx.py --scan 192.168.1.0/24 --ports --profile quick --json\npython netryx.py --scan \"10.0.0.0/24, 10.0.5.10\" --no-snmp --no-mdns\n```\n\nEvery device carries a `risk` assessment (`none`/`low`/`medium`/`high`/`critical`)\nderived from its open ports. Exit code is non-zero if the targets are invalid.\n\n### MCP server for AI agents (stdio)\n\n`netryx_mcp.py` is a [Model Context Protocol](https://modelcontextprotocol.io)\nserver, so assistants like Claude can scan and reason about your network. Point\nyour MCP client at it:\n\n```\ncommand: python\nargs:    [\"/full/path/to/netryx_mcp.py\"]\n```\n\nExample `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"netryx\": {\n      \"command\": \"python\",\n      \"args\": [\"C:\\\\path\\\\to\\\\netryx_mcp.py\"]\n    }\n  }\n}\n```\n\nTools exposed: `network_info`, `scan_network`, `list_devices`, `get_device`,\n`find`, `whats_new`, `exposure_report`, `scan_ports`, `wake_device`,\n`name_device`, `scan_history`, `get_baseline`, `set_baseline`, `check_rogues`,\n`recent_events`. The MCP server shares Netryx's data directory, so it sees\nthe same scan history your web UI produces.\n\n### Remote MCP over HTTP\n\nThe web server also speaks MCP at `POST /mcp` (JSON-RPC 2.0), so a remote agent\ncan reach a Netryx running on your NAS. Authorize it with an **API token**\n(create one in the dashboard under **Settings → API tokens**, or use the legacy\n`NETRYX_TOKEN` env var):\n\n```\ncurl -X POST http://nas:8765/mcp \\\n  -H \"Authorization: Bearer nsk_your_token\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\"}'\n```\n\nSee [Security \u0026 access control](#security--access-control) for the full picture.\nA `?token=` query parameter is also accepted (avoid it where requests get logged).\n\n### OpenAPI\n\nThe full HTTP API is described at `GET /openapi.json` and `GET /openapi.yaml`\n(also committed as `openapi.yaml`). Load it into Swagger UI, Postman, or an\nagent's tool layer.\n\n### Proactive monitoring: baseline + rogue alerts\n\nApprove your current network as a known-good **baseline**, then every later scan\nis diffed against it. The first time an **unapproved device** or an **unapproved\nopen port** appears, Netryx logs an event and (optionally) pushes it out.\n\n- Manage the baseline: `POST /api/baseline {\"action\":\"set\"|\"approve\"|\"clear\"}`,\n  or the `set_baseline` MCP tool.\n- Read recent events: `GET /api/events`, or the `recent_events` MCP tool.\n- Deliver alerts to a **webhook** (HTTP POST) and/or **MQTT** by setting env vars\n  (below). Each alert fires once (de-duplicated) until you re-approve the baseline.\n\nPair this with **Live monitoring** in the UI (or a cron'd `--scan`) for continuous\nrogue-device detection with push notifications.\n\n### Environment variables\n\n| Variable | Purpose |\n|----------|---------|\n| `NETRYX_HOST` | Bind address (default `127.0.0.1`; Docker uses `0.0.0.0`) |\n| `NETRYX_PORT` | Port (default `8765`) |\n| `NETRYX_NO_BROWSER` | Don't auto-open a browser |\n| `NETRYX_DATA` | Data dir (history, names, vendor DB, baseline, events, tokens) |\n| `NETRYX_USER` | Admin username (default `admin`); seeds first launch |\n| `NETRYX_PASS` | Seeds/overrides the admin password (default login is `admin`) |\n| `NETRYX_TRUST_LOCALHOST` | `0` (default) prompts everywhere; `1` skips auth for `127.0.0.1` |\n| `NETRYX_OPEN` | `1` disables auth entirely (trusted segments only) |\n| `NETRYX_SESSION_DAYS` | Login session lifetime in days (default `30`) |\n| `NETRYX_TOKEN` | Legacy static bearer token (managed tokens in the UI are preferred) |\n| `NETRYX_WEBHOOK` | URL to POST events to |\n| `NETRYX_MQTT` | MQTT broker `host` or `host:port` |\n| `NETRYX_MQTT_TOPIC` | MQTT topic (default `netryx/events`) |\n| `NETRYX_MQTT_USER` / `NETRYX_MQTT_PASS` | MQTT credentials (optional) |\n\n---\n\n## Security \u0026 access control\n\nNetryx is **secure by default**. On first launch it creates an admin login\nof **`admin` / `admin`** and requires it for the **whole** app — the dashboard,\nevery `/api/*` endpoint, and `/mcp`. Change it immediately under **Settings** in\nthe dashboard.\n\n**Sign in:**\n\n- **Humans** — sign in on a styled **login page** (a session cookie keeps you\n  signed in; **Sign out** lives in the dashboard header). Change the\n  username/password under **Settings → Admin login**; the new credentials are\n  hashed (PBKDF2) and persisted to `netryx-data/auth.json`, so they survive\n  restarts — and changing the password no longer signs you out. You can also seed\n  the initial password with `NETRYX_PASS` (and `NETRYX_USER`), which\n  additionally works as a recovery/override login.\n- **Agents \u0026 scripts** — create **API tokens** under **Settings → API tokens**.\n  Each token is named, shows when it was created and last used, and is\n  **long-lived by default** (set an expiry in days if you want one). Token values\n  stay **viewable**, so you can copy one back into an agent's config later. Use\n  them with `Authorization: Bearer \u003ctoken\u003e` on the API and `/mcp`. Tokens live in\n  `netryx-data/tokens.json` (gitignored) — treat it as a secret.\n\n**Prompting \u0026 localhost.** By default you're prompted everywhere, including on\nthe machine running Netryx (`NETRYX_TRUST_LOCALHOST=0`). For a\nfrictionless local desktop, set `NETRYX_TRUST_LOCALHOST=1` to skip the prompt\nfor `127.0.0.1` while still requiring it from other devices.\n\n**Run fully open** on a genuinely trusted segment with `NETRYX_OPEN=1`, which\ndisables auth entirely (a banner reminds you it's off).\n\n### HTTPS with an nginx reverse proxy\n\nNetryx serves plain HTTP, so passwords and tokens travel in cleartext. On a\nNAS or any untrusted segment, put it behind a reverse proxy that terminates TLS:\n\n```nginx\nserver {\n    listen 443 ssl;\n    server_name netryx.example.lan;\n\n    ssl_certificate     /etc/nginx/certs/netryx.crt;\n    ssl_certificate_key /etc/nginx/certs/netryx.key;\n\n    location / {\n        proxy_pass http://127.0.0.1:8765;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        # Pass the caller's credentials (Bearer token / Basic) through:\n        proxy_set_header Authorization $http_authorization;\n    }\n}\n```\n\n**Gotcha:** nginx connects to Netryx from `127.0.0.1`. Keep\n`NETRYX_TRUST_LOCALHOST` at its default (`0`) so proxied requests are still\nauthenticated — setting it to `1` would make every proxied request look local and\nskip auth. Two working patterns:\n\n1. **App-enforced auth** (keeps in-app token management): set `NETRYX_PASS`\n   and/or create API tokens, set `NETRYX_TRUST_LOCALHOST=0`, and let nginx\n   pass `Authorization` through (as above). nginx only does TLS.\n2. **Proxy-enforced auth**: let nginx do its own `auth_basic`, and leave\n   Netryx trusting localhost. Simpler, but you lose per-token management.\n\nEither way, don't expose Netryx directly to the internet.\n\n---\n\n## Notes \u0026 tips\n\n- **Run as Administrator / root** for the most complete ARP and discovery results.\n- **Allow it through your firewall** on private networks the first time.\n- The local launcher binds to `127.0.0.1` only. The Docker/`--host 0.0.0.0` modes\n  expose it to your whole LAN — appropriate for a NAS, but don't expose it to the\n  internet. If you do expose `/mcp`, set `NETRYX_TOKEN`.\n- **Full** port scans (65,535 ports/host) are thorough but slow — best used on a\n  single host via the per-device **Scan ports** button.\n- The downloaded vendor database is saved in the data folder and loaded\n  automatically on the next scan.\n\n## Ethical use\n\nOnly scan networks you own or are authorized to test.\n\n---\n\n## Continuous integration\n\nThis repo ships a GitHub Actions workflow (`.github/workflows/build.yml`) that runs on every push and pull request:\n\n- **Docker image** → built and pushed to the GitHub Container Registry (GHCR) as `ghcr.io/\u003cowner\u003e/netryx:latest` (and a `:\u003ccommit-sha\u003e` tag). Pull and run it on your NAS with:\n\n  ```\n  docker run -d --name netryx --network host \\\n    --cap-add NET_RAW \\\n    -v \"$PWD/netryx-data:/data\" --restart unless-stopped \\\n    ghcr.io/\u003cowner\u003e/netryx:latest\n  ```\n\n- **Standalone Windows .exe** → built with PyInstaller on a Windows runner and uploaded as a build **artifact** on every run. Pushing a version tag (e.g. `git tag v1.0.0 \u0026\u0026 git push --tags`) also publishes the `.exe` on a GitHub **Release**.\n\nNo secrets are required — the workflow authenticates to GHCR with the built-in `GITHUB_TOKEN`. After the first successful run, make the GHCR package public from your repo's *Packages* page if you want others to pull it.\n\n## Privacy\n\nYour scan results are local only. `.gitignore` excludes `netryx_data/` (IPs, MACs, hostnames, device names/notes, scan history, baseline, events, API tokens and the admin login) and common secret files so they're never committed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubhits%2Fnetryx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fubhits%2Fnetryx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubhits%2Fnetryx/lists"}