A personal homelab dashboard for service links, status, and operations.
  • JavaScript 45.9%
  • TypeScript 32.3%
  • CSS 16.6%
  • HTML 4.2%
  • Shell 0.9%
  • Other 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
David Spitzer 8c62e62e89
All checks were successful
Publish Container / publish (push) Successful in 24s
0.16.1: wallboard Services tiles scale to fill the panel
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-03 10:20:07 -08:00
.forgejo/workflows Attribute Forgejo releases to registry user 2026-06-10 09:25:48 -07:00
.vscode Document build metadata publishing 2026-05-28 15:18:50 -07:00
design Mockups: blue and red palette (blue = normal, red = problem) 2026-10-14 11:49:35 -07:00
docs 0.16.1: wallboard Services tiles scale to fill the panel 2026-11-03 10:20:07 -08:00
public Add qBittorrent and SABnzbd integrations 2026-10-14 11:30:41 -07:00
scripts 0.14.1: Proxmox backup warnings reflect the latest result per guest 2026-11-02 14:45:16 -08:00
server 0.16.0: classic, dense and admin views follow the wallboard 2026-11-03 10:09:24 -08:00
src 0.16.1: wallboard Services tiles scale to fill the panel 2026-11-03 10:20:07 -08:00
.dockerignore Add Docker-ready integration foundation 2026-05-19 13:24:39 -07:00
.env.example 0.14.0: Jellyfin module with per-stream direct, remux and transcode detail 2026-11-02 14:35:46 -08:00
.gitattributes Container and dependency hardening; document new deployment settings 2026-10-14 09:36:18 -07:00
.gitignore Move dashboard persistence to SQLite 2026-05-27 08:16:06 -07:00
AGENTS.md One design language across the whole app (0.11.0) 2026-10-14 21:10:19 -07:00
CHANGELOG.md 0.16.1: wallboard Services tiles scale to fill the panel 2026-11-03 10:20:07 -08:00
docker-compose.build.yml Publish dashboard image to Forgejo registry 2026-05-19 13:56:39 -07:00
docker-compose.yml Container and dependency hardening; document new deployment settings 2026-10-14 09:36:18 -07:00
docker-entrypoint.sh Container and dependency hardening; document new deployment settings 2026-10-14 09:36:18 -07:00
Dockerfile Container and dependency hardening; document new deployment settings 2026-10-14 09:36:18 -07:00
homelab-dashboard.code-workspace Add Codex handoff and VS Code workspace 2026-05-27 13:34:13 -07:00
index.html Add resizable cards and dashboard branding 2026-05-21 09:03:23 -07:00
package-lock.json 0.16.1: wallboard Services tiles scale to fill the panel 2026-11-03 10:20:07 -08:00
package.json 0.16.1: wallboard Services tiles scale to fill the panel 2026-11-03 10:20:07 -08:00
README.md One design language across the whole app (0.11.0) 2026-10-14 21:10:19 -07:00
tsconfig.json Initial homelab dashboard scaffold 2026-05-19 12:28:16 -07:00
vite.config.ts Initial homelab dashboard scaffold 2026-05-19 12:28:16 -07:00

Homelab Dashboard

A private dashboard for homelab service links, uptime, infrastructure stats, media libraries, storage health, downloads, and operational shortcuts. It polls your services from one backend (so tokens never reach the browser), raises alerts, and has a wall-mounted wallboard view.

Wallboard showing three issues

The wallboard (/wall) in demo mode with three problems. Blue is normal; red is a problem. More about the wallboard.

Wallboard, all normal

Dense work view

The dense view (/) for a work screen: problems stand out, healthy rows stay quiet, and rows expand for detail.

Dense work view with rows expanded

Classic dashboard

The original card dashboard, still available at /classic, now in the same design language, with cards, drill-downs, layouts and diagnostics. All screenshots use built-in demo data, never real hosts or secrets.

Admin console

The admin console. Every screen, from sign-in to settings, shares one design language: flat panels, blue for normal, red for problems.

What it monitors

Proxmox, TrueNAS, ASUSTOR and UniFi NAS storage, UniFi Network, Uptime Kuma, qBittorrent, SABnzbd, Plex, Seerr, Kavita, Grimmory and Navidrome, with optional webhook alerts (Discord, ntfy or generic JSON). Each one is set up in the admin page; the Module Setup Guide walks through every module with screenshots and says where to find each URL, token and key.

Documentation

Development

npm install
npm run dev

The Vite dev server handles the frontend. Production runs through the Node backend so API tokens stay server-side.

Build

npm run build

Production

Example docker-compose.yml:

