Skip to content

Repository files navigation

NodeWatcher

NodeWatcher is a lightweight, self-hosted VPS monitoring dashboard for Node.js 22+ with SQLite persistence. The repository folder is still named node-monitor, but the product is documented here as NodeWatcher.

It accepts HTTP reports from agents, stores metrics in SQLite, and renders a server-rendered dashboard with no frontend build step. The UI is a plain HTML template string styled with Tailwind via CDN and charts via Chart.js.

Features

  • Lightweight monitoring dashboard for VPS or other Linux/Unix hosts
  • Agent reporting endpoint for collecting CPU, memory, disk, network, and Docker metrics
  • SQLite-backed persistence for the Express target and D1-backed persistence for the Cloudflare Worker target
  • In-memory live cache over SQLite for fast dashboard reads and low-latency updates
  • Search, sorting, and filtering in the server table, plus a detail modal with charts
  • Auto-refresh polling and copy-to-clipboard helpers for the agent endpoint and token
  • Default password seed plus a forced password change on first login
  • Auto-generated agent token stored in the database and refreshable from the dashboard

Screenshots

Screenshots can be added here in the future.

Architecture

flowchart LR
    A[Agent: Go or Node.js] -->|POST /api/report| B[Express API or Hono Worker]
    B --> C[(SQLite / D1)]
    C --> D[In-memory server cache]
    D --> E[Browser dashboard UI]
Loading

The live server list is held in an in-memory Map in the Express implementation. That cache is rebuilt from SQLite at startup and then updated as new reports arrive. SQLite remains the source of truth for persistence, history, and retention jobs.

Requirements

  • Node.js 22+ is required because the server uses the built-in node:sqlite module.
  • The startup scripts run with node --experimental-sqlite.
  • Docker is optional but supported.
  • A Cloudflare account is only needed if you want to deploy the Worker/D1 target.

Quick start

git clone <repository-url>
cd node-monitor
npm install
npm start

Then open http://localhost:3000.

Default login credentials:

  • Username: not used; the UI uses a password-only login flow
  • Password: 123456

On first login, the app forces a password change. After that, use the newly chosen password.

The dashboard shows an auto-generated agent token. Copy it and point an agent at the dashboard endpoint.

Configuration

The Express target reads configuration from src/config.js.

Setting Default Source Notes
PORT 3000 Environment variable PORT Env-configurable.
MONITOR_PORT 3000 docker-compose host port mapping Compose-only variable used to map the host port to container port 3000; the Node.js app does not read it.
DB_PATH data/monitor.db Environment variable DB_PATH Env-configurable.
MAX_HISTORY 100 Code constant In-memory history buffer size.
OFFLINE_TIMEOUT_MS 30000 Code constant Marks a server offline after 30 seconds without an update.
SWEEP_INTERVAL_MS 5000 Code constant Sweep interval for offline detection.
RAW_RETENTION_MS 48 hours Code constant Raw samples are retained for 48 hours.
ROLLUP_RETENTION_MS 90 days Code constant Hourly rollups are retained for 90 days.
ROLLUP_INTERVAL_MS 600000 Code constant Maintenance and rollup interval, 10 minutes.

Deployment

1. Node.js directly

Run the app directly on a VPS or local machine:

npm install
npm start

The server listens on the configured PORT and writes its SQLite database to DB_PATH. The default database file is data/monitor.db.

2. Docker and docker compose

The repository includes a Dockerfile and docker-compose.yml for containerized deployment.

docker compose up -d

The compose file defines a monitor service and an agent service. The dashboard container exposes port 3000 by default, and the volume monitor-data persists the database at /app/data. The compose file maps the host port from MONITOR_PORT (default 3000) to container port 3000. The application inside the container always runs with PORT=3000; only TOKEN is passed through to the app as an environment variable. The agent service uses the same TOKEN value so the dashboard and agents can authenticate together.

3. Cloudflare Workers

The Worker implementation uses Hono and D1, which is SQLite-compatible. Follow the steps in DEPLOY-CLOUDFLARE.md for the Workers deployment path.

Agents

NodeWatcher ships with two agent options:

  • The Go agent in agent/README.md is the recommended companion project and is maintained separately from the dashboard.
  • The example Node.js agent is agent.js. It uses systeminformation and must be installed manually because it is not declared in package.json dependencies. Install it with:
npm install systeminformation

The example agent reads DASHBOARD_URL, TOKEN, and HOSTNAME from the environment.

API reference

Method Path Auth requirement Description
POST /api/report Token in JSON body Accepts agent metrics and creates or updates a server record.
GET /api/servers None in the current Express code Returns all known servers as JSON.
GET /api/server/:hostname None in the current Express code Returns one server by hostname.
DELETE /api/server/:hostname None in the current Express code Deletes a server and its history from memory and SQLite.
GET /api/server/:hostname/history None in the current Express code Returns history points for a server. Valid ranges are today, 24h, 7d, 30d, and 60d. Invalid ranges return 400; unknown hosts return 404.
GET /api/stats None in the current Express code Returns aggregate counts and averages across all servers.
GET /api/health None Basic health endpoint.
GET /api/token Session auth Returns the current agent token for the signed-in dashboard user.
POST /api/token/refresh Session auth Rotates the agent token and invalidates all existing agents.
GET / Session auth Dashboard page.
GET / POST /login None Login page and login action.
GET / POST /change-password Session auth plus forced password-change state Page and handler for changing the password.
POST /logout None Destroys the current session cookie.

