A self-hosted homelab dashboard inspired by Homer, with automatic LAN service discovery.
Default NetDash port: 18787 — chosen to avoid conflicts with common homelab ports such as Readarr (8787).
Recommended deploy: Ubuntu VM on Proxmox + Dockge — not QNAP. A 2 GB RAM VM is sufficient for NetDash alone (512M container limit). QNAP is deprecated — see DEPRECATION-QNAP.md.
Run this on any Linux host with Docker:
curl -fsSL https://raw.githubusercontent.com/lobrzut/netdash/main/deploy/docker-simple/install.sh | bashOpen http://:18787 and sign in with admin / changeme, then change the password in Settings → Password.
Port note: NetDash uses 18787 by default. Set
NETDASH_LISTEN_PORTin.envto change it. If you are migrating an older install on 8787, setNETDASH_LISTEN_PORT=8787.
Windows (Docker Desktop): irm https://raw.githubusercontent.com/lobrzut/netdash/main/deploy/docker-simple/install.ps1 | iex — see deploy/docker-simple/.
Dark-theme homelab dashboard with pinned services, API key vault, notes, and network filters.
| Dashboard | Services |
|---|---|
![]() |
![]() |
| Settings | Login |
|---|---|
![]() |
![]() |
Screenshots use demo data only (
*.demo.local,10.0.0.x, masked keys likesk-demo-…). Regenerate withNETDASH_DEMO_MODE=1 python scripts/capture_screenshots.py(requires Playwright and a running app on port 18787).
| Homer | NetDash |
|---|---|
| Manual YAML configuration | Automatic network scanning (CIDR / local /24) |
| Static service list | Service detection and identification (HTTP, title, favicon) |
| Icons from config | 70+ brand icons (Jellyfin, Grafana, Plex, and more) + favicon fallback |
| No vault | Encrypted API key vault (Fernet) |
| No notes | Notes widget with markdown |
| — | Visibility filters: login required / public |
| — | Widgets: clock, stats, search |
- Two scan modes — automatic adaptive background discovery vs on-demand manual scan (with Stop)
- Auto-discovery (ping, port scan, HTTP/HTTPS identification)
- IPS-friendly / stealth probing — spreads port probes per host over time to avoid Symantec SEP and similar endpoint IPS blocks (on by default)
- Settings toggle to disable automatic background discovery (manual add and manual scan still work)
- Auto-remove stale services — configurable offline days (
NETDASH_STALE_REMOVE_DAYSor Settings → Scanning) - Dark theme with configurable accent color
- JWT authentication and encrypted API key vault
- Per-service notes plus Wake-on-LAN / Sleep-on-LAN (install scripts auto-detect MAC per OS; pre-filled from discovery)
- Mobile-friendly WOL/SOL — tile action buttons tappable on touch devices
- 70+ brand icons via Simple Icons
- Persistent online/offline health checks
- One-command Docker deployment
- i18n support: English, Polish, German, Ukrainian
- Optional Brain stats tile — live knowledge-base counts (notes, sessions, library, graph) from a
/statsendpoint; “Open dashboard” link when Brain is online; off by default - Optional Network tile — LAN/WAN info (public IP, ISP, country), link latency, discovery sparkline; off by default
- Remote discovery agent (v1.3.112): lightweight LAN scanner on a separate host pushing to
POST /api/discovery/import(ideal for split deployments)
If NetDash runs on a low-power NAS (for example QNAP) without safe LAN scan access, disable local scanning and use a remote agent:
| Host | Role |
|---|---|
QNAP .150 |
Dashboard only — NETDASH_SCAN_DISABLED=true |
Homelab .201 |
deploy/agent/docker-compose.yml — network_mode: host, arp-scan |
See deploy/agent/README.md and deploy/qnap/README.md.
- IPS-friendly / stealth scanning — probes one host gently (1 port at a time by default, randomized order, jittered delay) so Symantec SEP and similar endpoint IPS do not block NetDash's source IP for 600 s. Env:
NETDASH_IPS_FRIENDLY,NETDASH_PORT_PARALLEL_PER_HOST,NETDASH_PORTS_PER_HOST_DELAY,NETDASH_PORTS_PER_HOST_JITTER,NETDASH_SCAN_RANDOMIZE_PORTS(all on by default). IncreaseNETDASH_PORTS_PER_HOST_DELAYif still blocked.
- Mobile WOL/SOL tap fix — tile action buttons (⚡ WOL, 💤 SOL, pin, edit, notes) are always visible and tappable on touch devices; taps no longer fall through to open the service.
- Sleep-on-LAN install scripts — auto-detect primary-interface MAC on Linux, Windows, and macOS; MAC from NetDash discovery is pre-filled when generating a script from a service.
- Settings → Automatic discovery — UI toggle to disable background network scanning without a container restart. Manual Add service and manual scan still work.
- Brain tile — discreet “Open dashboard” link in the tile header when Brain is online (URL derived from
brain_stats_url).
- Auto-remove inactive services —
NETDASH_STALE_REMOVE_DAYS(0 = off) or checkbox in Settings → Scanning removes auto-discovered offline entries after N days; pinned and manual entries are skipped.
- Health check fixes — local-IP services are probed like remote hosts; offline status after N consecutive failures (
NETDASH_HEALTH_OFFLINE_AFTER_FAILURES).
NETDASH_DISCOVERY_ENABLEDkill switch — master off for background TCP discovery; auto-disabled on hosts with <~2.1 GB RAM. Nuclear-safe 2 GB VM defaults indockge/compose.yaml(512M limit, discovery off, enrich off).- Watchtower —
nickfedor/watchtower:1.7.1in Dockge compose (Docker 29+ / API 1.44+). Balanced deploy:bash dockge/deploy-balanced.sh.
- Two scan modes — automatic (adaptive background,
/28chunks,NETDASH_AUTO_DISCOVERY_ALL_PORTS) vs manual (Scan options button, hard limits, Stop). QNAP/Proxmox port probes fixed (8006, DSM 5000/5001/8080/8081).
- Discover services on any port —
NETDASH_AUTO_DISCOVERY_ALL_PORTS=true(auto, gradual) orNETDASH_SCAN_ALL_PORTS=true(manual) deep-probes live hosts against ~190 service ports (8123,32400,9090, …).
- Network tile polish — link latency (Cloudflare / Google) replaced the category donut; the WAN line shows city + country; the tile fits the widget.
- API vault & notes — key cards no longer overlap in the narrow tile; notes are full-width list rows.
- Stop a running network scan — the scan bar now has a Stop button that cancels the background job.
- Network tile shows a real country flag image (emoji flags don't render on Windows); revealed API keys stay inside the card (scrollable).
- Network tile (off by default) — LAN IP / gateway / subnet, device online/total counts, WAN public IP + ISP/country (GeoIP) with flag, a services-by-category donut and a 7-day discovery sparkline.
- "Update now" via the Watchtower HTTP API — triggers an immediate pull + recreate without mounting
docker.sockinto the portal (safe on QNAP).
- Optional Brain stats tile (off by default) — point it at a Brain
/statsendpoint (knowledge counts) in Settings → Appearance and it shows live numbers; served via the auth-gated/api/brain/statsproxy.
- Visible brand/icon watermark on every tile — pinned cards and emoji/letter tiles now included (no more blank backgrounds).
- Login brute-force guard (
429+Retry-After, 5 attempts / 5 min per IP+user); UI-set password no longer overwritten on restart. - Swagger
/docsoff by default (NETDASH_DOCS_ENABLED=trueto enable). python-jose→PyJWT(CVE-2024-33663/33664); SSRF guard for cloud-metadata endpoints.
- Recommended: Proxmox Ubuntu VM + Dockge — dockge/README.md (2 GB RAM sufficient; balanced profile:
dockge/deploy-balanced.sh). - QNAP: deprecated — DEPRECATION-QNAP.md.
Full version history: CHANGELOG.md.
See ROADMAP.md for remaining work.
Clone and run on a fresh Linux server (or locally):
git clone https://github.com/lobrzut/netdash.git
cd netdash
cp .env.example .env
# Edit .env and set NETDASH_SECRET_KEY (password defaults to changeme)
docker compose up -d --buildOpen http://localhost:18787 (or http://<server-ip>:18787 on your LAN).
Default login: admin / changeme (synced from env on container start when NETDASH_SYNC_ADMIN_PASSWORD=true).
Change the password immediately after first login (Settings → Password).
Full deployment instructions: DEPLOYMENT.md.
On a Linux host with Dockge:
git clone https://github.com/lobrzut/netdash.git /opt/stacks/netdash
cd /opt/stacks/netdash && cp .env.example .envIn Dockge: Scan Stacks Folder → deploy stack netdash.
Compose file: dockge/compose.yaml (alias dockge/docker-compose.yml). Copy or symlink it into the expected stack root if required by your Dockge setup.
LAN scanning requires network_mode: host (Linux only) — see dockge/README.md.
curl -fsSL https://raw.githubusercontent.com/lobrzut/netdash/main/deploy/docker-simple/install.sh | bashManual alternative: deploy/docker-simple/docker-compose.yml + .env.example, then run docker compose up -d.
git clone https://github.com/lobrzut/netdash.git
cd netdash
python -m venv .venv
# Windows: .venv\Scripts\activate
# Linux/macOS: source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # optional for local dev; config.py defaults also work
python run.pyShortcuts: Windows .\start.ps1, Linux ./start.sh.
NetDash has two scan modes:
| Mode | Trigger | Purpose |
|---|---|---|
| Automatic discovery | Background (NETDASH_DISCOVERY_MODE=adaptive) |
Low-priority, throttled scan from Settings → Automatic discovery (or NETDASH_SCAN_CIDR). Rotates /28 chunks; optional gradual all-port probe via NETDASH_AUTO_DISCOVERY_ALL_PORTS (off by default on 2 GB VMs). Disable entirely with NETDASH_DISCOVERY_ENABLED=false. |
| Manual scan | Scan options button | On-demand CIDR scan. Hard limits (NETDASH_MANUAL_SCAN_MAX_HOSTS, max /24). Optional NETDASH_SCAN_ALL_PORTS=true for full port list. Stop button cancels the job. |
- Sign in.
- For manual scan: click Scan options, pick a CIDR (e.g.
192.168.1.144/28), confirm. - For automatic discovery: set CIDR in Settings → Automatic discovery and ensure
NETDASH_DISCOVERY_MODE=adaptive(default indockge/compose.yaml). - Services appear in real time.
Docker note: without
network_mode: host, the container scans its own bridge network (172.x), not your LAN. On Linux,docker-compose.ymlusesnetwork_mode: host. On Windows/macOS, disable host mode and setNETDASH_SCAN_CIDR=192.168.1.0/24in.envor in Settings → Automatic discovery.
On LANs where workstations run Symantec Endpoint Protection or similar endpoint IPS, aggressive port scanning can trigger a 600 s block on NetDash's source IP (The client will block traffic from IP address … for the next 600 seconds). This was most likely when deep-probing ~190 service ports on a single live host at once.
IPS-friendly mode (on by default) probes each host gently: limited per-host parallelism, randomized port order, and a jittered delay between probes to the same host. Cross-host parallelism is unchanged, so discovery stays effective. Health checks serialize probes to the same host too.
| Variable | Default | Purpose |
|---|---|---|
NETDASH_IPS_FRIENDLY |
true |
Master switch for gentle per-host probing |
NETDASH_PORT_PARALLEL_PER_HOST |
1 |
Max concurrent port probes to one host |
NETDASH_PORTS_PER_HOST_DELAY |
0.3 |
Seconds between probes to the same host |
NETDASH_PORTS_PER_HOST_JITTER |
0.2 |
Random extra delay (0…N s) per probe |
NETDASH_SCAN_RANDOMIZE_PORTS |
true |
Randomize port order (avoids sequential scan signatures) |
If SEP still blocks NetDash, increase NETDASH_PORTS_PER_HOST_DELAY (e.g. 0.6–1.0). Set NETDASH_IPS_FRIENDLY=false only on isolated lab networks where fast scanning matters more than IPS avoidance.
NetDash is designed to run on low-resource homelab hardware. A 2 GB Proxmox VM is enough for NetDash solo (512M container limit in dockge/compose.yaml). Safe scan mode (NETDASH_SCAN_SAFE_MODE=true) is on by default with lower concurrency, a shorter port list, and host limits.
| Problem | Recommendation |
|---|---|
| Host becomes unstable during scans | Keep safe mode enabled; use automatic discovery (chunked /28) instead of manual /24 |
| Need full LAN coverage | Set NETDASH_SCAN_CIDR=192.168.1.0/24 and NETDASH_DISCOVERY_MODE=adaptive — background scan covers the /24 over time |
| Manual scan on strong hardware | Keep NETDASH_SCAN_SAFE_MODE=true on shared VLANs; use /28 manual scans or accept confirmation for /24 |
| Scans are too slow on strong hardware | Tune NETDASH_DISCOVERY_INTERVAL or NETDASH_DISCOVERY_PROFILE=strong — do not disable chunking on weak hosts |
| Full port scan needed | NETDASH_AUTO_DISCOVERY_ALL_PORTS=true (auto, gradual — 4 GB+ VM) or NETDASH_SCAN_ALL_PORTS=true (manual only) |
| Discovery overloads weak host | NETDASH_DISCOVERY_ENABLED=false or use ultra-safe profile in .env.example |
| Symantec SEP / IPS blocks NetDash IP | IPS-friendly mode is on by default; increase NETDASH_PORTS_PER_HOST_DELAY (e.g. 0.6–1.0) |
| Health checks consume too many resources | Increase health-check interval (for example 120s) or disable it |
| Stale offline services clutter the list | Enable auto-remove in Settings → Scanning or set NETDASH_STALE_REMOVE_DAYS=7 |
Example .env for Proxmox VM 2 GB (balanced — or run bash dockge/deploy-balanced.sh):
NETDASH_DISCOVERY_ENABLED=true
NETDASH_SCAN_SAFE_MODE=true
NETDASH_DISCOVERY_MODE=adaptive
NETDASH_SCAN_CIDR=192.168.1.0/24
NETDASH_AUTO_DISCOVERY_ALL_PORTS=false
NETDASH_AUTO_DISCOVERY_ALWAYS_CHUNK=trueExample .env for low-resource hosts:
NETDASH_SCAN_SAFE_MODE=true
NETDASH_SCAN_CIDR=192.168.1.0/28Check profile output: curl -s http://127.0.0.1:18787/api/health → scan_safe_mode, resource_profile, auto_discovery_all_ports.
Deployment details: DEPLOYMENT.md · Dockge: dockge/README.md · QNAP (deprecated): DEPRECATION-QNAP.md.
| Profile | Run command | URL |
|---|---|---|
| Local / dev | python run.py, start.ps1, start.sh |
http://localhost:18787 |
| Server / Docker | docker compose up -d (Linux, network_mode: host) |
http://:18787 |
More options: DEPLOYMENT.md · simple Docker: deploy/docker-simple/ · QNAP: deploy/qnap/ · SSH deploy: deploy/README.md.
sudo mkdir -p /opt/netdash/data
cd /opt/netdash
git clone https://github.com/lobrzut/netdash.git .
cp .env.example .env
# Set NETDASH_SECRET_KEY (>=32 random chars); default login is admin/changeme
docker compose up -d --build
docker compose ps # expected: healthySQLite path: ./data/netdash.db (volume ./data:/app/data).
$env:NETDASH_SSH_HOST = "user@your-server"
$env:NETDASH_SSH_PASSWORD = "your-ssh-password"
$env:NETDASH_SSH_HOSTKEY = "ssh-ed25519 255 ..."
.\deploy\install.ps1Linux rsync option: NETDASH_SSH_HOST=user@your-server ./deploy/install.sh.
sudo useradd -r -m netdash || true
cd /opt/netdash
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
cp .env.example .env
sudo cp deploy/netdash.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now netdash| Variable | Description |
|---|---|
NETDASH_SECRET_KEY |
JWT signing key and API vault encryption key (required for Docker) |
NETDASH_DEFAULT_ADMIN_USER |
Default admin username (admin) |
NETDASH_DEFAULT_ADMIN_PASSWORD |
Admin password from env (changeme by default — change after first login) |
NETDASH_SYNC_ADMIN_PASSWORD |
Sync admin password from env on every start (true by default; set to false after changing in UI) |
NETDASH_SCAN_CIDR |
Networks for automatic discovery (and Docker bridge LAN override) |
NETDASH_DISCOVERY_ENABLED |
Master switch for background TCP discovery (false by default in Dockge compose); UI toggle in Settings → Automatic discovery when env is not locked |
NETDASH_DISCOVERY_MODE |
adaptive (background TCP discovery), arp, local, or remote |
NETDASH_SCAN_SAFE_MODE |
Safe manual scan limits (true by default) |
NETDASH_SCAN_ALL_PORTS |
Deep-probe live hosts on ~190 service ports during manual scan (false by default) |
NETDASH_AUTO_DISCOVERY_ALL_PORTS |
Gradual ~190-port probe on live hosts in auto mode (false by default on 2 GB VMs) |
NETDASH_AUTO_DISCOVERY_ALWAYS_CHUNK |
Never scan full /24 in one auto cycle (true by default) |
NETDASH_MANUAL_SCAN_MAX_HOSTS |
Hard cap for manual scan host count (default 128) |
NETDASH_IPS_FRIENDLY |
Gentle per-host port probing to avoid endpoint IPS blocks (true by default) |
NETDASH_PORT_PARALLEL_PER_HOST |
Max concurrent port probes to one host when IPS-friendly (default 1) |
NETDASH_PORTS_PER_HOST_DELAY |
Seconds between port probes to the same host (default 0.3) |
NETDASH_PORTS_PER_HOST_JITTER |
Random extra delay per same-host probe (default 0.2) |
NETDASH_SCAN_RANDOMIZE_PORTS |
Randomize port probe order (true by default) |
NETDASH_STALE_REMOVE_DAYS |
Auto-remove auto-discovered offline services after N days (0 = off; UI in Settings → Scanning overrides when > 0) |
NETDASH_HEALTH_OFFLINE_AFTER_FAILURES |
Mark service offline after N consecutive failed health probes (default 2) |
NETDASH_BUILD_DATE |
Optional build date for About panel |
See .env.example for the full list.
- Backend: FastAPI, SQLAlchemy, SQLite
- Frontend: Vanilla JavaScript (no Node.js build step)
- Auth: JWT + bcrypt
- Vault: Fernet (
cryptography)
netdash/
├── app/
│ ├── main.py # API routes
│ ├── scanner.py # Auto-discovery
│ ├── icons.py # Brand icons
│ ├── vault.py # Key encryption
│ └── static/ # Frontend
├── deploy/
├── dockge/ # Proxmox + Dockge (recommended)
├── docker-compose.yml
├── Dockerfile
└── run.py
- Online/offline status and health checks
- Per-service notes and Wake-on-LAN
- Homer YAML import (MVP)
- YAML export (Homer compatibility)
- ARP-based device discovery
- Multi-user support
- Homer (Apache-2.0) — UI inspiration and YAML import compatibility.
- GPTWOL (MIT, Misterbabou) — Wake/Sleep-on-LAN ideas and optional HTTP gateway integration (
gptwol_urlin settings). NetDash implements WoL/SOL and ARP discovery independently and is not a GPTWOL fork.
MIT — suitable for portfolio, homelab, and commercial use.
A modern Homer alternative with automatic network discovery.