services:
  homelab-dashboard:
    image: registry.example.com/YOUR-USER/homelab-dashboard:latest
    container_name: homelab-dashboard
    restart: unless-stopped
    environment:
      - DATA_DIR=/data
      - PORT=3000
      # Number of reverse proxies in front of the dashboard (nginx, NPM, ...). Use 1 behind one proxy, 0 when clients connect directly.
      - TRUST_PROXY_HOPS=0
    security_opt:
      - no-new-privileges:true
    ports:
      - "3000:3000"
    volumes:
      - homelab-dashboard-data:/data

volumes:
  homelab-dashboard-data:

Start or update the container:

docker compose pull
docker compose up -d

The container listens on port 3000. On first launch, open http://YOUR-VM-IP:3000/admin to create the initial admin user.

It is ready to run behind an nginx reverse proxy. See docs/nginx-proxy.md. Container publishing notes live in docs/container-registry.md.

To build locally instead of using the Forgejo container registry:

docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build

Deployment Settings

These environment variables control how the server runs. They are not stored in the admin database. See .env.example for the full list.

Variable Default Purpose
TRUST_PROXY_HOPS 0 Number of reverse proxies in front of the dashboard. Set 1 behind nginx so login rate limits and the audit log use the real client IP. Leave 0 if clients connect directly.
DASHBOARD_SETUP_TOKEN unset When set, creating the first admin user requires this token.
DASHBOARD_ALLOWED_ORIGINS unset Extra browser origins allowed to make changes, needed only if your proxy rewrites the Host header.
DASHBOARD_DISPLAY_KEY unset Optional read-only key (24+ characters) that lets a wall display open /wall?key=... without logging in. It only opens the live data connection. See Wallboard.
DASHBOARD_DEMO unset ok or warn serves synthetic demo data only, for previews and screenshots. Never set on a real deployment.
DASHBOARD_REALTIME_INTERVAL_MS 5000 Tick interval of the background poller and WebSocket pushes.
DASHBOARD_POLL_<ID>_SECONDS per integration How long each integration's result is reused, for example DASHBOARD_POLL_STORAGE_SECONDS=300.

A single server-side loop polls every integration, records history, sends alerts, and pushes updates to all open browsers, so alerts fire even when nobody has the dashboard open and extra browser tabs do not add upstream API calls.

The container runs as the unprivileged node user. On start it fixes ownership of /data for volumes created by older root-run images.

npm run test:hardening runs the regression checks (security hardening, the pollers, the download clients, demo mode and the display key) against throwaway instances. npm run docs:screenshots regenerates every image in docs/ from demo data; it needs Chrome or Edge.

Admin Settings

Open /admin after first launch to create the initial admin user. After registration, use the admin dashboard to configure module URLs and tokens.

The admin dashboard stores the admin user, module settings, notification history, and audit history in a SQLite database at /data/dashboard.db. Existing settings.json, notification-history.json, and audit-log.json files are imported into the database automatically on first startup after upgrade. Secret fields are saved server-side and are not returned to the browser after saving.

The dashboard includes local layout profiles, wallboard presets, mobile-friendly card layouts, theme presets, card drill-downs, a SQLite-backed event timeline, server-side Uptime Kuma and diagnostic history samples with retention controls, module-specific diagnostic guidance, running version visibility, redacted settings export, history export/clear controls, and optional webhook alert notifications. Browser-local items such as layout, theme, uptime ticks, and older fallback timeline data can be cleared from the Dashboard Recovery section.

The admin dashboard also includes a White Label section for changing the header title, subtitle, eyebrow text, logo URL, and module documentation link base URL.

For module-by-module setup, including where to find each URL, API key and token, use the Module Setup Guide. The same guide is mirrored in the Forgejo wiki (Module-Setup), and each module's Wiki setup button opens its page there.

Project Shape

  • server/server.js serves the production app, the WebSocket feed and the admin API; server/dashboard-runtime.js is the background poller; each integration lives in its own server/*.js module and returns display checks plus structured stats. server/demo-data.js produces the synthetic data for demo mode.
  • src/DenseView.tsx (the default view at /), src/WallBoard.tsx (/wall) and src/App.tsx (the classic dashboard at /classic, the admin console and routing) are the views. src/normalize.ts and src/stats.ts turn API data into typed shapes, and src/useDashboardFeed.ts is the live WebSocket feed.
  • scripts/hardening-smoke.mjs holds the regression checks, and scripts/capture-screenshots.mjs regenerates the documentation images.
  • docs/ has the guides, CHANGELOG.md lists what changed in each release, and design/ keeps the original mockups.