svc.Run reports SERVICE_STOPPED as soon as the service handler returns. Existing installs only restart a process that dies without that report, so the handler now stays inside Execute until the process exits. Also drop Playwright session dumps that were committed with the previous update fix, and ignore that directory. Co-authored-by: Cursor <cursoragent@cursor.com>
Node Stats
Node Stats is an open-source, self-hosted system monitoring and infrastructure monitoring dashboard built with Go and React. Monitor your servers, Docker containers, and system resources in real-time with a beautiful, modern web interface. Perfect for DevOps engineers, system administrators, and developers who need comprehensive server monitoring, container monitoring, and infrastructure metrics visualization.
What is Node Stats?
Node Stats is a lightweight, self-hosted alternative to commercial monitoring solutions like Grafana, Prometheus, or Datadog. It provides real-time system metrics collection, Docker container monitoring, and a beautiful dashboard interface without the complexity of enterprise monitoring tools. Built with Go for performance and React for a modern user experience, Node Stats is ideal for monitoring single servers, development environments, or small infrastructure deployments.
Key Capabilities
- Server Monitoring: Real-time CPU, memory, disk, and network metrics
- Docker Monitoring: Container statistics, resource usage, and health monitoring
- System Metrics: Temperature sensors, system information, and hardware monitoring
- Self-Hosted: Complete control over your data with no external dependencies
- Lightweight: Minimal resource footprint compared to enterprise monitoring solutions
- Modern UI: Beautiful, customizable dashboard themes with real-time updates
Features
- Real-time Monitoring: Live CPU usage, memory usage, disk I/O, network traffic, and Docker container metrics
- Beautiful UI: Modern monitoring dashboard with multiple customizable themes (Neon Terminal, Glass Aurora, Cards Flow, Slate Pro)
- RESTful API: Clean REST API endpoints for all system metrics and Docker statistics
- Docker Support: Comprehensive Docker container monitoring with resource usage tracking
- Persistent Storage: SQLite database for historical metrics and data retention
- User Authentication: Secure login system with JWT tokens and refresh tokens
- Temperature Monitoring: Hardware temperature sensor monitoring for system health
- Multi-theme Support: Switch between different dashboard themes for personalized monitoring experience
Use Cases
Node Stats is perfect for:
- Development Teams: Monitor development servers and staging environments
- DevOps Engineers: Track infrastructure health and resource utilization
- System Administrators: Monitor server performance and system metrics
- Docker Users: Monitor containerized applications and Docker host resources
- Home Lab Enthusiasts: Self-hosted monitoring for personal servers and homelabs
- Small to Medium Infrastructure: Lightweight monitoring solution without enterprise complexity
- Privacy-Conscious Users: Self-hosted alternative to cloud-based monitoring services
Roadmap
- ✅ Real-time metrics monitoring (CPU, memory, disk, network, Docker containers, temperature sensors)
- ✅ Modern UI dashboard with multiple themes (Neon Terminal, Glass Aurora, Cards Flow, Slate Pro)
- ✅ RESTful API endpoints for all metrics
- ✅ User authentication (registration, login, refresh tokens, user management)
- ✅ SQLite database for historical metrics storage
- ✅ Application configuration via UI on first launch (setup wizard for initial configuration)
- ✅ Prometheus metrics export (
/api/v1/metrics, enabled viaPROMETHEUS_ENABLED=true) - ✅ Swagger UI for API documentation (
/swagger/) - ✅ PostgreSQL database support (alternative to SQLite via
DB_TYPE=postgres) - ✅ Health check endpoint (
/api/v1/health) for load balancers and Kubernetes probes - ✅ Live metrics stream via Server-Sent Events (
/api/v1/stream) - ✅ Configurable data retention (
METRICS_RETENTION_DAYSfor automatic cleanup of old metrics) - ✅ Hosts registration and management
- ✅ Admin/user roles
- ✅ Backend unit tests for service layer
- ✅ Multi-node statistics synchronization and aggregation (Raft consensus replication — nodes form a cluster via the setup wizard and replicate state across peers; see "Clustering (Raft)" below)
- ❌ Alert system (configurable notifications when metric thresholds are exceeded)
- ✅ Stack detection with aggregation into apps with icons and minimal stats
- ❌ Auto config for reverse proxy for apps routing
- 🚫 Application port tunneling (tunnel selected application ports from closed machines through the central node to local machine for fast, direct, and secure access) — declined; NetBird solves this better
- ✅ Container logs monitoring (real-time viewing and filtering of Docker container logs)
- ❌ Additional time-series databases support (integration with databases better suited for time-series data like InfluxDB, TimescaleDB)
Screenshots
UI collage (dark glass / neon and light themes). Click an image on GitHub to open the full-size PNG.
Installation & Quick Start
Pick the path that matches your machine. The database and configuration are not baked in ahead of time — you choose them in the setup wizard on first run, and the stack reconfigures itself automatically.
Linux — one-line install (Docker, recommended)
curl -fsSL https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/install.sh | bash
This detects your OS/arch, checks Docker + Compose, creates a stack dir
(~/.node-stats, or /opt/node-stats as root), pulls the image, sets the right
host capabilities (pid/ipc: host, /host mount) for accurate metrics, and
brings the stack up. Then open http://localhost:9090 to finish setup.
Manage it later:
curl -fsSL https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/install.sh | bash -s -- update # pull + recreate
curl -fsSL https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/install.sh | bash -s -- uninstall # stop (add --purge to wipe data)
No network? The stack lives in the dir above, so this is the same uninstall by hand:
cd /opt/node-stats && docker compose down --remove-orphans # stop, keep data (use ~/.node-stats if not root)
cd /opt/node-stats && docker compose down --remove-orphans -v && rm -rf /opt/node-stats # wipe data too
Overrides: NODE_STATS_DIR (stack dir), NODE_STATS_PORT (HTTP port),
NODE_STATS_IMAGE (pin a :vX.Y.Z tag).
Linux SBC / lean host — native install (no Docker, arm64 + amd64)
For Orange Pi, Raspberry Pi, or any Linux box where you'd rather not run Docker,
install the self-contained native binary (it reads /proc directly, so you get
real host metrics) as a systemd service:
curl -fsSL https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/install.sh | sudo bash -s -- native
Downloads the matching linux/{amd64,arm64} release binary (checksum-verified),
installs it to /usr/local/bin, and registers a node-stats systemd service
(data/config in /var/lib/node-stats). Open http://localhost:8080 to finish
setup. Manage with curl -fsSL https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/install.sh | sudo bash -s -- update-native (or uninstall-native). Pin a
version with NODE_STATS_VERSION=vX.Y.Z. (Without sudo/systemd it installs to
~/.local/bin and prints how to run it manually.)
Proxmox VE — one command on the host (LXC)
Spin up node-stats as a tiny Debian LXC, community-scripts.org style. Run this on the Proxmox VE host (the hypervisor, as root):
bash -c "$(curl -fsSL https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/proxmox-lxc.sh)"
It creates an unprivileged Debian 12 container, installs the native release
inside (systemd service), and prints http://<container-ip>:8080. Because it
runs on the PVE host, it also auto-attaches the Proxmox connector (mints a
read-only PVEAuditor token and wires it in) — so the hypervisor + every VM/LXC
show up automatically, no clicks. Disable with PROXMOX_AUTOCONNECT=0. Full
guide (options, day-2 commands, and how to get it listed on community-scripts.org):
docs/PROXMOX-LXC.md.
macOS / Windows — native binary (best host metrics)
Docker Desktop runs in a Linux VM, so its host metrics reflect the VM, not your machine. For true host metrics, download the native single binary from the latest release:
- macOS (Apple Silicon):
node-stats_<version>_darwin_arm64.tar.gz - Windows (x64):
node-stats_<version>_windows_amd64.zip - Linux (x64/arm64):
node-stats_<version>_linux_{amd64,arm64}.tar.gz
tar -xzf node-stats_*_darwin_arm64.tar.gz
./node-stats # serves http://localhost:8080
./node-stats update # self-update to the latest release
The binary is fully self-contained (frontend embedded, pure-Go SQLite — no CGO).
Windows — one-line install (Docker Desktop, PowerShell)
irm https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/install.ps1 | iex
Requires Docker Desktop. Same VM-metrics caveat as macOS. If your execution
policy blocks it, run from an elevated prompt with
powershell -ExecutionPolicy Bypass.
Synology NAS — Docker (Container Manager)
Synology runs node-stats as a Docker container. It works on x86 (Intel/AMD)
models (amd64) and 64-bit ARM models (arm64) — the image ships both; old
32-bit ARM models aren't supported. You need the Container Manager package
(DSM 7.2+) or the older Docker package (DSM 7.0–7.1).
Easiest — SSH + the installer. Enable SSH (Control Panel → Terminal & SNMP → Enable SSH service), connect, then run — pointing the stack at a folder on your volume so data persists across DSM updates:
sudo NODE_STATS_DIR=/volume1/docker/node-stats \
bash -c "$(curl -fsSL https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/install.sh)"
Open http://<nas-ip>:9090 to finish setup. sudo is required because the
Docker socket is root-owned. The container reads the DSM host's /proc and the
Docker socket (pid: host / /host mount), so the machine card shows the NAS's
real CPU/RAM/disk and its containers.
To install and join an existing cluster in one go, add the join env vars and
call agent-join.sh instead of install.sh:
sudo NODE_STATS_DIR=/volume1/docker/node-stats \
NODE_STATS_JOIN_URL="http://<leader-ip>:9090" \
NODE_STATS_JOIN_KEY="<one-shot token>" \
bash -c "$(curl -fsSL https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/agent-join.sh)"
The leader's admin panel (Admin → Nodes → Add a node) generates this exact command when you pick the Synology NAS platform — copy it, paste it over SSH, done.
Manual / Container Manager GUI route. Prefer the
advanced docker-compose flow below with the
stack dir set to /volume1/docker/node-stats. Keep .env.agent a file, not
a folder. The controller sidecar needs the project dir identity-mounted
(NODE_STATS_STACK_HOST_DIR=/volume1/docker/node-stats), which the SSH installer
sets for you — the GUI Project import doesn't, so SSH is the recommended path.
HTTPS. Use DSM's built-in reverse proxy (Control Panel → Login Portal →
Advanced → Reverse Proxy) pointed at localhost:9090, then set
COOKIE_SECURE=true in .env.agent and docker compose restart node-stats.
SSE works out of the box (see docs/REVERSE-PROXY.md).
Auto-updates
node-stats checks GitHub Releases and shows an "update available" badge to
admins. Toggle auto-update in settings: Docker deployments pull the new
image and recreate via the controller; native installs use node-stats update.
Release channel (stable / beta). Pick the update line in the admin update
popup — it applies to every install type and is remembered. stable follows
the latest full release; beta follows the bleeding edge (the rolling :beta
image on Docker, the newest prerelease release on native). To start a fresh
install on beta, pass NODE_STATS_CHANNEL=beta to any installer, e.g.:
NODE_STATS_CHANNEL=beta bash -c "$(curl -fsSL https://gitea.sky-apps.uk/LastSkywalker/node-page/raw/branch/main/scripts/install.sh)"
Advanced: manual docker-compose
The installer is just a convenience wrapper around docker compose. To run it
by hand, create a stack directory and let the image generate the base compose:
mkdir -p ~/.node-stats/data/docker && cd ~/.node-stats
: > .env.agent # MUST be a file (it is bind-mounted to /app/.env);
# a directory mount silently swallows the wizard's config
cat > .env <<'EOF'
NODE_STATS_IMAGE=gitea.sky-apps.uk/lastskywalker/node-page:latest
NODE_STATS_PORT=9090
NODE_STATS_STACK_HOST_DIR=__set_to_this_dir__
COMPOSE_PROJECT_NAME=node-stats
EOF
docker run --rm gitea.sky-apps.uk/lastskywalker/node-page:latest gen-compose > docker-compose.yml
printf 'services:\n node-stats:\n pid: host\n ipc: host\n' > docker-compose.override.yml # Linux only
docker compose up -d
JWT_SECRET/REFRESH_SECRET are generated by the setup wizard into
.env.agent — you do not set them by hand. The wizard also switches the
database (SQLite ↔ Postgres) and the controller sidecar regenerates this
docker-compose.yml and restarts the app for you.
Clustering (Raft)
Multiple Node Stats instances form a cluster using Raft consensus replication — there is no central "main" that other nodes push to. State is replicated across all peers.
How to join a cluster:
- On a running cluster node (the leader), generate a one-shot connect key.
- On a fresh node, open the setup wizard and choose "Join an existing cluster".
- Paste the connect key and the cluster node URL, then submit. The node posts to
POST /api/v1/setup/join-raft-cluster; the leader adds it as a voter and replicates state to it. The wizard shows progress while the leader catches the new node up.
The join handler writes the resolved RAFT_* values (node id, bind/advertise addresses, data dir, etc.) to the node's .env, so cluster membership survives restarts and image rebuilds. See docker-compose.cluster.yml for a ready-to-run two-node example and the full list of RAFT_* environment variables.
Local Development
Full Dev Run (Recommended)
The project uses Overmind with a Procfile to run backend and frontend in parallel. Backend uses Air for live reload; frontend uses Vite with proxy to the API.
Prerequisites:
- Overmind —
brew install overmind(macOS) or install from releases - Go, Node.js, Yarn
# Install backend dependencies
go mod download
# Install frontend dependencies
cd frontend && yarn install && cd ..
# Set required environment variables
export JWT_SECRET=your-jwt-secret-key
export REFRESH_SECRET=your-refresh-secret-key
# Optional: customize server address (default: :8080)
export ADDR=:8080
# Run backend + frontend together
./scripts/dev
- Backend (Air):
http://localhost:8080— live reload on Go file changes - Frontend (Vite):
http://localhost:5173— proxies/apiand/wsto backend
Backend Only (Go)
# Install dependencies
go mod download
# Set required environment variables
export JWT_SECRET=your-jwt-secret-key
export REFRESH_SECRET=your-refresh-secret-key
# Optional: customize server address (default: :8080)
export ADDR=:8080
# Run the server
go run cmd/server/main.go
Frontend Only (React + TypeScript)
cd frontend
yarn install
yarn dev
The frontend development server typically runs on http://localhost:5173 (Vite default port). It proxies API requests to http://localhost:8080.
API Documentation
Node Stats provides a comprehensive REST API for accessing all system metrics programmatically. All endpoints return JSON data and support real-time metrics retrieval.
System Metrics Endpoints
GET /api/cpu- CPU usage metrics including per-core statistics and load averagesGET /api/memory- Memory usage metrics including RAM, swap, and memory statisticsGET /api/disk- Disk usage metrics including I/O statistics and filesystem informationGET /api/network- Network statistics including interface traffic and connection dataGET /api/docker- Docker containers information including resource usage and container statusGET /api/system- System information including hostname, uptime, and platform detailsGET /api/sensors- Hardware temperature sensors and thermal monitoring data
Authentication Endpoints
POST /api/auth/register- User registrationPOST /api/auth/login- User authenticationPOST /api/auth/refresh- Refresh access tokenPOST /api/auth/logout- User logout
All API endpoints support CORS and can be integrated with external monitoring tools, automation scripts, or other applications.
Pulling Pre-built Images
# Pull from GitHub Container Registry
docker pull gitea.sky-apps.uk/lastskywalker/node-page:latest
# Run the container (default port 8080)
docker run -p 8080:8080 \
-e ADDR=:8080 \
-e JWT_SECRET=your-jwt-secret-key \
-e REFRESH_SECRET=your-refresh-secret-key \
-v ./stats.db:/app/stats.db \
gitea.sky-apps.uk/lastskywalker/node-page:latest
Configuration
Node Stats is configured via environment variables:
ADDR- Server address and port (default::8080)GIN_MODE- Gin framework mode:releaseordebug(default:release)JWT_SECRET- Secret key for JWT access tokens (required)REFRESH_SECRET- Secret key for JWT refresh tokens (required)DB_TYPE- Database type (default:sqlite)DB_DSN- Database connection string or file path. Local dev:stats.db; Docker:/app/stats.db(mounted from./data/docker/stats.db)DEBUG- Enable debug mode:trueorfalse(default:false)- Clustering (Raft):
RAFT_ENABLED,RAFT_CLUSTER_ID,RAFT_NODE_ID,RAFT_BIND_ADDR,RAFT_ADVERTISE_ADDR,RAFT_ADVERTISE_PUBLIC_URL,RAFT_DATA_DIR,RAFT_BOOTSTRAP— see "Clustering (Raft)" above anddocker-compose.cluster.yml. Usually set by the setup-wizard join flow. - Local metrics host id: This server always stores its own collected metrics under
hosts.id = 1. Rebuilds update that row (same DB file).
Architecture & Technology Stack
Node Stats is built using modern web technologies and follows Clean Architecture principles for maintainability and scalability.
Technology Stack
- Frontend: React 19 + TypeScript 5.9 + Tailwind CSS for a modern, responsive user interface
- Backend: Go (Golang) with Gin web framework for high-performance API server
- Database: SQLite (default) or PostgreSQL via GORM
- Monitoring: Real-time system metrics collection using native Go libraries
- Authentication: JWT-based authentication with refresh token support
- Containerization: Docker and Docker Compose for easy deployment
Architecture Principles
- Clean Architecture: Separation of concerns with domain, application, infrastructure, and presentation layers
- RESTful API Design: Standard REST endpoints for all system metrics
- Real-time Updates: Server-Sent Events (SSE) for real-time metric streaming
- Modular Design: Feature-based module structure for easy extensibility
Development
Project Structure
├── cmd/server/ # Application entry point
├── internal/
│ ├── app/ # Application configuration
│ └── modules/ # Feature modules (CPU, Memory, etc.)
├── frontend/ # React frontend
├── .github/workflows/ # CI/CD pipelines
└── Dockerfile # Container definition
Development
Building from Source
# Clone the repository
git clone https://github.com/yourusername/node-stats.git
cd node-stats
# One-command build (backend + frontend)
./scripts/build
Or build manually: go build -o bin/server ./cmd/server and cd frontend && yarn && yarn build.
Helper scripts (in scripts/): ./scripts/dev — run backend + frontend; ./scripts/build — build both; ./scripts/clean-db — remove SQLite DB (prompts for confirmation, reads DB_DSN from .env or uses stats.db).
Running Tests
# Backend tests
go test ./...
# Frontend tests
cd frontend
yarn test
Contributing
Contributions are welcome! Whether it's bug fixes, new features, or documentation improvements, your help makes Node Stats better.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Test thoroughly
- Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Related Projects & Alternatives
Node Stats is inspired by and can be used alongside:
- Grafana - Advanced visualization and alerting (Node Stats is lighter)
- Prometheus - Time-series database and monitoring (Node Stats uses SQLite)
- Netdata - Real-time performance monitoring (Node Stats focuses on simplicity)
- Portainer - Docker management UI (Node Stats adds system monitoring)
Keywords & Tags
Monitoring Tools: system monitoring, server monitoring, infrastructure monitoring, docker monitoring, container monitoring, system metrics, server metrics, real-time monitoring, self-hosted monitoring
Technologies: Go, Golang, React, TypeScript, Docker, SQLite, REST API, JWT authentication, Gin framework, Tailwind CSS
Use Cases: DevOps monitoring, server health monitoring, Docker container stats, system performance tracking, homelab monitoring, development server monitoring, infrastructure health checks
Features: CPU monitoring, memory monitoring, disk monitoring, network monitoring, temperature sensors, Docker stats, system information, real-time dashboard, monitoring dashboard
License
MIT License - see LICENSE file for details






