Lightweight, self-contained Linux® server monitoring tool.
🌏 Website | 👀 Demo | 🐋 Docker Hub
Zero dependencies. No external databases. Single binary. Just deploy and go.
Kula collects system metrics every second by reading directly from /proc and /sys,
stores them in a built-in tiered ring-buffer storage engine, and serves them through a real-time Web UI dashboard and a terminal TUI.
| Metric | What's Collected |
|---|---|
| CPU | Total usage (user, system, iowait, irq, softirq, steal) + core count |
| GPU | Load, Power consumption, VRAM |
| Load | 1 / 5 / 15 min averages, running & total tasks |
| Memory | Total, free, available, used, buffers, cached, shmem |
| Swap | Total, free, used |
| Network | Per-interface throughput (Mbps), packets/s, errors, drops; TCP errors/s, resets/s, established connections; socket counts |
| Disks | Per-device I/O (read/write bytes/s, reads/s, writes/s IOPS); filesystem usage |
| System | Uptime, entropy, clock sync, hostname, logged-in user count |
| Processes | Running, sleeping, blocked, zombie counts |
| Self | Kula's own CPU%, RSS memory, open file descriptors |
| Thermal | CPU, GPU and Disk temperatures |
Note: Monitoring NVIDIA GPUs might require additional setup. Check GPU monitoring.
┌──────────────────────────────────────────────┐
│ Linux Kernel │
│ /proc/stat /proc/meminfo /sys/... │
└──────────────────┬───────────────────────────┘
│ read every 1s
▼
┌──────────────────┐
│ Collectors │
│ (cpu, mem, net, │
│ disk, system) │
└────────┬─────────┘
│ Sample struct
┌────────────┼────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────┐ ┌──────────┐
│ Storage │ │ Web │ │ TUI │
│ Engine │ │ Server │ │ Terminal │
└─────┬──────┘ └───┬────┘ └──────────┘
│ │
┌──────────┼─────────┐ └───────────┐ HTTP + WebSocket
▼ ▼ ▼ ▼
┌─────────┬─────────┬─────────┐ ┌───────────────┐
│ Tier 1 │ Tier 2 │ Tier 3 │ │ Dashboard │
│ 1s │ 1m │ 5m │ │ (Browser) │
│ 250 MB │ 150 MB │ 50 MB │ └───────────────┘
└─────────┴─────────┴─────────┘
Ring-buffer binary files
with circular overwrites
Data is persisted in pre-allocated ring-buffer files per tier. Each tier file has a fixed maximum size — when it fills up, new data overwrites the oldest entries. This gives predictable, bounded disk usage with no cleanup needed.
- Tier 1 — Raw 1-second samples (default 250 MB)
- Tier 2 — 1-minute metrics aggregation (Avg/Min/Max) (default 150 MB)
- Tier 3 — 5-minute metrics aggregation (Avg/Min/Max) (default 50 MB)
The HTTP server on backend exposes a REST API and a WebSocket endpoint for live streaming. Authentication is optional - when enabled, it uses Argon2id hashing with salt and session cookies. It is worth adding that Kula truly respects your privacy. It works on closed networks and does not make any calls to external services.
The frontend is a single-page application embedded in the binary. Built on Chart.js with custom SVG gauges, it connects via WebSocket for live updates and falls back to history API for longer time ranges. Features include:
- Interactive zoom with drag-select (auto-pauses live stream)
- Focus mode to display only specific charts of interest
- Configurable Y-axis bounds (Manual limits or Auto-detect)
- Per-device selectors for Network, Disk I/O, and Thermal monitoring
- Grid / stacked list layout toggle
- Alert system for clock sync, low entropy, and system overload
- Modern aesthetics with light/dark theme support
Kula was built to have everything in one binary file. You can just upload it to your server and not worry about installing anything else because Kula has no dependencies. It just works out of the box! It is a great tool when you need to quickly start real-time monitoring.
Example installation methods for amd64 (x86_64) GNU/Linux.
Check Releases for ARM and RISC-V packages.
Note: Never thoughtlessly paste commands into the terminal. Even checking the checksum is no substitute for reviewing the code.
sh -c "$(curl -fsSL https://raw.githubusercontent.com/c0m4r/kula/refs/heads/main/addons/install.sh)"KULA_INSTALL=$(mktemp)
curl -o ${KULA_INSTALL} -fsSL https://kula.ovh/install
echo "c70f6f070a1f93e278f07f7efb7d662a48bc16f43909df7889d8778430dde1b6 ${KULA_INSTALL}" | sha256sum -c || rm -f ${KULA_INSTALL}
bash ${KULA_INSTALL}
rm -f ${KULA_INSTALL}wget https://github.com/c0m4r/kula/releases/download/0.10.0/kula-0.10.0-amd64.tar.gz
echo "b15df0dba80f74260e422c040b6ac3fcfc14bf51b772b12e35ecdc8fc3654b8a kula-0.10.0-amd64.tar.gz" | sha256sum -c || rm -f kula-0.10.0-amd64.tar.gz
tar -xvf kula-0.10.0-amd64.tar.gz
cd kula
./kulaTemporary, no persistent storage:
docker run --rm -it --name kula --pid host --network host -v /proc:/proc:ro c0m4r/kula:latestWith persistent storage:
docker run -d --name kula --pid host --network host -v /proc:/proc:ro -v kula_data:/app/data c0m4r/kula:latest
docker logs -f kulawget https://github.com/c0m4r/kula/releases/download/0.10.0/kula-0.10.0-amd64.deb
echo "4b274bb2a47a9fd57c97701267cf3e59b7b71825c553bbdb339ac16f7a789c95 kula-0.10.0-amd64.deb" | sha256sum -c || rm -f kula-0.10.0-amd64.deb
sudo dpkg -i kula-0.10.0-amd64.deb
journalctl -f -t kulawget https://github.com/c0m4r/kula/releases/download/0.10.0/kula-0.10.0-x86_64.rpm
echo "1f36cf5f5da39be6ab4a66ed43d0bd70c16fbaf99f687d59fbc0778371189c09 kula-0.10.0-x86_64.rpm" | sha256sum -c || rm -f kula-0.10.0-x86_64.rpm
sudo rpm -i kula-0.10.0-x86_64.rpm
journalctl -f -t kulawget https://github.com/c0m4r/kula/releases/download/0.10.0/kula-0.10.0-aur.tar.gz
echo "f05e1028117652367a936b97b674d9c6bc715840609ef0c793f746c76ffb0adf kula-0.10.0-aur.tar.gz" | sha256sum -c || rm -f kula-0.10.0-aur.tar.gz
tar -xvf kula-0.10.0-aur.tar.gz
cd kula-0.10.0-aur
makepkg -sigit clone https://github.com/c0m4r/kula.git
cd kula
bash addons/build.shStarting Kula is as simple as running:
./kulaDashbord will be available at: http://localhost:27960 (or :8080 if you're using earlier versions)
You can change default port and listen address in config.yaml or using environment variables:
export KULA_LISTEN="127.0.0.1"
export KULA_PORT="27960"
./kula./kula tui./kula inspect# Generate password hash
./kula hash-password
# Add the output to config.yaml under web.authInit system files are provided in addons/init/:
# systemd
sudo cp addons/init/systemd/kula.service /etc/systemd/system/
sudo systemctl enable --now kula
# OpenRC
sudo cp addons/init/openrc/kula /etc/init.d/
sudo rc-update add kula default
# runit
sudo cp -r addons/init/runit/kula /etc/sv/
sudo ln -s /etc/sv/kula /var/service/All settings live in config.yaml. See config.example.yaml for defaults.
# Lint + test suite
bash ./addons/check.sh
# Build dev (Binary size: ~14MB)
CGO_ENABLED=0 go build -o kula ./cmd/kula/
# Build prod (Binary size: ~9MB, xz: ~3MB)
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -buildvcs=false -o kula ./cmd/kula/To safely update only the Go modules used by Kula to their latest minor/patch versions, and prune any unused dependencies:
go get -u ./...
go mod tidy# Run unit tests with race detector
go test -race ./...
# Run the full storage benchmark suite (default: 3s per bench)
bash addons/benchmark.sh
# Shorter run for quick iteration
bash addons/benchmark.sh 500ms
# Python scripts formatter and linters
black addons/*.py
pylint addons/*.py
mypy --strict addons/*.pybash addons/build.sh cross # builds amd64, arm64, riscv64bash addons/build_deb.sh
ls -1 dist/kula-*.debbash addons/build_aur.sh
cd dist/aur && makepkg -sibash addons/build_rpm.sh
ls -1 dist/kula-*.rpmbash addons/docker/build.sh
docker compose -f addons/docker/docker-compose.yml up -dPrivacy is a core pillar, not an afterthought.
Kula is built for privacy-conscious infrastructure. It is a completely self-contained binary that requires no cloud connection and no third-party APIs. Designed to function perfectly in air-gapped networks, Kula never sends metadata to external servers, never serves advertisements, and requires no user registration. Your monitoring starts and ends on your infrastructure, exactly where it should be.
GNU Affero General Public License v3.0