The Proxmox page only showed guest (VM/LXC) status; there was no view
of the underlying host(s) themselves -- uptime, CPU/RAM usage, or how
full each storage pool is.
New adapter.listNodeStats() calls GET /nodes/{node}/status and GET
/nodes/{node}/storage for every online node (a node going down
shouldn't blank the whole page, same tolerance as listGuests()) and
returns uptime, CPU usage % + core count + load average, RAM/swap
usage, and per-storage (local, LVM-thin, ZFS, NFS, ...) used/total.
New GET /:id/proxmox/nodes route alongside the existing /guests one.
One card per online node now sits above the VM/LXC table, showing
these stats plus a small storage table with usage bars (reusing the
same green/yellow/red thresholds as the Servers detail page and the
Synology page). Handles a multi-node cluster by rendering one card
per node, and storages with no active/total data (e.g. an offline NFS
mount) render as an "Inactive" badge with blank usage instead of
throwing.
Verified end-to-end against a local mock Proxmox API server over real
TLS (a throwaway self-signed cert, matching how the adapter's
`insecure` option is meant to be used) since this sandbox can't reach
the user's actual Proxmox cluster -- confirmed CPU fraction-to-percent
conversion, load average parsing, byte fields, and that a
null-valued/inactive storage doesn't break parsing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
136 lines
6.4 KiB
Markdown
136 lines
6.4 KiB
Markdown
# Homelab Manager
|
|
|
|
Repository: `git@10.200.5.13:bobban/Homelab-manager.git` ([gitea.labsconnect.se/bobban/Homelab-manager](https://gitea.labsconnect.se/bobban/Homelab-manager) externally).
|
|
|
|
A single dashboard for a homelab: Proxmox, Synology DSM, Semaphore, Tailscale,
|
|
Gitea, and Dockhand/Docker status and basic actions, plus DNS record
|
|
management, an IP address inventory (IPAM), and a secret-expiry tracker
|
|
(ported from [Sloth Manager](../Sloth%20manager)) and scheduled-task tracking
|
|
across Debian/Raspbian hosts (ported from
|
|
[Schedule Task Manager](../ScheduleTaskManager)). Looks and feels like a
|
|
[Tabler](https://tabler.io) admin dashboard. Sign-in is delegated to
|
|
Authentik (OIDC), with local admin/operator/viewer roles.
|
|
|
|
## Status
|
|
|
|
All modules from the original plan are built:
|
|
|
|
- Monorepo scaffold, Tabler-themed app shell/navigation
|
|
- Authentik OIDC login, roles (first user to sign in becomes admin), audit log
|
|
- **Secrets** — expiry tracking for API tokens/certs/passwords
|
|
- **IP Addresses (IPAM)** — inventory of IPs across vendors/locations,
|
|
with "Sync from Tailscale" and "Sync from Proxmox" actions to pull in
|
|
tailnet device IPs and VM/LXC IPs (never overwrites a
|
|
manually-entered IP), and each entry now shows its matching DNS
|
|
record(s) from the DNS module's cache
|
|
- **DNS** — zone/record management across Cloudflare, Loopia, Pi-hole, Azure
|
|
DNS, cPanel, and Technitium; providers are configured in-app (not via env
|
|
vars) and their credentials are encrypted at rest
|
|
- **Servers** — cron/systemd tracking across Debian/Raspbian servers via a
|
|
lightweight push agent (`agent/linux/`), plus manual entries for things an
|
|
agent can't see (Docker jobs, backups). The Servers page itself just lists
|
|
registered servers and (admin-only) adds new ones / issues agent tokens;
|
|
clicking a server opens its detail page with CPU/RAM/disk status, IP
|
|
addresses, matching DNS names (looked up from the DNS module's cache), and
|
|
its scheduled tasks — live hardware from Proxmox for VM/LXC-backed
|
|
servers, or from the agent's own hardware report for everything else.
|
|
Proxmox-linked servers also get start/stop/restart buttons right on the
|
|
detail page.
|
|
- **Tailscale**, **Proxmox**, **Synology**, **Semaphore**, **Gitea**,
|
|
and **Docker** each get their own top-level page (backed by the
|
|
matching integration) instead of living inside a shared Integrations
|
|
browsing view:
|
|
- **Tailscale** — device list with online/authorized status, and
|
|
authorize/deauthorize/remove actions; a live device-count widget.
|
|
- **Proxmox** — VM/LXC status across every node in the cluster, with
|
|
start/restart/shutdown/stop actions; a live running/total widget. Each
|
|
online node also gets its own host-stats card — uptime, CPU usage/cores/
|
|
load average, RAM and swap usage, and per-storage usage (local, LVM-thin,
|
|
ZFS, NFS, etc). Supports self-signed certificates (common in homelab
|
|
setups).
|
|
- **Synology** — volume and disk health (read-only by design).
|
|
Supports self-signed certificates.
|
|
- **Semaphore** — Ansible run status per template across every
|
|
project, with a "Run" action to trigger a template; a live
|
|
template-count widget (with a last-failed warning).
|
|
- **Gitea** — repo list with each repo's last CI run status, and
|
|
re-running just the failed jobs in a run; a live repo-count widget
|
|
(with a failing-build warning).
|
|
- **Docker** — container status across every Docker host Dockhand
|
|
manages (one credential covers all of them), with
|
|
start/stop/restart actions, a host filter, and a live
|
|
running/total widget.
|
|
|
|
Add/edit/enable/disable/remove each integration's credential itself
|
|
under Integrations → Manage integrations.
|
|
- **Settings** (admin-only) — notification channels (Gotify, ntfy, SMTP,
|
|
generic webhook) with per-channel test buttons, per-event toggles (DNS
|
|
record added/updated/deleted, daily secret-expiry reminder and daily
|
|
Tailscale key-expiry reminder — both sharing one configurable
|
|
time/timezone), badge-color customization for both DNS
|
|
providers and integration types, and a date/time display format
|
|
(date order, 12/24-hour clock) applied consistently to every table in
|
|
the app.
|
|
|
|
All six integrations follow the same config-in-UI + encrypted-credentials
|
|
pattern, added (and edited — e.g. to rotate an expired API token without
|
|
recreating the whole integration) through **Integrations → Manage
|
|
integrations**.
|
|
|
|
**Verified for real, end to end**: every module above — including all six
|
|
integrations, both their read-only views and their write actions
|
|
(start/stop/restart, trigger-a-run, authorize/deauthorize) — has been
|
|
exercised against the user's actual live homelab, not just built against
|
|
specs. That pass also found and fixed two real bugs: the Synology adapter
|
|
assumed HTTPS-only (the NAS is reached over plain HTTP), and the Tailscale
|
|
adapter read `online`/`isExitNode` fields that don't actually exist in the
|
|
real API response (fixed to derive them from `connectedToControl` and
|
|
`enabledRoutes`). See the git log for the full verification notes per
|
|
integration.
|
|
|
|
## Requirements
|
|
|
|
- Node.js 20+
|
|
- An Authentik instance reachable from wherever this app runs
|
|
|
|
## 1. Set up an Authentik application
|
|
|
|
1. Create an **OAuth2/OpenID Provider**:
|
|
- Redirect URI: `<APP_BASE_URL>/auth/callback`
|
|
- Scopes: `openid`, `email`, `profile`
|
|
2. Create an **Application** using that provider, and assign the users/groups
|
|
who should be able to sign in — Authentik controls who can authenticate;
|
|
the app's own admin/operator/viewer roles control what they can do once in.
|
|
3. Copy the provider's issuer URL, client ID, and client secret into `.env`.
|
|
|
|
## 2. Local development
|
|
|
|
```bash
|
|
cp .env.example .env # fill in AUTHENTIK_*, SESSION_SECRET, CREDENTIALS_ENCRYPTION_KEY
|
|
npm install
|
|
npm run dev:server # http://localhost:3000 (API)
|
|
npm run dev:web # http://localhost:5173 (Vite dev server, proxies /api and /auth to :3000)
|
|
```
|
|
|
|
Visit `http://localhost:5173` during development. Database migrations run
|
|
automatically on server start. SQLite data lands in `./data` (gitignored).
|
|
|
|
Generate `SESSION_SECRET` and `CREDENTIALS_ENCRYPTION_KEY` with:
|
|
|
|
```bash
|
|
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
```
|
|
|
|
## 3. Run with Docker
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
# edit .env
|
|
docker compose -f docker-compose.dev.yml up -d --build # build locally
|
|
# or, once an image is published to your registry:
|
|
docker compose up -d
|
|
```
|
|
|
|
The app listens on `HOST_PORT` (default `3000`); SQLite data persists in
|
|
`./data` on the host.
|