From e2052082e09559578227c9d5345100e138b8e6f8 Mon Sep 17 00:00:00 2001 From: Josh Creek <8179928+jcreek@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:51:22 +0000 Subject: [PATCH 1/4] feat(#4): Add docker support --- .dockerignore | 13 + .github/workflows/docker.yml | 56 ++++ .gitignore | 3 + Dockerfile | 38 +++ data/network.json.example | 54 ++++ docker-compose.yml | 11 + nginx/default.conf | 16 ++ package.json | 3 + pnpm-lock.yaml | 12 + static/data/network.json | 494 ----------------------------------- svelte.config.js | 16 +- 11 files changed, 217 insertions(+), 499 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/docker.yml create mode 100644 Dockerfile create mode 100644 data/network.json.example create mode 100644 docker-compose.yml create mode 100644 nginx/default.conf delete mode 100644 static/data/network.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2781986 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +.git +.github +.svelte-kit +.vscode +node_modules +.pnpm-store +.DS_Store +Thumbs.db +coverage +dist +.env +.env.* +data/network.json diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..d3aeb35 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,56 @@ +name: Docker + +on: + pull_request: + branches: + - main + push: + branches: + - main + tags: + - "v*.*.*" + +env: + IMAGE_NAME: jcreek23/open-network-diagram + +jobs: + docker: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + if: github.event_name == 'push' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: docker.io/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=sha,prefix=sha- + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Build (PR) / Build+Push (push) + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile + push: ${{ github.event_name == 'push' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore index 3b462cb..e2cbe7a 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,9 @@ Thumbs.db !.env.example !.env.test +# User-provided Docker data +data/network.json + # Vite vite.config.js.timestamp-* vite.config.ts.timestamp-* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6dca253 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +FROM node:20-alpine AS builder + +WORKDIR /app + +ENV PNPM_HOME=/pnpm +ENV PATH=$PNPM_HOME:$PATH + +RUN corepack enable + +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile --store-dir /pnpm/store + +COPY . . + +ENV DEPLOY_TARGET=docker +RUN pnpm run build:docker + +FROM nginxinc/nginx-unprivileged:1.27-alpine AS runner + +USER root + +RUN apk add --no-cache libcap && \ + setcap 'cap_net_bind_service=+ep' /usr/sbin/nginx + +COPY nginx/default.conf /etc/nginx/conf.d/default.conf +COPY --from=builder /app/build /usr/share/nginx/html + +RUN mkdir -p /usr/share/nginx/html/data && \ + chown -R 101:101 /usr/share/nginx/html /var/cache/nginx /var/run /etc/nginx/conf.d + +USER 101 + +EXPOSE 80 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD wget -qO- http://127.0.0.1/ > /dev/null || exit 1 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/data/network.json.example b/data/network.json.example new file mode 100644 index 0000000..7620d12 --- /dev/null +++ b/data/network.json.example @@ -0,0 +1,54 @@ +{ + "machines": [ + { + "machineName": "Example Host", + "ipAddress": "192.168.1.10", + "role": "Hypervisor", + "operatingSystem": "Linux", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Example Switch", + "port": "1" + } + } + ], + "software": { + "vms": [ + { + "name": "Example VM", + "role": "Service", + "ipAddress": "192.168.1.20" + } + ] + }, + "hardware": { + "cpu": "CPU model", + "ram": "16GB", + "networkPorts": 1, + "networkPortSpeedGbps": 1, + "gpu": "Optional GPU" + } + } + ], + "devices": [ + { + "name": "Example Switch", + "ipAddress": "192.168.1.2", + "type": "Network Switch", + "notes": "Optional notes", + "ports": [ + { + "portName": "1", + "speedGbps": 1, + "connectedTo": { + "device": "Example Host", + "port": "eth0" + } + } + ] + } + ] +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d4f567c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +services: + open-network-diagram: + build: + context: . + dockerfile: Dockerfile + image: open-network-diagram:local + ports: + - "8080:80" + volumes: + - ./data:/usr/share/nginx/html/data:ro + restart: unless-stopped diff --git a/nginx/default.conf b/nginx/default.conf new file mode 100644 index 0000000..6d3f25b --- /dev/null +++ b/nginx/default.conf @@ -0,0 +1,16 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + location /data/ { + try_files $uri =404; + add_header Cache-Control "no-cache"; + } + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/package.json b/package.json index 0d9979f..ec7bcf1 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ "scripts": { "dev": "vite dev", "build": "vite build", + "build:docker": "DEPLOY_TARGET=docker vite build", + "build:netlify": "DEPLOY_TARGET=netlify vite build", "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", @@ -19,6 +21,7 @@ "@eslint/js": "^8.57.1", "@sveltejs/adapter-auto": "^4.0.0", "@sveltejs/adapter-netlify": "^5.0.0", + "@sveltejs/adapter-static": "^3.0.10", "@sveltejs/kit": "^2.16.0", "@sveltejs/vite-plugin-svelte": "^5.0.0", "@tailwindcss/typography": "^0.5.15", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b9ef4af..b834361 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,6 +30,9 @@ importers: '@sveltejs/adapter-netlify': specifier: ^5.0.0 version: 5.0.0(@sveltejs/kit@2.20.4(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2))) + '@sveltejs/adapter-static': + specifier: ^3.0.10 + version: 3.0.10(@sveltejs/kit@2.20.4(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2))) '@sveltejs/kit': specifier: ^2.16.0 version: 2.20.4(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)) @@ -595,6 +598,11 @@ packages: peerDependencies: '@sveltejs/kit': ^2.4.0 + '@sveltejs/adapter-static@3.0.10': + resolution: {integrity: sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew==} + peerDependencies: + '@sveltejs/kit': ^2.0.0 + '@sveltejs/kit@2.20.4': resolution: {integrity: sha512-B3Y1mb1Qjt57zXLVch5tfqsK/ebHe6uYTcFSnGFNwRpId3+fplLgQK6Z2zhDVBezSsPuhDq6Pry+9PA88ocN6Q==} engines: {node: '>=18.13'} @@ -2420,6 +2428,10 @@ snapshots: esbuild: 0.24.2 set-cookie-parser: 2.7.1 + '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.20.4(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)))': + dependencies: + '@sveltejs/kit': 2.20.4(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)) + '@sveltejs/kit@2.20.4(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)))(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2))': dependencies: '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.25.8)(vite@6.2.5(jiti@2.4.2)(lightningcss@1.29.2)) diff --git a/static/data/network.json b/static/data/network.json deleted file mode 100644 index a6a6f8c..0000000 --- a/static/data/network.json +++ /dev/null @@ -1,494 +0,0 @@ -{ - "machines": [ - { - "machineName": "ProxRouter", - "ipAddress": "10.0.0.3", - "role": "Hypervisor", - "operatingSystem": "Proxmox", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "1" - } - }, - { - "portName": "eth1", - "speedGbps": 1 - }, - { - "portName": "eth2", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "2" - } - }, - { - "portName": "eth3", - "speedGbps": 1, - "connectedTo": { - "device": "WAN Uplink", - "port": "wan" - } - } - ], - "software": { - "vms": [ - { - "name": "OpnSense", - "role": "Router/Firewall/Gateway (DHCP 10.0.0.100-254)", - "ipAddress": "10.0.0.1" - }, - { - "name": "TPLink Omada Controller", - "role": "Network Controller (:8043)", - "ipAddress": "10.0.0.4" - }, - { "name": "PiVPN (WireGuard)", "role": "VPN Server", "ipAddress": "10.0.0.5" }, - { - "name": "PiHole", - "role": "DNS Ad-blocker (installed, not in active use)", - "ipAddress": "10.0.0.6" - }, - { "name": "Dashy", "role": "Dashboard", "ipAddress": "10.0.0.12" }, - { - "name": "ProxRouter-Docker", - "role": "Docker host (Nginx reverse proxy, RustDesk, TwinGate)", - "ipAddress": "10.0.0.23" - } - ] - }, - "hardware": { - "cpu": "Intel N100", - "ram": "8GB", - "networkPorts": 4, - "networkPortSpeedGbps": 1 - } - }, - { - "machineName": "Asustor NAS", - "ipAddress": "10.0.0.9", - "role": "NAS", - "operatingSystem": "Asustor ADM", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "3" - } - } - ], - "software": { "vms": [] }, - "hardware": { - "cpu": "Realtek RTD1296 Quad Core 1.4GHz", - "ram": "2GB", - "networkPorts": 1, - "networkPortSpeedGbps": 1 - } - }, - { - "machineName": "Home Assistant Green", - "ipAddress": "10.0.0.13", - "role": "Smart Home Controller", - "operatingSystem": "Home Assistant OS", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "4" - } - } - ], - "software": { "vms": [] }, - "hardware": { - "cpu": "Home Assistant Custom SoC", - "ram": "Unknown", - "networkPorts": 1, - "networkPortSpeedGbps": 1 - } - }, - { - "machineName": "Plex Server", - "ipAddress": "10.0.0.11", - "role": "Media Server", - "operatingSystem": "Ubuntu Server", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "5" - } - } - ], - "software": { "vms": [] }, - "hardware": { - "cpu": "Intel N100", - "ram": "Unknown", - "networkPorts": 1, - "networkPortSpeedGbps": 1 - } - }, - { - "machineName": "Win11 N100", - "ipAddress": "10.0.0.8", - "role": "Media Downloader", - "operatingSystem": "Windows 11", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "6" - } - } - ], - "software": { "vms": [] }, - "hardware": { - "cpu": "Intel N100", - "ram": "Unknown", - "networkPorts": 1, - "networkPortSpeedGbps": 1 - } - }, - { - "machineName": "Win11 Backblaze NAS", - "ipAddress": "10.0.0.7", - "role": "Backup NAS + Hypervisor", - "operatingSystem": "TrueNAS Scale", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "7" - } - } - ], - "software": { - "vms": [ - { "name": "Win11NAS", "role": "Backblaze Backup VM", "ipAddress": "10.0.0.24" }, - { "name": "MakeMKV", "role": "Blu-ray Ripper", "ipAddress": "10.0.0.14" }, - { "name": "Handbrake", "role": "Video Transcoder", "ipAddress": "10.0.0.15" } - ] - }, - "hardware": { - "cpu": "AMD Ryzen 5 4600G", - "ram": "16GB", - "networkPorts": 1, - "networkPortSpeedGbps": 1, - "gpu": "EVGA GeForce GTX 1050 Ti" - } - }, - { - "machineName": "TrueNAS Host", - "ipAddress": "10.0.0.10", - "role": "Storage + VM Host", - "operatingSystem": "TrueNAS Scale", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "8" - } - } - ], - "software": { - "vms": [ - { - "name": "TrueNAS-Docker", - "role": "Docker host on TrueNAS", - "ipAddress": "10.0.0.25" - } - ] - }, - "hardware": { - "cpu": "Unknown", - "ram": "Unknown", - "networkPorts": 1, - "networkPortSpeedGbps": 1 - } - }, - { - "machineName": "AI Server", - "ipAddress": "10.0.0.20", - "role": "AI Dev/Inference", - "operatingSystem": "Pop!_OS", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "9" - } - } - ], - "software": { - "vms": [ - { "name": "Ollama", "role": "LLM Inference", "ipAddress": "10.0.0.21" }, - { "name": "Bot Training", "role": "AI Training", "ipAddress": "10.0.0.22" } - ] - }, - "hardware": { - "cpu": "AMD Ryzen 5 3600", - "ram": "32GB", - "networkPorts": 1, - "networkPortSpeedGbps": 1, - "gpu": "Gigabyte GeForce GTX 1080" - } - }, - { - "machineName": "Immich Mini PC", - "ipAddress": "10.0.0.30", - "role": "Photo Server", - "operatingSystem": "Linux", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "10" - } - } - ], - "software": { "vms": [] }, - "hardware": { - "cpu": "Unknown", - "ram": "Unknown", - "networkPorts": 1, - "networkPortSpeedGbps": 1 - } - } - ], - "devices": [ - { - "name": "Gigabit Switch", - "ipAddress": "unknown", - "type": "Network Switch", - "notes": "Main 24-port switch. Wireless access point uplinks through this switch.", - "ports": [ - { - "portName": "1", - "speedGbps": 1, - "connectedTo": { - "device": "ProxRouter", - "port": "eth0" - } - }, - { - "portName": "2", - "speedGbps": 1, - "connectedTo": { - "device": "ProxRouter", - "port": "eth2" - } - }, - { - "portName": "3", - "speedGbps": 1, - "connectedTo": { - "device": "Asustor NAS", - "port": "eth0" - } - }, - { - "portName": "4", - "speedGbps": 1, - "connectedTo": { - "device": "Home Assistant Green", - "port": "eth0" - } - }, - { - "portName": "5", - "speedGbps": 1, - "connectedTo": { - "device": "Plex Server", - "port": "eth0" - } - }, - { - "portName": "6", - "speedGbps": 1, - "connectedTo": { - "device": "Win11 N100", - "port": "eth0" - } - }, - { - "portName": "7", - "speedGbps": 1, - "connectedTo": { - "device": "Win11 Backblaze NAS", - "port": "eth0" - } - }, - { - "portName": "8", - "speedGbps": 1, - "connectedTo": { - "device": "TrueNAS Host", - "port": "eth0" - } - }, - { - "portName": "9", - "speedGbps": 1, - "connectedTo": { - "device": "AI Server", - "port": "eth0" - } - }, - { - "portName": "10", - "speedGbps": 1, - "connectedTo": { - "device": "Immich Mini PC", - "port": "eth0" - } - }, - { - "portName": "11", - "speedGbps": 1, - "connectedTo": { - "device": "HDHomeRun", - "port": "eth0" - } - }, - { - "portName": "12", - "speedGbps": 1 - }, - { - "portName": "13", - "speedGbps": 1 - }, - { - "portName": "14", - "speedGbps": 1 - }, - { - "portName": "15", - "speedGbps": 1 - }, - { - "portName": "16", - "speedGbps": 1 - }, - { - "portName": "17", - "speedGbps": 1 - }, - { - "portName": "18", - "speedGbps": 1 - }, - { - "portName": "19", - "speedGbps": 1 - }, - { - "portName": "20", - "speedGbps": 1 - }, - { - "portName": "21", - "speedGbps": 1 - }, - { - "portName": "22", - "speedGbps": 1 - }, - { - "portName": "23", - "speedGbps": 1 - }, - { - "portName": "24", - "speedGbps": 1 - } - ] - }, - { - "name": "WAN Uplink", - "ipAddress": "unknown", - "type": "ISP/WAN", - "notes": "Upstream internet link (modem/ONT/ISP path).", - "ports": [ - { - "portName": "wan", - "speedGbps": 1, - "connectedTo": { - "device": "ProxRouter", - "port": "eth3" - } - } - ] - }, - { - "name": "HDHomeRun", - "ipAddress": "10.0.0.2", - "type": "TV Tuner", - "ports": [ - { - "portName": "eth0", - "speedGbps": 1, - "connectedTo": { - "device": "Gigabit Switch", - "port": "11" - } - } - ] - }, - { - "name": "3DS", - "ipAddress": "10.0.0.17", - "type": "Handheld Console", - "notes": "Wi-Fi only." - }, - { - "name": "2DS", - "ipAddress": "10.0.0.18", - "type": "Handheld Console", - "notes": "Wi-Fi only." - }, - { - "name": "Nintendo Switch", - "ipAddress": "10.0.0.19", - "type": "Gaming Console", - "notes": "Wi-Fi only." - }, - { - "name": "NanoKVM Lite", - "ipAddress": "10.0.0.26", - "type": "KVM Device", - "notes": "Port link not yet modeled." - }, - { - "name": "UPS Pi", - "ipAddress": "10.0.0.27", - "type": "Power Monitoring Device", - "notes": "Port link not yet modeled." - }, - { - "name": "Waveshare", - "ipAddress": "10.0.0.28", - "type": "Peripheral Device", - "notes": "Port link not yet modeled." - } - ] -} diff --git a/svelte.config.js b/svelte.config.js index 57aec4b..49b4fa4 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,6 +1,15 @@ -import adapter from '@sveltejs/adapter-netlify'; +import netlifyAdapter from '@sveltejs/adapter-netlify'; +import staticAdapter from '@sveltejs/adapter-static'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; +const deployTarget = (process.env.DEPLOY_TARGET ?? 'docker').toLowerCase(); +const adapter = deployTarget === 'netlify' + ? netlifyAdapter() + : staticAdapter({ + fallback: 'index.html', + strict: false + }); + /** @type {import('@sveltejs/kit').Config} */ const config = { // Consult https://svelte.dev/docs/kit/integrations @@ -8,10 +17,7 @@ const config = { preprocess: vitePreprocess(), kit: { - // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. - // If your environment is not supported, or you settled on a specific environment, switch out the adapter. - // See https://svelte.dev/docs/kit/adapters for more information about adapters. - adapter: adapter() + adapter } }; From e002764e3228b3a7ae222cb200a9c53f07d8ca8e Mon Sep 17 00:00:00 2001 From: Josh Creek <8179928+jcreek@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:57:18 +0000 Subject: [PATCH 2/4] build(#4): Add netlify config --- netlify.toml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 netlify.toml diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..eb2e028 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,5 @@ +[build] + command = "pnpm run build:netlify" + +[build.environment] + DEPLOY_TARGET = "netlify" From 824db1c005886c19905902b20a9350a11f8a8436 Mon Sep 17 00:00:00 2001 From: Josh Creek <8179928+jcreek@users.noreply.github.com> Date: Sun, 22 Feb 2026 16:57:25 +0000 Subject: [PATCH 3/4] docs(#4): Update readme --- README.md | 84 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 510857f..afcb8f1 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ **Open Network Diagram** is an **open-source, self-hosted tool** for creating **interactive network and infrastructure diagrams** using a **declarative JSON format**. ✅ **Fully self-hostable via Docker** -✅ **JSON-based network structure** (editable in UI or manually) +✅ **Docker-first deployment target** (Netlify optional for demo hosting) ✅ **Interactive network visualisation** ✅ **Simple file-based configuration** ✅ **Lightweight Svelte** @@ -20,25 +20,41 @@ Use it to **document your home lab, office network, or cloud infrastructure** wi ## **🚀 Quick Start (For Users)** -### **1️⃣ Run Open Network Diagram via Docker** +### **1️⃣ Create Your Runtime Data File** -Pull and run the latest image: +Copy the template and edit your own network data: ```bash -docker run -d -p 8080:3000 jcreek23/open-network-diagram +cp data/network.json.example data/network.json ``` -- **`-p 8080:3000`** → Maps the app to `http://localhost:8080` +### **2️⃣ Run Open Network Diagram via Docker** -### **2️⃣ Open the Web UI** +From this repo: + +```bash +docker compose up --build +``` + +Or pull and run directly: + +```bash +docker run -d -p 8080:80 -v "$(pwd)/data:/usr/share/nginx/html/data:ro" jcreek23/open-network-diagram +``` + +- **`-p 8080:80`** → Maps the app to `http://localhost:8080` +- **`-v .../data:/usr/share/nginx/html/data:ro`** → Uses your local `data/network.json` + +### **3️⃣ Open the Web UI** Visit **`http://localhost:8080`** to view your network diagram. -### **3️⃣ Modify Your Network (JSON-Based)** +### **4️⃣ Modify Your Network (JSON-Based)** -- The app reads **`/data/network.json`** from static assets. -- In this repo, the default file is **`static/data/network.json`**. -- Update that file to change the diagram data. +- Docker runtime reads **`/data/network.json`** from the mounted volume. +- In this repo, your editable file is **`data/network.json`** (gitignored). +- Netlify demo builds use committed sample data at **`static/data/network.json`**. +- After editing JSON, click **Reload Default JSON** in the UI. --- @@ -65,17 +81,28 @@ pnpm run dev - Runs at `http://localhost:5173` +### **4️⃣ Build Targets** + +```bash +pnpm run build # default (Docker/static target) +pnpm run build:docker # explicit Docker/static target +pnpm run build:netlify # explicit Netlify target +``` + --- ## **🛠️ Project Structure** -``` +```text open-network-diagram/ -│ ├── src/ # Svelte components -│ ├── package.json # Dependencies -│── Dockerfile # Docker setup -│── .github/workflows/ # CI/CD pipelines -│── README.md # Documentation +├── src/ # Svelte app source +├── static/data/network.json # Demo dataset (Netlify/demo) +├── data/network.json.example # User data template (Docker) +├── Dockerfile # Docker build/runtime +├── docker-compose.yml # Local Docker run with mounted data +├── netlify.toml # Netlify build config +├── .github/workflows/ # CI workflows (Docker image build/push) +└── README.md # Documentation ``` --- @@ -91,13 +118,14 @@ docker build -t open-network-diagram . ### **Run Locally** ```bash -docker run -p 8080:3000 open-network-diagram +docker run --rm -p 8080:80 -v "$(pwd)/data:/usr/share/nginx/html/data:ro" open-network-diagram ``` -### **CI/CD (GitHub Actions)** +### **CI/CD (GitHub Actions + Netlify)** -- Automatic Docker builds when changes are pushed to `main`. -- Pushes the latest image to **Docker Hub**. +- GitHub Actions workflow (`.github/workflows/docker.yml`) builds Docker on PRs. +- Pushes to `main` publish Docker images to **Docker Hub** (`jcreek23/open-network-diagram`). +- Netlify uses its own CI/CD pipeline with `netlify.toml` (`pnpm run build:netlify`). --- @@ -114,10 +142,7 @@ Define your network using **`network.json`**: "role": "Hypervisor", "operatingSystem": "Proxmox", "software": { - "vms": [ - { "name": "OpnSense", "role": "Router", "ipAddress": "10.0.0.4" }, - { "name": "PiVPN", "role": "VPN Server", "ipAddress": "10.0.0.5" } - ] + "vms": [{ "name": "OpnSense", "role": "Router", "ipAddress": "10.0.0.4" }] }, "hardware": { "cpu": "Intel N100", @@ -125,7 +150,8 @@ Define your network using **`network.json`**: "networkPorts": 4 } } - ] + ], + "devices": [{ "name": "Switch", "ipAddress": "10.0.0.2", "type": "Nintendo Switch" }] } ``` @@ -163,11 +189,3 @@ We welcome contributions! To contribute: **Author:** [Joshua Creek](https://github.com/jcreek) **Project Repo:** [GitHub](https://github.com/jcreek/OpenNetworkDiagram) - ---- - -### **🔥 Next Steps** - -✅ **Set up GitHub Repo** -✅ **Push initial project structure** -✅ **Add CI/CD for automated Docker builds** From adfcac4d3c6274806a11061c57cdaae48d34d038 Mon Sep 17 00:00:00 2001 From: Josh Creek <8179928+jcreek@users.noreply.github.com> Date: Sun, 22 Feb 2026 17:08:00 +0000 Subject: [PATCH 4/4] build(#4): Add example data --- static/data/network.json | 494 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 static/data/network.json diff --git a/static/data/network.json b/static/data/network.json new file mode 100644 index 0000000..a6a6f8c --- /dev/null +++ b/static/data/network.json @@ -0,0 +1,494 @@ +{ + "machines": [ + { + "machineName": "ProxRouter", + "ipAddress": "10.0.0.3", + "role": "Hypervisor", + "operatingSystem": "Proxmox", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "1" + } + }, + { + "portName": "eth1", + "speedGbps": 1 + }, + { + "portName": "eth2", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "2" + } + }, + { + "portName": "eth3", + "speedGbps": 1, + "connectedTo": { + "device": "WAN Uplink", + "port": "wan" + } + } + ], + "software": { + "vms": [ + { + "name": "OpnSense", + "role": "Router/Firewall/Gateway (DHCP 10.0.0.100-254)", + "ipAddress": "10.0.0.1" + }, + { + "name": "TPLink Omada Controller", + "role": "Network Controller (:8043)", + "ipAddress": "10.0.0.4" + }, + { "name": "PiVPN (WireGuard)", "role": "VPN Server", "ipAddress": "10.0.0.5" }, + { + "name": "PiHole", + "role": "DNS Ad-blocker (installed, not in active use)", + "ipAddress": "10.0.0.6" + }, + { "name": "Dashy", "role": "Dashboard", "ipAddress": "10.0.0.12" }, + { + "name": "ProxRouter-Docker", + "role": "Docker host (Nginx reverse proxy, RustDesk, TwinGate)", + "ipAddress": "10.0.0.23" + } + ] + }, + "hardware": { + "cpu": "Intel N100", + "ram": "8GB", + "networkPorts": 4, + "networkPortSpeedGbps": 1 + } + }, + { + "machineName": "Asustor NAS", + "ipAddress": "10.0.0.9", + "role": "NAS", + "operatingSystem": "Asustor ADM", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "3" + } + } + ], + "software": { "vms": [] }, + "hardware": { + "cpu": "Realtek RTD1296 Quad Core 1.4GHz", + "ram": "2GB", + "networkPorts": 1, + "networkPortSpeedGbps": 1 + } + }, + { + "machineName": "Home Assistant Green", + "ipAddress": "10.0.0.13", + "role": "Smart Home Controller", + "operatingSystem": "Home Assistant OS", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "4" + } + } + ], + "software": { "vms": [] }, + "hardware": { + "cpu": "Home Assistant Custom SoC", + "ram": "Unknown", + "networkPorts": 1, + "networkPortSpeedGbps": 1 + } + }, + { + "machineName": "Plex Server", + "ipAddress": "10.0.0.11", + "role": "Media Server", + "operatingSystem": "Ubuntu Server", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "5" + } + } + ], + "software": { "vms": [] }, + "hardware": { + "cpu": "Intel N100", + "ram": "Unknown", + "networkPorts": 1, + "networkPortSpeedGbps": 1 + } + }, + { + "machineName": "Win11 N100", + "ipAddress": "10.0.0.8", + "role": "Media Downloader", + "operatingSystem": "Windows 11", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "6" + } + } + ], + "software": { "vms": [] }, + "hardware": { + "cpu": "Intel N100", + "ram": "Unknown", + "networkPorts": 1, + "networkPortSpeedGbps": 1 + } + }, + { + "machineName": "Win11 Backblaze NAS", + "ipAddress": "10.0.0.7", + "role": "Backup NAS + Hypervisor", + "operatingSystem": "TrueNAS Scale", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "7" + } + } + ], + "software": { + "vms": [ + { "name": "Win11NAS", "role": "Backblaze Backup VM", "ipAddress": "10.0.0.24" }, + { "name": "MakeMKV", "role": "Blu-ray Ripper", "ipAddress": "10.0.0.14" }, + { "name": "Handbrake", "role": "Video Transcoder", "ipAddress": "10.0.0.15" } + ] + }, + "hardware": { + "cpu": "AMD Ryzen 5 4600G", + "ram": "16GB", + "networkPorts": 1, + "networkPortSpeedGbps": 1, + "gpu": "EVGA GeForce GTX 1050 Ti" + } + }, + { + "machineName": "TrueNAS Host", + "ipAddress": "10.0.0.10", + "role": "Storage + VM Host", + "operatingSystem": "TrueNAS Scale", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "8" + } + } + ], + "software": { + "vms": [ + { + "name": "TrueNAS-Docker", + "role": "Docker host on TrueNAS", + "ipAddress": "10.0.0.25" + } + ] + }, + "hardware": { + "cpu": "Unknown", + "ram": "Unknown", + "networkPorts": 1, + "networkPortSpeedGbps": 1 + } + }, + { + "machineName": "AI Server", + "ipAddress": "10.0.0.20", + "role": "AI Dev/Inference", + "operatingSystem": "Pop!_OS", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "9" + } + } + ], + "software": { + "vms": [ + { "name": "Ollama", "role": "LLM Inference", "ipAddress": "10.0.0.21" }, + { "name": "Bot Training", "role": "AI Training", "ipAddress": "10.0.0.22" } + ] + }, + "hardware": { + "cpu": "AMD Ryzen 5 3600", + "ram": "32GB", + "networkPorts": 1, + "networkPortSpeedGbps": 1, + "gpu": "Gigabyte GeForce GTX 1080" + } + }, + { + "machineName": "Immich Mini PC", + "ipAddress": "10.0.0.30", + "role": "Photo Server", + "operatingSystem": "Linux", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "10" + } + } + ], + "software": { "vms": [] }, + "hardware": { + "cpu": "Unknown", + "ram": "Unknown", + "networkPorts": 1, + "networkPortSpeedGbps": 1 + } + } + ], + "devices": [ + { + "name": "Gigabit Switch", + "ipAddress": "unknown", + "type": "Network Switch", + "notes": "Main 24-port switch. Wireless access point uplinks through this switch.", + "ports": [ + { + "portName": "1", + "speedGbps": 1, + "connectedTo": { + "device": "ProxRouter", + "port": "eth0" + } + }, + { + "portName": "2", + "speedGbps": 1, + "connectedTo": { + "device": "ProxRouter", + "port": "eth2" + } + }, + { + "portName": "3", + "speedGbps": 1, + "connectedTo": { + "device": "Asustor NAS", + "port": "eth0" + } + }, + { + "portName": "4", + "speedGbps": 1, + "connectedTo": { + "device": "Home Assistant Green", + "port": "eth0" + } + }, + { + "portName": "5", + "speedGbps": 1, + "connectedTo": { + "device": "Plex Server", + "port": "eth0" + } + }, + { + "portName": "6", + "speedGbps": 1, + "connectedTo": { + "device": "Win11 N100", + "port": "eth0" + } + }, + { + "portName": "7", + "speedGbps": 1, + "connectedTo": { + "device": "Win11 Backblaze NAS", + "port": "eth0" + } + }, + { + "portName": "8", + "speedGbps": 1, + "connectedTo": { + "device": "TrueNAS Host", + "port": "eth0" + } + }, + { + "portName": "9", + "speedGbps": 1, + "connectedTo": { + "device": "AI Server", + "port": "eth0" + } + }, + { + "portName": "10", + "speedGbps": 1, + "connectedTo": { + "device": "Immich Mini PC", + "port": "eth0" + } + }, + { + "portName": "11", + "speedGbps": 1, + "connectedTo": { + "device": "HDHomeRun", + "port": "eth0" + } + }, + { + "portName": "12", + "speedGbps": 1 + }, + { + "portName": "13", + "speedGbps": 1 + }, + { + "portName": "14", + "speedGbps": 1 + }, + { + "portName": "15", + "speedGbps": 1 + }, + { + "portName": "16", + "speedGbps": 1 + }, + { + "portName": "17", + "speedGbps": 1 + }, + { + "portName": "18", + "speedGbps": 1 + }, + { + "portName": "19", + "speedGbps": 1 + }, + { + "portName": "20", + "speedGbps": 1 + }, + { + "portName": "21", + "speedGbps": 1 + }, + { + "portName": "22", + "speedGbps": 1 + }, + { + "portName": "23", + "speedGbps": 1 + }, + { + "portName": "24", + "speedGbps": 1 + } + ] + }, + { + "name": "WAN Uplink", + "ipAddress": "unknown", + "type": "ISP/WAN", + "notes": "Upstream internet link (modem/ONT/ISP path).", + "ports": [ + { + "portName": "wan", + "speedGbps": 1, + "connectedTo": { + "device": "ProxRouter", + "port": "eth3" + } + } + ] + }, + { + "name": "HDHomeRun", + "ipAddress": "10.0.0.2", + "type": "TV Tuner", + "ports": [ + { + "portName": "eth0", + "speedGbps": 1, + "connectedTo": { + "device": "Gigabit Switch", + "port": "11" + } + } + ] + }, + { + "name": "3DS", + "ipAddress": "10.0.0.17", + "type": "Handheld Console", + "notes": "Wi-Fi only." + }, + { + "name": "2DS", + "ipAddress": "10.0.0.18", + "type": "Handheld Console", + "notes": "Wi-Fi only." + }, + { + "name": "Nintendo Switch", + "ipAddress": "10.0.0.19", + "type": "Gaming Console", + "notes": "Wi-Fi only." + }, + { + "name": "NanoKVM Lite", + "ipAddress": "10.0.0.26", + "type": "KVM Device", + "notes": "Port link not yet modeled." + }, + { + "name": "UPS Pi", + "ipAddress": "10.0.0.27", + "type": "Power Monitoring Device", + "notes": "Port link not yet modeled." + }, + { + "name": "Waveshare", + "ipAddress": "10.0.0.28", + "type": "Peripheral Device", + "notes": "Port link not yet modeled." + } + ] +}