Josh Creek 7c7118bbf8 Merge pull request #25 from jcreek/14-read-only-mode
feat(#14): Add zero-setup Docker data initialization
2026-07-24 22:51:39 +01:00
2026-02-22 16:51:22 +00:00
2026-07-24 22:43:44 +01:00
2026-07-24 22:43:44 +01:00
2026-02-22 16:51:22 +00:00
2025-04-13 22:24:43 +01:00
2025-01-19 14:38:27 +00:00
2026-02-22 16:57:18 +00:00
2026-07-24 22:43:44 +01:00
2026-07-13 22:01:13 +01:00
2026-07-13 22:01:13 +01:00
2026-07-13 22:01:13 +01:00
2026-07-13 22:01:13 +01:00
2026-07-13 22:01:13 +01:00
2026-07-13 22:01:13 +01:00

Open Network Diagram

Docker Pulls Release Workflow Docker CI Workflow Latest Release Netlify

A declarative, self-hosted containerised tool for visualising and managing home lab & network architecture diagrams.

Open Network Diagram helps you document your infrastructure in a visual UI while keeping a real JSON source of truth you can back up, reuse, and optionally version after reviewing it for sensitive information.

  • Homelab-friendly: run it in minutes with Docker.
  • Practical: edit in the UI and autosave to network.json.
  • Declarative: keep your topology in Git if you wish.

Docker Hub | Live Demo (Read-Only) | GitHub Releases

Open Network Diagram network view with ethernet labels

Features

  • Network view with ethernet labels to make physical and logical links easy to read.
  • Hosts & VMs view for host-first inventory and service mapping.
  • Rack view: managed racks with U positions and heights, side-by-side shelf items, and click-through to the editor.
  • Node search that highlights matches by name, IP, role or OS and dims everything else.
  • IPAM panel: per-subnet utilization, duplicate-IP conflict detection, and next-free-IP suggestions when adding machines, devices or VMs.
  • Subnet and VLAN declarations, with nodes colour-coded by VLAN and a clickable legend filter.
  • Cable tracking on connections (type, colour, length) with colour-coded links and hover details.
  • Expandable VM lists per machine for quick virtualization visibility.
  • Modal editor for machines/devices with live diagram updates, notes and MAC address fields.
  • JSON-backed persistence with autosave in self-hosted mode.
  • Docker-first deployment with writable data volume support.
  • Optional read-only mode for public demos and safe sharing.
  • Local vendored icon catalog for offline-friendly runtime behavior.

Why Home Lab Users Use It

  • Keep an always-up-to-date map of machines, VMs, and devices.
  • Find a free IP and spot duplicate assignments without a spreadsheet.
  • Know exactly what's in your rack and where, down to the U.
  • Edit quickly through a modal UI instead of hand-editing large diagrams.
  • Persist everything to JSON so backups and Git workflows stay simple.
  • Stay fully self-hosted with no runtime dependency on external APIs.

2-Minute Docker Quick Start

This is the fastest way to run Open Network Diagram for a home lab.

  1. Create a local data folder:
mkdir -p data
  1. Run the published Docker image:
docker run -d \
  --name open-network-diagram \
  --restart unless-stopped \
  -p 8080:3000 \
  --user "$(id -u):$(id -g)" \
  -e NETWORK_DATA_FILE=/app/data/network.json \
  -e NETWORK_BACKUP_DIR=/app/data/.backups \
  -v "$(pwd)/data:/app/data" \
  jcreek23/open-network-diagram:latest

On first access, Open Network Diagram creates a valid blank data/network.json and shows the getting-started card.

  1. Open the app at http://localhost:8080.

  2. Add your first machine. Changes and rolling backups remain directly accessible in the local data directory across container updates and restarts.

Useful follow-up commands:

docker logs -f open-network-diagram
docker stop open-network-diagram
docker rm open-network-diagram

The --user option runs the container with your host UID and GID so files in the bind mount remain writable and owned by your account. Docker Desktop commonly handles bind-mount permissions without this mapping, so macOS users can omit --user if their Docker Desktop configuration requires the image's built-in user. If storage is not writable, the app leaves it untouched, loads the bundled read-only demo, and reports the exact permission problem in the UI.

Optional Sample Data

The application starts with a blank network by default. To explore the sample topology instead, download it before starting the container:

curl -fsSL https://raw.githubusercontent.com/jcreek/OpenNetworkDiagram/main/data/network.json.example \
  -o data/network.json

The sample is optional and is never required for startup.

Deployment Security

Open Network Diagram does not include authentication or TLS. The quick-start port mapping -p 8080:3000 listens on all host interfaces, so any device that can reach the host can view the topology and, in writable mode, change it.

Do not expose a writable deployment directly to the internet. Restrict access with a firewall, LAN or VPN, or place the application behind an authenticated reverse proxy that terminates TLS.

To make the service reachable only from the Docker host, replace the quick-start mapping with -p 127.0.0.1:8080:3000.

For a public demonstration, add -e NETWORK_READ_ONLY=true to docker run, or add NETWORK_READ_ONLY: 'true' under Compose's environment. Read-only mode prevents changes and uses the bundled demo if the configured data file is missing, but it does not hide a configured topology or replace authentication.

What It Looks Like

Network view with ethernet labels Hosts & VMs view with VMs expanded Modal editing a machine
Open Network Diagram network view with ethernet labels Open Network Diagram Hosts & VMs view with VMs expanded Open Network Diagram modal editing a machine
IPAM panel with subnet utilization Rack view with shelf items Dark mode
Open Network Diagram IPAM panel with subnet utilization Open Network Diagram rack view with shelf items Open Network Diagram dark mode
Zero-setup first run Read-only live demo
Open Network Diagram zero-setup first-run onboarding Open Network Diagram read-only live demo

Docker Compose Option

If you prefer compose:

services:
  open-network-diagram:
    image: jcreek23/open-network-diagram:latest
    user: '${OND_UID:?Set OND_UID to your host user ID}:${OND_GID:?Set OND_GID to your host group ID}'
    ports:
      - '8080:3000'
    volumes:
      - ./data:/app/data
    environment:
      NETWORK_DATA_FILE: /app/data/network.json
      NETWORK_BACKUP_DIR: /app/data/.backups
    restart: unless-stopped

Start it with:

mkdir -p data
OND_UID="$(id -u)" OND_GID="$(id -g)" docker compose up -d

OND_UID and OND_GID are required Compose interpolation values supplied by the command above; they are not application environment variables. Docker Desktop users can remove the user line if their file-sharing configuration requires the image's built-in user.

Using a Docker Named Volume

If host-directory permissions are inconvenient, Docker can manage the storage volume instead:

docker run -d \
  --name open-network-diagram \
  --restart unless-stopped \
  -p 8080:3000 \
  -e NETWORK_DATA_FILE=/app/data/network.json \
  -e NETWORK_BACKUP_DIR=/app/data/.backups \
  -v ond-data:/app/data \
  jcreek23/open-network-diagram:latest

Docker creates the ond-data volume automatically. Use docker volume inspect ond-data to inspect its location or docker cp open-network-diagram:/app/data/network.json ./network.json to copy the data file out.

Versioning Your Topology

data/network.json and data/.backups are ignored by Git because topology data may expose host names, addresses, MAC addresses, and other sensitive infrastructure details. If you have reviewed and sanitized the data and deliberately want to track it, opt in with:

git add -f data/network.json
git commit -m "Track network topology"

Once the file is tracked, normal Git commands include later changes. Backup files remain ignored.

For Developers

Local Development

git clone https://github.com/jcreek/OpenNetworkDiagram.git
cd OpenNetworkDiagram
pnpm install
pnpm run dev

App URL: http://localhost:5173

Build Targets

pnpm run build          # default build
pnpm run build:docker   # Docker/static target
pnpm run build:netlify  # Netlify target (read-only mode)
pnpm run icons:manifest # regenerate local vendor icon manifest

Runtime and Persistence

  • API endpoint: GET/PUT /api/network-data
  • Writes are enabled unless NETWORK_READ_ONLY=true
  • Writable deployments automatically initialize a missing or whitespace-only data file with a blank network.
  • Read-only deployments never initialize or modify the configured data file and continue to use the bundled demo when the API data is unavailable.
  • When writes are unavailable, API responses include writableReason for diagnostics.
  • Writes are persisted atomically to the configured data file
  • Rolling backups are kept in the backup directory (last 5)

Environment variables:

  • NETWORK_READ_ONLY (default: false)
    • Set to true to disable writes and force read-only mode.
  • NETWORK_DATA_FILE (default: data/network.json)
    • JSON file path to read/write.
  • NETWORK_BACKUP_DIR (default: data/.backups)
    • Directory for backup files.

JSON Example

{
	"machines": [
		{
			"machineName": "ProxRouter",
			"ipAddress": "10.0.0.3",
			"role": "Hypervisor",
			"operatingSystem": "Proxmox",
			"notes": "Primary router box.",
			"software": {
				"vms": [
					{
						"name": "OpnSense",
						"role": "Router",
						"ipAddress": "10.0.0.4",
						"macAddress": "bc:24:11:5a:2e:01"
					}
				]
			},
			"hardware": {
				"cpu": "Intel N100",
				"ram": "8GB",
				"networkPorts": 4
			},
			"ports": [
				{
					"portName": "eth0",
					"speedGbps": 1,
					"connectedTo": {
						"device": "Switch",
						"port": "1",
						"cable": { "type": "Cat6", "color": "blue", "lengthM": 1 }
					}
				}
			],
			"rack": { "name": "Lab Rack", "unit": 10 }
		}
	],
	"devices": [
		{
			"name": "Switch",
			"ipAddress": "10.0.0.2",
			"type": "Network Switch",
			"ports": [
				{
					"portName": "1",
					"speedGbps": 1,
					"connectedTo": {
						"device": "ProxRouter",
						"port": "eth0",
						"cable": { "type": "Cat6", "color": "blue", "lengthM": 1 }
					}
				}
			],
			"rack": { "name": "Lab Rack", "unit": 12 }
		}
	],
	"subnets": [{ "cidr": "10.0.0.0/24", "name": "LAN", "vlanId": 1 }],
	"racks": [{ "name": "Lab Rack", "heightU": 12 }]
}

Notes on the optional fields:

  • subnets powers the IPAM panel and VLAN colouring (vlanId is optional per subnet).
  • racks declares rack names and total units for the rack view; machines/devices opt in with a rack placement (unit is the bottom U, heightU defaults to 1). Items with the identical U range render side by side as shelf-mates.
  • cable on a connectedTo records type/colour/length and is kept identical on both ends automatically.
  • notes (machines and devices) and macAddress (ports and VMs) are free text.

Project Structure

OpenNetworkDiagram/
├── src/                               # Svelte app source
├── src/lib/shared/                    # Schema + persistence core (shared with server.mjs)
├── src/lib/config/vendorIconManifest.ts # Generated local icon catalog
├── static/data/network.json           # Demo dataset (Netlify)
├── static/icons/vendor/               # Vendored icon assets (runtime-local)
├── data/network.json.example          # Optional starter data template
├── third_party/                       # Third-party provenance + licensing
├── Dockerfile                         # Docker build/runtime image
├── server.mjs                         # Node runtime server (static + API)
├── docker-compose.yml                 # Local compose example (build from repo)
├── netlify.toml                       # Netlify build config
└── .github/workflows/                 # CI workflows

CI/CD

  • docker.yml: validates AMD64 and ARM64 Docker builds on pull requests.
  • release.yml: semantic release on main and multi-platform Docker Hub publish for tagged releases.
  • Published images support AMD64 and 64-bit ARM (including Raspberry Pi systems); Docker selects the matching variant automatically.
  • Docker Hub image: jcreek23/open-network-diagram

Contributing

  1. Fork the repository.
  2. Create a feature branch.
  3. Before committing, run:
pnpm lint
pnpm test
pnpm check
pnpm run build:docker
pnpm run build:netlify
  1. Commit your changes.
  2. Push your branch.
  3. Open a pull request.

License

GNU GPL v3

S
Description
No description provided
Readme GPL-3.0 223 MiB
Languages
TypeScript 69%
Svelte 23.4%
JavaScript 7.1%
CSS 0.4%
Dockerfile 0.1%