Example report payload:

{
  "token": "hex-token",
  "hostname": "web-01",
  "os": "Linux 6.8.0",
  "platform": "linux",
  "uptime": 123456,
  "cpu": {
    "name": "x86_64",
    "usage": 38.2
  },
  "memory": {
    "used": 2048,
    "total": 8192,
    "percent": 25
  },
  "disk": {
    "used": 120,
    "total": 500,
    "percent": 24
  },
  "network": {
    "rx": 1024000,
    "tx": 2048000
  },
  "docker": {
    "containers": 4,
    "running": 3
  }
}

Validation rules for report payloads:

  • hostname is required and must be a non-empty string.
  • uptime must be a number when present.
  • cpu.usage must be a number when present.
  • memory.percent must be a number when present.
  • disk.percent must be a number when present.

Data retention

NodeWatcher keeps raw samples for 48 hours and rolls them into hourly buckets for 90 days. The maintenance job runs at startup and every 10 minutes in the Express target.

The history endpoint uses different data sources depending on the range:

  • today and 24h read raw history from the history table.
  • 7d, 30d, and 60d read the hourly rollup from history_hourly.

The API down-samples history to a maximum of 500 points when a range is very large.

Security

  • The Express middleware enables a Content Security Policy with default-src 'self', script-src including self and the CDN assets, and script-src-attr 'none'. Inline event handlers are intentionally blocked.
  • Global rate limiting is 300 requests per minute, dashboard requests are limited to 120 per minute, and login attempts are limited to 10 per minute.
  • Agent token validation uses timing-safe comparison.
  • The default password is 123456 and is seeded on first run, but the app forces a password change on the first login.
  • Dashboard sessions are stored in memory in the Express target, use the nm_session cookie, are HttpOnly, SameSite=Lax, and expire after 24 hours. In production they are marked Secure.

Important limitations:

  • In the current Express implementation, /api/servers, /api/server/:hostname, DELETE /api/server/:hostname, /api/stats, and the history endpoint are not protected by session authentication.
  • Sessions are in-memory, so all users are logged out when the Express process restarts.
  • For production exposure, run NodeWatcher behind HTTPS and a reverse proxy or another authentication layer.

Project structure

.
├── index.js                  # Starts the Express server and maintenance loop
├── package.json              # npm scripts and runtime dependencies
├── src/                      # Application code
│   ├── app.js                # Creates the Express app
│   ├── auth.js               # Password hashing, sessions, and cookies
│   ├── config.js             # Runtime configuration defaults
│   ├── database.js           # SQLite schema, maintenance, and access helpers
│   ├── middleware.js         # Security middleware and rate limits
│   ├── store.js              # In-memory server cache and report processing
│   ├── routes/               # API, auth, and dashboard routes
│   └── views/                # Server-rendered dashboard and auth templates
├── worker/                   # Cloudflare Worker implementation and routes
├── migrations/               # D1 schema migration for the Worker target
├── agent.js                  # Example Node.js agent
├── agent/                    # Go agent companion project
├── Dockerfile                # Container build for the Express target
├── docker-compose.yml        # Container orchestration example
└── DEPLOY-CLOUDFLARE.md      # Cloudflare Worker deployment guide

npm scripts

Script What it does
npm start Starts the Express app with node --experimental-sqlite.
npm run dev Alias for the development/start command.
npm run agent Starts the example Node.js agent with node --experimental-sqlite.
npm run tunnel Starts a Cloudflared tunnel to the local dashboard.
npm run cf:dev Starts the Cloudflare Worker locally with Wrangler.
npm run cf:deploy Deploys the Worker with Wrangler.
npm run cf:migrate Applies D1 migrations to the remote database.
npm run cf:migrate:local Applies D1 migrations to the local database.

Troubleshooting

Problem What to try
ERR_UNKNOWN_BUILTIN_MODULE: node:sqlite Use Node.js 22+; older versions do not support the built-in node:sqlite module.
Agents do not appear in the dashboard Check that the agent uses the correct dashboard URL and the current token. The token is generated automatically on first run and can be refreshed from the dashboard.
Servers stay offline The Express target marks a server offline after 30 seconds without a report. Check whether the agent is running and reachable.
7D/30D/60D charts are empty The hourly rollup only contains completed hours. A new range will appear only after some hourly buckets exist.
CSP errors in the browser console Inline event handlers are intentionally blocked by the CSP. Use the built-in UI behavior or adjust the deployment environment carefully if you change the CSP.

License

NodeWatcher is licensed under the MIT License. See LICENSE.md for the text.

The Go agent in agent/ is a separate companion project and is licensed separately under agent/LICENSE.md.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages