Files
Homelab-manager/README.md
T
bobbanandClaude Sonnet 5 e7ac6fea3b Add a "Sync from Proxmox" action to IP Addresses (IPAM)
Extends the Tailscale IPAM sync to Proxmox: pulls every VM/LXC's IP
address(es) across all enabled Proxmox integrations into the
inventory, reusing the same never-overwrite-a-manual-entry semantics.

Proxmox guests can have multiple NICs (each IP synced as its own
entry) and, for QEMU VMs, IP discovery depends on a responsive guest
agent — a VM with none simply contributes zero entries rather than
erroring, matching getGuestDetail()'s existing best-effort behavior.
listGuests() doesn't include IPs, so this fetches getGuestDetail() per
guest; acceptable for an explicit, user-triggered sync rather than a
background poll.

Extracted the shared "insert, update only if I own this row, else
skip and report" upsert logic (previously inline in the Tailscale sync
handler) into upsertSyncedEntry(), now used by both sync routes so the
core safety rule can't drift between them.

Verified end-to-end against a mock Proxmox server covering: an LXC
with two NICs (both synced), a QEMU VM with a responsive guest agent,
a QEMU VM with no agent (zero entries, no error), a manual-entry
collision (skipped and reported, never overwritten), and idempotent
re-sync (add -> update on the second run).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 23:45:10 +02:00

122 lines
5.8 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 & Tasks** — 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). A clickable server
overview opens a detail page with CPU/RAM/disk status, IP addresses, and
matching DNS names (looked up from the DNS module's cache) — live 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.
- **Integrations → Tailscale** — device list with online/authorized status,
and authorize/deauthorize/remove actions; a live device-count widget.
- **Integrations → 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).
- **Integrations → Dockhand** — container status across every Docker host
Dockhand manages (one credential covers all of them), with
start/stop/restart actions; a live running/total widget.
- **Integrations → 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).
- **Integrations → Proxmox** — VM/LXC status across every node in the
cluster, with start/stop/restart actions; a live running/total widget.
Supports self-signed certificates (common in homelab Proxmox setups).
- **Integrations → Synology** — volume and disk health (read-only by
design). Supports self-signed certificates.
- **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 with a
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.