Physical network documentation for home labs and small offices. Map your devices, ports, cable runs, patch panels, and racks — then keep a visual, searchable record of what's plugged into what, backed up with real photos of your gear.
CableMap is a self-hosted, single-binary-ish web app (Node + SQLite) with a dark, keyboard-friendly UI. It's built for the person who has traced one cable too many and wants to write it down once.
| Dashboard | Racks |
|---|---|
![]() |
![]() |
| At-a-glance counts, quick search, and recent activity. | Front-of-rack "U" elevation with per-rack photos. |
| VLAN Manager |
|---|
![]() |
| Manage VLANs and see the connections assigned to each. |
Home labs grow organically. You add a switch, a NAS, an AP, a UPS — and six months later you can't remember whether port 14 on the core switch goes to the office wall jack or the garage. CableMap is a focused record-keeping tool for exactly that:
- Write down the trace — port A → patch panel → port B, with cable type, color, length, and VLAN.
- Prove it with a photo — attach pictures of the actual cable run, the device, or the whole rack.
- See it two ways — a fast searchable table for daily lookups, and a visual canvas + rack elevation for planning and documentation.
- Devices, ports & connections — full CRUD with a port-conflict-aware connection model (a port can only hold one active connection at a time).
- Bulk patching — patch a whole range of ports between two devices at once (switch 1–24 → panel 1–24), with a row-by-row preview and per-row conflict validation.
- Patch panel support — front/back port pairs are modeled as linked ports, so a cable trace follows through the panel automatically.
- Port trace algorithm —
GET /api/ports/:id/tracewalks the physical path hop-by-hop (including patch-panel pass-through and cycle detection). - Rack elevation view — a real "U" diagram driven by each device's rack position, with real front/rear device images (via the NetBox import), drag-to-reposition, and PNG export. Passive occupants (UPS, shelves, blank panels) take up space too.
- Connection-aware rack view — click a device in the elevation to see its cable runs drawn as arcs along the rack rail, color-coded by cable type, with runs that leave the rack tagged. The rack view answers "follow that cable" in physical space.
- NetBox devicetype-library import — search 5,000+ community device definitions (CC0) and import any model as an editable template with accurate ports, power outlets, and front/rear elevation images. Devicetype YAML flows both ways: upload a local .yaml, or export any template back to the library format. Half-U gear and pass-through patch panels import correctly.
- Rack layout import — bootstrap racks from a NetBox devices JSON export or a Rackula layout file: racks + placed devices (half-U supported), with template matching for types and images.
- LLDP/CDP link discovery — poll a managed switch over SNMP to learn what's plugged into what, and confirm the proposed links into real connections (optional
net-snmpdependency; managed gear only). - IPAM-lite — subnets (VLAN-linked) with live usage bars, per-address assignments, next-free suggestions, and one-click import of device management IPs.
- Cable schedule — a registry of every physical run (cable ID, from/to device+port+location, type, connector, color, length, VLAN) with CSV export; plus scannable device QR codes for field lookup.
- Asset & lifecycle — serial/asset tag/supplier/cost and purchase/warranty/EOL dates per device, with an Assets dashboard rolling up out-of-warranty, EOL-soon, and estimated fleet value.
- Multi-user & API tokens — admin/editor/viewer accounts (viewers read-only) and hashed API tokens for scripted access (
Authorization: Bearer/X-API-Key), on top of the env-configured bootstrap admin. - Canvas view — a React Flow topology map with device nodes, color-coded cable edges, draggable layout, VLAN/location filtering, live-status overlay, themes, uplink-aware auto-layout, and PNG/SVG export.
- Reachability monitoring — opt in per device (ping / HTTP / HTTPS / TCP) and CableMap shows live online/offline status in the list, on device detail, on the canvas, and on the dashboard. A documentation aid — not a metrics/alerting system. Configurable sweep interval; set
MONITOR_INTERVAL_SECONDS=0to disable. - Network discovery — sweep a subnet (
/24–/30) to find live hosts (IP, MAC + vendor, hostname) and approve them into your inventory from a pending queue. Pings only; no port scanning. - Read-only share links — revocable, no-login "live view" links for a wall display or a colleague (structure + status + connections; no photos, no editing).
- Interop — JSON topology export (and a tokenized public feed) for other tools, plus an optional MCP server so an AI assistant can query the physical record.
- Power mapping & load budgeting — model UPS/PDU outlets and which device each one feeds (with receptacle types and estimated draw), give a power source its rated capacity, and watch a live load bar with overload warnings. Device detail shows an outlet map for power sources and a "powered by" panel for everything else.
- Health check — audits your documentation for inconsistencies: double-booked ports, rack-U overlaps, overloaded power sources, unmapped power, devices with no ports, and stale planned connections.
- Change history — an append-only timeline of every device, connection, and power change, with a global History page and a per-device view.
- Photos & documents — attach images (cable traces, device shots, rack photos) with auto-generated thumbnails, plus PDF spec sheets and Visio stencils. There's also a free-form photo gallery.
- Full backup & restore — one-click ZIP of all data + uploaded files, and a guarded restore.
- 344 built-in device templates across 25+ vendors — pick a model and the device form auto-fills make, type, rack height, ports, and (for UPS/PDU) outlets.
- Custom templates — create your own gear (manufacturer, model, OS/firmware, form factor, ports, photo, spec sheet, product URLs). Built-ins are read-only; your custom ones are fully editable down to individual ports.
- VLAN manager, full-text search, CSV import/export, and PDF port-map export.
- Single-user session auth, dark-mode-only UI, mobile-friendly list/search views.
344 templates spanning networking, security, NAS, and power gear, including:
- Ubiquiti — the UniFi lineup (gateways, switches, access points, aggregation)
- Firewalls / NGFW — Fortinet (FortiGate/FortiSwitch/FortiAP, D/E/F gens), Palo Alto Networks (PA-200 → PA-5400), Cisco (ASA, Firepower, Secure Firewall), Cisco Meraki MX, Netgate/pfSense, OPNsense, Sophos XGS, SonicWall TZ, Protectli
- Switches / APs — Cisco Catalyst (1200/1300, 2960-X, 3850, 9200/9300) & Meraki MS/MR, TP-Link Omada, MikroTik, Netgear, Aruba Instant On
- NAS — Synology, QNAP, TrueNAS/iXsystems, Asustor, UGREEN, Drobo, plus custom DIY builds
- UPS / power — APC, CyberPower, Eaton, Tripp Lite, Vertiv (rackmount + tower/desktop), plus rack PDUs — all with outlet definitions
- Generic — patch panels, rackmount servers, UPS, shelves/drawers, blank rackspace, DIY
⚠️ Template port layouts are best-effort reference data to save you typing — not a guaranteed spec sheet. Every value is editable after you add a device, and you can create your own custom templates. Corrections via PR are welcome.
Need something not in the built-in library? Use Import from NetBox on the Templates page to pull any of 5,000+ community device definitions (ports, outlets, and rack images included).
| Layer | Technology |
|---|---|
| Frontend | React + Tailwind CSS, bundled with Vite |
| Canvas | React Flow (reactflow) |
| Charts | Chart.js |
| Backend | Node.js + Express |
| Database | SQLite via better-sqlite3 |
| Auth | express-session + bcrypt (single user) |
| Images | sharp (server-side thumbnails) |
| Export | CSV + PDF (pdfkit) |
Prerequisites: Node.js 22 LTS and npm. (It still runs on Node 20+, but Node 20 reached end-of-life in April 2026 — use 22.)
git clone https://github.com/breed007/CableMap.git
cd CableMap
# Install root, client, and server dependencies
npm run install:all
# Configure environment (change the secrets!)
cp .env.example .env
# edit .env → set SESSION_SECRET and ADMIN_PASSWORD
# Initialize the database (creates tables, seeds locations, VLANs, templates)
npm run db:init
# Run client (Vite) + server (Express) together
npm run dev- Frontend dev server: http://localhost:5173
- API: http://localhost:3000
Log in with the ADMIN_USERNAME / ADMIN_PASSWORD from your .env.
npm run build # builds the React app into server/public/
npm start # serves the app + API from Express on PORT (default 3000)cp .env.example .env # edit secrets
docker compose up -dThe app runs on port 3000 and stores everything (database, sessions, uploaded photos) in a named volume mounted at /data. See docs/deployment-docker.md for update, backup, and reset instructions.
Running Proxmox? Create a ready-to-go container in one line — run this on the Proxmox host as root:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/breed007/CableMap/main/scripts/proxmox-lxc-install.sh)"It spins up a Debian 13 LXC (defaults: 2 vCPU · 2048 MiB · 8 GiB, unprivileged), installs CableMap as a systemd service, and prints the URL plus a generated admin password. Pick Advanced at the prompt to change resources, hostname, or set a static IP. Update later by re-running pct exec <CTID> -- bash /root/lxc-setup.sh. Full details in scripts/README.md.
All configuration is via environment variables (see .env.example):
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
HTTP port |
SESSION_SECRET |
changeme |
Session signing secret — change this |
ADMIN_USERNAME |
admin |
Login username |
ADMIN_PASSWORD |
changeme |
Login password (plaintext, or a bcrypt hash) — change this |
DATA_DIR |
./data |
Directory for the DB, sessions, and uploads |
DB_PATH |
./data/cablemap.db |
SQLite database path |
MONITOR_INTERVAL_SECONDS |
60 |
Reachability sweep interval; 0 disables the background checker |
COOKIE_SECURE |
false |
Set true when behind an HTTPS reverse proxy (marks the session cookie Secure) |
HISTORY_RETENTION |
5000 |
Max history rows kept; older rows are pruned hourly (0 disables) |
To use a hashed admin password instead of plaintext:
node -e "require('bcrypt').hash('your-password', 10).then(h => console.log(h))"
# paste the $2b$... output as ADMIN_PASSWORD- Linux (PM2 + Nginx/Apache):
docs/deployment-linux.md - Docker:
docs/deployment-docker.md
CableMap/
├── client/ React + Vite frontend
│ └── src/
│ ├── pages/ Dashboard, Devices, Connections, Canvas, Racks, Templates, …
│ ├── components/ Sidebar, Modal, PhotoUploader, DocumentUploader, icons
│ └── utils/ API client, color/label maps
├── server/ Express backend
│ ├── db/ schema, seeds (templates), init/migrations
│ ├── routes/ devices, ports, connections, vlans, attachments, templates, …
│ └── utils/ tracePath (port-trace algorithm)
├── docs/ Deployment guides
└── data/ SQLite DB + uploads (gitignored)
All routes are under /api/ and require an authenticated session.
GET|POST /api/locations GET /api/locations/:id (rack elevation)
GET|POST /api/devices PUT /api/devices/:id/position
POST /api/devices/:id/ports/bulk-create
GET|PUT|DELETE /api/ports/:id GET /api/ports/:id/trace
GET|POST /api/connections POST /api/connections/bulk (bulk patch)
GET|POST /api/vlans
GET|POST|PUT|DELETE /api/device-templates (custom templates editable; built-ins read-only)
GET|POST|PUT|DELETE /api/attachments (images + PDF/Visio docs)
GET|POST|PUT|DELETE /api/power/outlets POST /api/power/outlets/bulk-create
GET|POST|PUT|DELETE /api/power/connections (outlet → device power mapping)
GET /api/history GET /api/history/device/:id
GET /api/health (consistency / completeness checks)
POST /api/devices/:id/check POST /api/monitor/check-all (reachability)
POST /api/discovery/scan GET /api/discovery POST /api/discovery/:id/import
GET /api/netbox/search?q= POST /api/netbox/import (devicetype-library)
POST /api/netbox/import-yaml GET /api/device-templates/:id/netbox.yaml
POST /api/import/rack (NetBox / Rackula rack layouts)
GET /api/elevations/:file POST /api/elevations/upload
GET|POST|PUT|DELETE /api/ipam/subnets /api/ipam/addresses (IPAM)
POST /api/lldp/poll GET /api/lldp POST /api/lldp/:id/import (link discovery)
GET /api/cable-schedule GET /api/cable-schedule/export.csv
GET /api/qr/device/:id.svg GET /api/assets/lifecycle
GET|POST|PUT|DELETE /api/users /api/tokens (admin only)
GET|POST|DELETE /api/share (read-only share links)
GET /api/public/:token/snapshot GET /api/public/:token/topology.json (no auth)
GET /api/export/topology.json (interop)
GET /api/backup/export POST /api/backup/import
GET /api/search?q= GET /api/summary
POST /api/import/connections GET /api/export/connections
GET /api/export/device/:id/pdf
CableMap ships an experimental MCP server that exposes the physical record as read-only tools (list_devices, get_device, list_connections, search, topology) so an AI assistant can answer questions like "what's plugged into the core switch?".
cd server
npm install @modelcontextprotocol/sdk # optional dependency
DB_PATH=../data/cablemap.db npm run mcp # stdio MCP serverIt reads the SQLite database directly (via Node's built-in driver) and doesn't require the web server to be running.
The server has a test suite built on Node's built-in test runner and node:sqlite — no external dependencies to install. Requires Node 22+ for testing (which is also the recommended runtime; the app still runs on Node 20+).
cd server && npm testCI (GitHub Actions) runs the server tests and a client build on every push/PR.
Contributions are welcome — especially device template corrections and additions. To add or fix templates, edit server/db/seeds.js (the seedTemplates array) and open a PR. Each template lists its make, model, SKU, device type, rack height, and a default_ports array.
- Fork and create a branch.
- Make your change; run
npm run buildto confirm the client compiles. - For schema changes, keep
server/db/init.jsmigrations additive and idempotent. - Open a pull request.
MIT © 2026 breed007
CableMap was designed for documenting your own network. It supports multiple accounts (admin/editor/viewer) and API tokens, but is still intended to run on a trusted LAN or behind a reverse proxy with HTTPS — not exposed directly to the public internet. Set
COOKIE_SECURE=truebehind HTTPS, and changeADMIN_PASSWORD/SESSION_SECRETfrom their defaults.


