Files
Homelab-manager/README.md
T
bobbanandClaude Sonnet 5 f5d3c25c89 Add editing existing integrations, so an expired secret can be rotated
Manage integrations only supported add/toggle/delete — fixing an
expired API token meant deleting and recreating the whole integration.

- New GET /api/integrations/:id/config returns only the non-secret
  config fields (never the decrypted secret) so an edit form can
  pre-fill URL/tailnet/etc. fields.
- New POST /api/integrations/:id/test merges the stored, decrypted
  config with any freshly-typed overrides and pings the real adapter —
  lets "Test connection" work during an edit without ever sending the
  current secret back to the browser.
- New IntegrationEditForm component: secret fields render blank with a
  "leave blank to keep the current value" placeholder; submitting only
  sends the fields that were actually filled in, so a name/URL edit
  can't accidentally wipe a secret and a secret rotation can't touch
  anything else. Reuses the existing PATCH /:id route, which already
  merged partial config updates correctly.

Verified end-to-end against the real dev server: confirmed via direct
DB decryption that a non-secret-only edit leaves the stored secret
byte-for-byte unchanged, and that a secret-only edit rotates it without
touching other config; the test route was confirmed to make a real
network call (got a genuine "API token invalid" from Tailscale's API
against a fake key).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 13:12:17 +02:00

5.4 KiB

Homelab Manager

Repository: git@10.200.5.13:bobban/Homelab-manager.git (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) and scheduled-task tracking across Debian/Raspbian hosts (ported from Schedule Task Manager). Looks and feels like a Tabler 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
  • 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.
  • 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), and DNS provider badge-color customization.

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

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:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

3. Run with Docker

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.