Multiple scripts that monitor a home server and log state changes to a local SQLite database on a USB flash drive, with a small web dashboard for viewing status, history, and events.
Written to run on an old repurposed router with minimal dependencies.
Two independent components, both writing to the same SQLite database:
-
monitor.sh— runs every minute via cron. Performs two checks:- L3 (ICMP):
pingto verify the host is reachable on the network - L7 (TCP):
ncport check to verify the service is actually responding
A
/tmpstate file tracks whether the server was previously seen as down, so a transition is logged once when it goes offline and once when it comes back — not on every poll. - L3 (ICMP):
-
proxmox_monitor— a long-running daemon (started at boot viaprocd) that polls the Proxmox API everypoll_intervalseconds and detects:- Silent reboots — uptime decreasing between polls
- High temperature — CPU temp crossing
temp_threshold
Every poll from both components is logged to a readings table (for
the dashboard's history chart); state transitions and detected problems
are logged to an events table (for the dashboard's event log).
A CGI script (monitor-data) serves that data as JSON, and a static
dashboard page (index.html) renders it — both served by the router's
existing uhttpd, no extra web server needed.
- OpenWRT router with a free USB port
- USB flash drive (used for the SQLite database — keeps write cycles off the router's internal flash)
- Packages:
sqlite3-cli,block-mount,kmod-usb-storage,kmod-fs-ext4
This ships as a proper OpenWrt package (not a custom firmware image)
— build it against the OpenWrt SDK, install the resulting .ipk with
opkg, no reflashing required.
-
Drop this repo into an OpenWrt SDK's
package/directory and build:cp -r home-server-monitor <sdk>/package/home-server-monitor cd <sdk> make package/home-server-monitor/compile V=s
This produces
bin/packages/<arch>/base/home-server-monitor_1.0-1_<arch>.ipk. Dependencies (sqlite3-cli,block-mount,kmod-usb-storage,kmod-fs-ext4) are declared in the package and pulled in automatically. -
Copy the
.ipkto the router and install it:scp bin/packages/*/base/home-server-monitor_*.ipk root@<router-ip>:/tmp/ ssh root@<router-ip> opkg install /tmp/home-server-monitor_*.ipk
Installing the package automatically adds the cron entry for
monitor.shand enables theproxmox-monitorservice — no manual file copying or service setup needed. -
Format and mount the USB drive (first time only):
block info # find the device, e.g. /dev/sda1 mkfs.ext4 -L monitor /dev/sda1 # WARNING: erases the drive mkdir -p /mnt/usb block detect >> /etc/config/fstab uci set fstab.@mount[-1].target='/mnt/usb' uci set fstab.@mount[-1].enabled='1' uci commit fstab block mount
-
Edit
/etc/config/monitorwith your settings:config settings 'settings' option enabled '1' option target_ip '192.168.1.50' option target_port '8006' option proxmox_node 'pve' option api_token_id 'root@pam!monitor' option api_token_secret 'your-api-token-secret' option temp_threshold '80' option poll_interval '60' option db_path '/mnt/usb/monitor/monitor.db' -
If the USB drive wasn't mounted yet at install time, initialize the database manually (the package's postinst will remind you if so):
sqlite3 /mnt/usb/monitor/monitor.db < /usr/share/home-server-monitor/schema.sql -
Restart the daemon and cron to pick up your config:
/etc/init.d/proxmox-monitor restart /etc/init.d/cron restart
-
Open the dashboard at
http://<router-ip>/monitor/.
See docs/setup.md for the full step-by-step, including SSH access and
the SDK setup.
| Option | Description |
|---|---|
enabled |
Set to 1 to activate monitoring |
target_ip |
IP address of the server to monitor |
target_port |
TCP port for L7 service check (optional) |
proxmox_node |
Node name as configured in Proxmox (default pve) |
api_token_id |
Proxmox API token ID, e.g. root@pam!monitor |
api_token_secret |
Proxmox API token secret |
temp_threshold |
CPU temperature (°C) that triggers a temp_high event |
poll_interval |
Seconds between Proxmox API polls |
db_path |
Path to the SQLite database (on the USB drive) |
The database grows indefinitely by default. Add a weekly cron entry to prune old readings so the flash drive doesn't fill up:
sqlite3 /mnt/usb/monitor/monitor.db \
"DELETE FROM readings WHERE ts < strftime('%s','now','-90 days');"