BTC: bc1q24qhjfhyudqkldn5lc9vemgpfv9hesanvcw70d
A self-hosted homelab monitoring system for tracking GPU metrics, system resources, Docker containers, and LLM instances across multiple machines in real-time.
- GPU Monitoring: VRAM usage, temperature, utilization, power draw, and fan speed via nvidia-smi or pynvml
- System Metrics: CPU, RAM, disk usage, and uptime across all monitored machines
- Per-Process Tracking: Detailed GPU memory mapping at the process level
- Docker Support: Real-time container health monitoring with CPU %, memory, restart counts, and status
- LLM Instance Monitoring: Track llama.cpp and Ollama instances with idle/generating status, live token/s throughput, KV cache usage, and slot tracking
- Generation History: Detailed per-request metrics including exact token/s speed, token counts, and duration
- Over-The-Air Updates: Agents auto-update from the dashboard
- Multi-Machine Support: Monitor unlimited machines with unique IDs and real-time WebSocket synchronization
- Interactive Installer: Guided CLI installer with auto-discovery of backend and local LLM/STT services
- Zero Build Step Dashboard: Single-file React SPA with in-browser Babel compilation — no build process needed
- Quick Start
- Architecture
- Installation
- Configuration
- LLM Monitoring
- API Endpoints
- Dashboard
- Troubleshooting
- Contributing
- License
docker compose up -dBackend will be available at http://localhost:9090
Once the backend is running, set up an agent on each machine you want to monitor:
Linux:
curl http://<backend-ip>:9090/api/download-agent -o agent.zip
unzip agent.zip -d ocm-agent && cd ocm-agent
pip install -r requirements.txt
python3 install.pyWindows (PowerShell):
Invoke-WebRequest http://<backend-ip>:9090/api/download-agent -OutFile agent.zip
Expand-Archive agent.zip -DestinationPath ocm-agent; cd ocm-agent
pip install -r requirements.txt
python install.pyThe installer auto-discovers the backend on your LAN, scans for running LLM/STT services, and configures everything interactively.
Dohtar Monitor follows a distributed agent-based architecture with a centralized backend:
┌─────────────────────────────────────────────────────────────┐
│ Dashboard (React SPA) │
│ Single HTML file, Babel in-browser │
│ Real-time updates via WebSocket connection │
└──────────────────────┬──────────────────────────────────────┘
│ HTTP/WebSocket (:9090)
┌──────────────────────▼──────────────────────────────────────┐
│ Backend (Express.js + SQLite) │
│ │
│ • API endpoints for metric ingestion and querying │
│ • WebSocket server for real-time dashboard updates │
│ • OTA update queue management │
│ • Metrics storage (SQLite with better-sqlite3) │
│ • UDP discovery listener (:9091) │
└──────────────────────┬──────────────────────────────────────┘
│ REST API (POST /api/ingest)
┌──────────────┼──────────────┐
│ │ │
┌───────▼──────┐ ┌────▼──────┐ ┌────▼──────┐
│ Agent 1 │ │ Agent 2 │ │ Agent N │
│ (Linux) │ │ (Windows)│ │ (Linux) │
│ │ │ │ │ │
│ • Metrics │ │ • Metrics │ │ • Metrics │
│ collection │ │ collect │ │ collect │
│ • GPU stats │ │ • GPU │ │ • GPU │
│ • Docker mon │ │ stats │ │ stats │
│ • LLM track │ │ • Docker │ │ • LLM │
└──────────────┘ │ mon │ │ track │
│ • LLM │ │ │
│ track │ └───────────┘
└───────────┘
Every 2 seconds: Agent → Backend (metrics POST)
Continuous: Backend → Dashboard (WebSocket push)
- Node.js 18 or higher
- Docker and Docker Compose (recommended) or local SQLite3
- Clone the repository:
git clone https://github.com/Dohtar1337/dohtar-monitor.git
cd dohtar-monitor- Build and run:
docker compose up -dThe included docker-compose.yml exposes port 9090 (HTTP/WebSocket/API) and port 9091/udp (agent auto-discovery).
- Verify the backend is running:
curl http://localhost:9090/- Install dependencies (from the
backend/directory):
cd backend
npm install- Start the backend:
npm startThe backend will listen on port 9090 by default.
No need to clone the repo on agent machines — the backend serves the agent files directly.
- Python 3.10 or higher
- pip package manager
Linux:
curl http://<backend-ip>:9090/api/download-agent -o agent.zip
unzip agent.zip -d ocm-agent && cd ocm-agent
pip install -r requirements.txtWindows (PowerShell):
Invoke-WebRequest http://<backend-ip>:9090/api/download-agent -OutFile agent.zip
Expand-Archive agent.zip -DestinationPath ocm-agent; cd ocm-agent
pip install -r requirements.txtNote: On newer Linux distributions (Debian 12+, Ubuntu 23.04+), you may need to add
--break-system-packagesto the pip command, or use a virtual environment.
Or just open http://<backend-ip>:9090/api/download-agent in your browser to download the zip file.
python install.pyThe installer will walk you through:
- Finding or entering your backend URL (auto-discovers via UDP broadcast)
- Setting a machine name and agent ID
- Choosing an install location
- Selecting which metrics to collect (system, GPU, processes, disk, Docker)
- Auto-scanning for local LLM/STT services on well-known ports
- Setting the polling interval
- Optionally installing a system service (systemd on Linux, Task Scheduler on Windows, launchd on macOS)
To reconfigure an existing installation: python install.py configure
To uninstall: python install.py uninstall
If you prefer to configure manually instead of using the installer:
cp config.example.json config.json
# Edit config.json with your settings (see Configuration section below)
python agent.py --config config.jsonAdd --debug for verbose logging output.
The installer can do this automatically, but if you prefer manual setup:
- Create a systemd unit file at
/etc/systemd/system/ocm-agent.service:
[Unit]
Description=Dohtar Monitor Agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/ocm-agent
ExecStart=/usr/bin/python3 /opt/ocm-agent/agent.py --config /opt/ocm-agent/config.json
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target- Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable ocm-agent
sudo systemctl start ocm-agent- Check status:
sudo systemctl status ocm-agent
sudo journalctl -u ocm-agent -fCreate a config.json file in the agent directory. The easiest way is to copy and edit config.example.json.
| Key | Type | Required | Example | Description |
|---|---|---|---|---|
agent_id |
string | Yes | "ocm-7a3f2b1e9c04" |
Unique identifier for this agent. Auto-generated by the installer. |
machine_name |
string | Yes | "GPU Workstation" |
Human-readable display name shown in the dashboard. |
backend_url |
string | Yes | "http://192.168.1.100:9090" |
Full URL to the Dohtar backend. Include protocol and port. |
install_path |
string | No | "/opt/ocm-agent" |
Directory where the agent is installed. Used by the updater. |
poll_interval |
integer | No (default: 2) | 2 |
Seconds between metric collection and submission to backend. |
collectors |
object | No | { ... } |
Which metric collectors to enable. See below. |
services |
array | No | [ { ... } ] |
Array of LLM/STT services to monitor. See LLM Monitoring section. |
| Key | Type | Default | Description |
|---|---|---|---|
system |
boolean | true |
CPU, RAM, uptime metrics |
gpu |
boolean | true |
GPU metrics via nvidia-smi/pynvml (auto-detects all GPUs) |
processes |
boolean | true |
Top processes and per-process GPU usage |
disk |
boolean | true |
Disk usage metrics |
docker |
boolean | false |
Docker container stats (requires Docker access) |
{
"agent_id": "ocm-7a3f2b1e9c04",
"machine_name": "Main Inference Box",
"backend_url": "http://192.168.1.50:9090",
"install_path": "/opt/ocm-agent",
"poll_interval": 2,
"collectors": {
"system": true,
"gpu": true,
"processes": true,
"disk": true,
"docker": false
},
"services": [
{
"type": "llm",
"name": "llama.cpp",
"endpoint": "localhost:8081",
"probe": "llamacpp"
},
{
"type": "llm",
"name": "Ollama",
"endpoint": "localhost:11434",
"probe": "ollama"
}
]
}Important: The
endpointfield should behost:portwithout thehttp://prefix — the agent adds it automatically.
Dohtar Monitor tracks llama.cpp and Ollama instances in real-time, providing visibility into inference workloads, KV cache usage, and throughput metrics.
To enable full LLM monitoring with generation history, start your llama.cpp instance with the --metrics and --slots flags:
llama-server -m model.gguf --metrics --slots -ngl 35 -c 2048Important flags:
--metrics: Enables the Prometheus metrics endpoint (required for live speed display and generation history)--slots: Enables KV cache slot tracking (required for accurate cache monitoring)
The dashboard displays:
- Status: Current state (idle, generating, or error)
- Live Token/s: Real-time inference speed during generation
- KV Cache: Current usage and total capacity
- Slot Count: Number of concurrent generation slots and their usage
- Generations History: Table with per-request metrics including token count, tokens/second speed, duration, and timestamp
In your config.json, add each llama.cpp instance under the services array:
"services": [
{
"type": "llm",
"name": "My LLM",
"endpoint": "localhost:8081",
"probe": "llamacpp"
}
]name: Display name in the dashboardendpoint: Host and port without protocol (e.g.,localhost:8081)type:"llm"for language models,"stt"for speech-to-textprobe:"llamacpp"for llama.cpp,"ollama"for Ollama,"whisper"for Whisper STT
POST /api/ingest
Agents send metrics to this endpoint every poll interval (default 2 seconds).
Request body:
{
"agent_id": "ocm-7a3f2b1e9c04",
"machine_name": "GPU Workstation",
"agent_version": "2.5.2",
"ts": 1710432000000,
"client_ip": "192.168.1.50",
"system": { ... },
"gpus": [ ... ],
"processes": [ ... ],
"containers": [ ... ],
"services": [ ... ]
}Response includes any pending commands (e.g., OTA update triggers).
GET /api/latest
Retrieve the latest metrics snapshot for all agents (also broadcast via WebSocket).
GET /api/history/llm/:endpoint/runs
Retrieve recent generation runs for a specific LLM endpoint.
Parameters:
:endpoint: URL-encoded endpoint (e.g.,localhost%3A8081)?limit=100(optional): Number of recent runs to return
Response:
[
{
"ts": 1710432000000,
"endpoint": "localhost:8081",
"model": "model-name",
"tok_generated": 256,
"tok_prompt": 45,
"speed_gen": 31.2,
"speed_pp": 120.5,
"t_generation_ms": 8205.1,
"t_prompt_ms": 373.4,
"t_total_ms": 8578.5
}
]POST /api/agent-update
Queue an OTA update for a specific agent. The update command is delivered in the next ingest response.
Request body:
{
"agent_id": "ocm-7a3f2b1e9c04"
}GET /api/download-agent
Download the agent zip file for manual installation or OTA updates.
GET /api/agent-version
Returns the latest agent version available on the backend.
The Dohtar Monitor dashboard is a single-file React application served by the backend. No build process is required — Babel compiles JSX in the browser.
- Real-time Updates: WebSocket connection delivers metrics instantly as they arrive from agents
- Multi-Machine View: All agents displayed in a unified interface with individual machine tabs
- GPU Metrics: Live VRAM, temperature, utilization, power draw, and per-process breakdowns
- System Overview: CPU, RAM, disk, and uptime at a glance
- Container Monitoring: Docker container health and resource usage
- LLM Insights: Real-time inference speed, KV cache usage, and generation history
- Agent Management: Trigger OTA updates from the dashboard
Open your browser and navigate to:
http://<backend-ip>:9090
Symptom: Agent logs show connection errors or timeouts.
Solutions:
- Verify the
backend_urlinconfig.jsonis correct and reachable:curl http://<backend-ip>:9090/api/latest
- Check firewall rules allow outbound connections to port 9090
- Ensure the backend is running:
docker ps # if using Docker - Try using the backend machine's IP instead of localhost
Symptom: CPU and RAM show, but GPU metrics are missing.
Solutions:
- Ensure
gpuis enabled in thecollectorssection ofconfig.json - Ensure
nvidia-smiis available on the system (the agent uses it for GPU detection) - If using WSL2, verify GPU passthrough is configured correctly
- Check agent logs for GPU initialization errors (run with
--debugflag)
Symptom: LLM services show as offline or unreachable.
Solutions:
- Verify llama.cpp is started with
--metricsand--slotsflags - Test the health endpoint manually:
curl http://localhost:8081/health
- Check the
endpointinconfig.jsonishost:portformat withouthttp://prefix - Ensure the endpoint is reachable from the agent machine (not just localhost)
- Check agent logs for HTTP errors when connecting to the endpoint
Symptom: No Docker containers appear in the dashboard.
Solutions:
- Ensure
dockeris set totruein thecollectorssection ofconfig.json(it defaults tofalse) - Verify Docker is installed and running
- Check that the agent process has permission to access the Docker socket (Linux):
sudo usermod -aG docker $USER # Then log out and back in
- On Windows, ensure Docker Desktop is running
Symptom: Real-time updates stop, dashboard becomes stale.
Solutions:
- Check network connectivity between client and backend
- Verify firewall rules allow WebSocket connections (port 9090)
- Restart the backend service
- Check backend logs for connection errors
Symptom: The Python agent process consumes significant CPU.
Solutions:
- Increase the
poll_intervalinconfig.json(default is 2 seconds) - Disable collectors you don't need in the
collectorssection - Remove unused services from the
servicesarray - Check if GPU metrics collection is stalling (verify
nvidia-smiperformance)
Contributions are welcome! Please feel free to open issues for bugs, feature requests, or documentation improvements.
- Clone the repository
- Install backend dependencies:
cd backend && npm install - Install agent dependencies:
cd agent && pip install -r requirements.txt - Start the backend locally and agents on test machines
- Make your changes and test thoroughly
- Submit a pull request with a clear description of your changes
Dohtar Monitor is licensed under the MIT License. See the LICENSE file for details.
Current Agent Version: 2.5.2
For support, issues, or questions, please open an issue on the GitHub repository.
