Skip to content

dbkeys/vpsmc

Repository files navigation

vpsmc — VPS Master Control

A terminal dashboard for monitoring and managing a fleet of virtual private servers. Written in C++ with ncurses, it displays live stats (uptime, CPU load, memory, disk, pending updates, reboot status) fetched concurrently over SSH, with a sortable, scrollable server list and an interactive details pane.


Features

  • Live data over SSH — uptime, CPU load, memory, swap, disk usage (up to 3 devices per server), pending package updates, and reboot-required status are fetched in background threads and refresh automatically
  • Sortable list — press s to sort by any column (ID, nickname, IP, OS, cost, load, memory, disk, uptime, updates, reboot status, and more); toggle ascending/descending by pressing the same key again
  • Details pane — selecting a server shows a full breakdown in the lower third of the screen, including all disk devices with mount points
  • Edit in placeEnter opens an edit form for any server; a/+ adds a new one; d deletes with optional reason logging
  • Jump host support — each server can specify a jump host in servers.json for SSH tunneling
  • Local-machine aware — when vpsmc runs on one of the monitored servers, it detects this and fetches that server's data locally instead of looping through SSH
  • SSH key verificationcheck-ssh.sh cross-checks live host key fingerprints against the entries in servers.json and auto-adds verified keys to ~/.ssh/known_hosts
  • Rebooter utilityrebooter is a companion ncurses tool focused on the update/reboot cycle: it lists servers needing attention, checks for logged-in users, open files, and other pre-reboot conditions
  • Automatic JSON backups — every save archives the previous servers.json as servers.json.v1, .v2, etc.
  • 256-colour UI — zebra-striped rows, colour-coded disk usage (green / white / magenta / red by threshold), status indicators

Requirements

Dependency Purpose
g++ with C++17 Compilation
libncursesw + dev headers Terminal UI (-lncursesw)
libpthread Background SSH threads
jq Used by check-ssh.sh
ssh, ssh-keyscan, ssh-keygen Remote data fetching and key verification

On Debian/Ubuntu:

sudo apt install build-essential libncursesw5-dev jq

Build & Install

git clone https://github.com/yourname/vpsmc.git
cd vpsmc
make

To install binaries to /usr/local/bin/ and set up ~/vpsmc/ with example data:

make install

To build only a specific tool:

make vpsmc
make rebooter

Configuration

vpsmc looks for its configuration file in this order:

  1. ./vpsmc.conf.json (current directory)
  2. ~/vpsmc/vpsmc.conf.json

The bundled vpsmc.conf.json uses relative paths (./servers.json, ./logs/). There is no servers.json in the repo — on first run the built-in wizard prompts you to import servers from ~/.ssh/config or add them manually.

make install copies the conf to ~/vpsmc/vpsmc.conf.json (rewriting paths to ~/vpsmc/) and installs the binaries to /usr/local/bin/. After that, servers.json lives in ~/vpsmc/ and is never tracked by git.

The installed conf looks like:

{
  "vpsmc_config": {
    "paths": {
      "servers_json":        "~/vpsmc/servers.json",
      "log_directory":       "~/vpsmc/logs/",
      "exchange_rates_json": "~/vpsmc/xch-rates.USD.json"
    },
    "settings": {
      "default_base_currency":       "USD",
      "ssh_connect_timeout_seconds": 10
    }
  }
}

servers.json

Each server is an entry in the vpsmc.machines array. The SSH nick must match an alias in your ~/.ssh/config so that ssh nick works without a password prompt.

{
  "vpsmc": {
    "machines": [
      {
        "id":             1,
        "nick":           "web1",
        "canonical_name": "web1.example.com",
        "network":        { "ipv4": "192.0.2.1", "ipv6": "" },
        "ISP":            "Linode",
        "ISP_code":       "LN",
        "monthly_cost_cents": 1000,
        "cost_currency":  "USD",
        "purpose":        "Web, Frontend",
        "jump_host":      "",
        "os":             { "name": "Ubuntu", "version": "24.04" },
        "specs": {
          "cpu_cores":          2,
          "memory_gb":          3.814,
          "swap_gb":            0.0,
          "disk_used_percent":  34.0,
          "disk1_device":       "/dev/sda",
          "disk1_mount":        "/",
          "disk2_used_percent": -1.0,
          "disk2_device":       "",
          "disk2_mount":        "",
          "disk3_used_percent": -1.0,
          "disk3_device":       "",
          "disk3_mount":        ""
        },
        "public_keys": [
          { "type": "RSA",     "MD5": "aa:bb:...", "SHA-256": "base64==" },
          { "type": "ECDSA",   "MD5": "11:22:...", "SHA-256": "base64==" },
          { "type": "ED25519", "MD5": "99:88:...", "SHA-256": "base64==" }
        ],
        "reboot_required": false,
        "updates":  { "count": 0, "status": "none" },
        "flags":    { "c4": false, "o2": false, "s3": false },
        "tags":     [],
        "status":   "unknown",
        "last_checked": ""
      }
    ]
  }
}

See servers.json.example in the repo root for a complete worked example. Use check-ssh.sh to obtain and verify fingerprints for new servers before adding them.


SSH Setup

Each nick in servers.json must have a corresponding entry in ~/.ssh/config:

Host web1
    HostName        web1.example.com
    User            root
    IdentityFile    ~/.ssh/id_ed25519
    Port            22

For servers accessed via a jump host, set jump_host in servers.json to the nick of the bastion and add the appropriate ProxyJump or ProxyCommand to ~/.ssh/config.

Run check-ssh.sh to verify connectivity and fingerprints for all servers in one pass:

./check-ssh.sh

Key Bindings

vpsmc

Key Action
j / Move selection down
k / Move selection up
Enter Edit selected server
a / + Add new server
d / Del Delete selected server (with confirmation)
s Open sort key selector
r Re-fetch live data for selected server
R Re-fetch live data for all servers
q Quit

rebooter

Key Action
j / / k / Navigate server list
Tab Cycle detail view (users, open files, locks, ...)
u / a Filter: updates-only / all
r Re-check selected server
R Re-check all servers
q Quit

Project Layout

vpsmc/
├── vpsmc.cpp          # Main dashboard (ncurses TUI)
├── vpsmc_lib.cpp      # Shared library: JSON I/O, SSH fetchers, config
├── vpsmc_lib.h        # Shared library header
├── rebooter.cpp       # Reboot/update management companion tool
├── Makefile
├── check-ssh.sh       # SSH connectivity and fingerprint verifier
├── servers.json.example  # Example fleet structure (reference only)
├── servers.json       # Your server fleet — created by wizard, never committed
├── vpsmc.conf.json    # Application configuration
└── nlohmann/
    └── json.hpp       # JSON library (header-only, bundled)

Notes

  • 256-colour terminal required. Set TERM=xterm-256color if your terminal does not do this automatically.
  • Wide character support required. The build links against libncursesw (the wide-character variant of ncurses) for proper Unicode rendering.
  • Static data (specs, cost, OS) is read from servers.json at startup. Live data (uptime, CPU load, disk, updates) is fetched over SSH each time the tool starts or when r/R is pressed.
  • The exchange_rates_json path in the config is optional; it is used by the separate xch-normalizer utility (not included here) to normalise costs across currencies.

About

Virtual Private Server Master Control

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages