The Problem
Home‑lab operators need a simple way to discover devices on one or more LANs, keep persistent labels, and view the data through a lightweight UI or CLI. Existing tools either require a full‑stack installation or lack integration with Tailscale, making multi‑network setups cumbersome.
What This Does
LAN Orangutan ships as a single Go binary (cmd/orangutan/main.go) that can scan networks via nmap/ARP, store device records in JSON files (internal/storage/storage.go), and serve a web dashboard (internal/web/handler.go). The CLI commands (internal/cli/*.go) expose the same functionality (scan, list, export, status, serve).
Configuration lives in an INI file (config.example.ini) parsed by internal/config/config.go. Tailscale status is obtained via internal/network/tailscale.go. The Dockerfile builds a minimal golang:1.22-alpine image that copies the compiled binary and runs it as a container.
How It Is Wired
Execution starts at main in cmd/orangutan/main.go which creates a Cobra root command (internal/cli/root.go). The sub‑command serve calls runServe (internal/cli/serve.go → init → ServeHTTP).
- Web request flow –
ServeHTTP(ininternal/web/handler.go) routes to handlers: handleIndex→ rendersinternal/web/templates/index.html.handleSettings→ reads/writes config viainternal/config.handleDevices/handleDevice→ query the storage layer (internal/storage/storage.go) for device structs defined ininternal/types/types.go. These handlers collectively invoke 39 distinct functions, makingServeHTTPthe widest‑impact entry point.
- Scan flow –
runScan(internal/cli/scan.go) constructs aScanner(internal/scanner/scanner.go). Scanner.Newcreates the scanner,Scanner.Scandecides which backend to use (scanWithNmap,scanWithArpScan), then callsreverseDNS.- Results are persisted via
saveDevices(storage). runScanis called from three places (CLI, potential future automation, and the Docker entrypoint if used).
- Network detection –
DetectNetworks(internal/network/detect.go) is used by the scanner to enumerate CIDR blocks; it also feeds the UI for the “Networks” view.
- Tailscale integration –
GetTailscaleStatus(internal/network/tailscale.go) is invoked by the status command and the UI to show connectivity.
The import graph shows four internal modules with no circular dependencies, indicating a clean separation. The most‑referenced functions (success, New, IsOnline, DetectNetworks, GetTailscaleStatus, DevicesFile, StateFile) each have 5‑8 distinct callers, representing the primary blast radius for changes.
How To Use It
# Clone and build the binary
git clone https://github.com/moses-y/LAN-Orangutan
cd LAN-Orangutan
go build -o orangutan ./cmd/orangutan
# Run the web UI (requires sudo for full nmap data)
sudo ./orangutan serve # default http://localhost:291
# Scan a specific network
sudo ./orangutan scan 192.168.1.0/24
# List online devices in JSON
./orangutan list --online --format json
A Docker image can be built with the provided Dockerfile:
docker build -t lan-orangutan .
docker run --rm -p 291:291 lan-orangutan serve
Configuration files are expected at the platform‑specific paths described in README.md; the example file config.example.ini shows all supported options.
Real‑World Use
A homelab Raspberry Pi runs the container nightly via a systemd timer. The timer executes orangutan scan all to refresh the device inventory, while orangutan serve provides a persistent dashboard for the household. Tailscale status is displayed automatically, allowing remote access without exposing the Pi to the public internet.
Code Health & Issues
- HIGH – Pin third‑party GitHub Actions to a commit SHA (
.github/workflows/*.yml). - HIGH – No test suite (
26 source files, 0 test files). - MEDIUM – Enable Dependabot or Renovate (
go.mod,scanner/requirements.txt). - MEDIUM – Pin Docker base images by digest (
Dockerfile). - MEDIUM – Add a dependency‑vulnerability scan step to CI.
- MEDIUM – Set
persist-credentials: falseon the checkout step. - LOW – Add
timeout-minutesto workflow jobs. - LOW – Add repository convention files (
.editorconfig,.gitattributes, formatter config).
Additional observations: CI is present via GitHub Actions; a LICENSE file exists; no secrets are committed. The repository lacks any unit or integration tests, which limits confidence when modifying core functions such as Scanner.Scan or Storage.saveDevices.
The Bottom Line
LAN Orangutan delivers a functional, single‑binary network scanner with a tidy web UI and solid Go code organization, making it suitable for homelab or small‑office environments. However, the absence of automated tests and the need for CI hardening mean that any production‑grade adoption should be preceded by adding test coverage and tightening the CI pipeline.