server-dashSRV-004
2026
Self-hosted home server dashboard
Rust / Axum
Next.js 16
NixOS
Put it backLinux & systems crate
Back to Linux & systems crateSRV-004 · 2026 · Linux & systems

server-dash

Self-hosted home server dashboard

A dashboard for my NixOS home server: live system stats, systemd service control, smart plugs and ESP32 buttons, with passkey login.

Stack
Rust / Axum, Next.js 16, NixOS
Links
GitHub ↗

Overview

server-dash is the control panel for my NixOS home server. It shows live system stats, starts, stops and restarts systemd services, controls TP-Link Tapo smart plugs, and manages ESP32 smart buttons I built (JMIoT). It began as two repos, a Next.js frontend and a Rust API, which I later merged into one pnpm monorepo.

The API

The backend is a Rust service on Axum and Tokio.

  • Stats come from sysinfo: CPU, memory, root disk, network counters, load average, temperature and uptime.
  • Services are controlled over D-Bus with zbus, calling systemd's StartUnit, StopUnit and RestartUnit directly instead of shelling out to systemctl. Only services on an allowlist can be touched, and the last 100 lines of a unit's journal can be read from the dashboard.
  • Smart plugs: the API finds Tapo plugs by scanning the local subnet, polls their power draw live, streams it to the frontend, and keeps a power history on disk.
  • Smart buttons: the ESP32 buttons register with the API and report presses to a callback endpoint, and presses can trigger automations such as switching a plug. The API registers itself as the buttons' callback URL, and automations run in the background so the button gets its response right away.

Login

The dashboard can restart services and power off the machine, so login is more than a password. After the password check, the API asks for a WebAuthn passkey (I use a YubiKey) or a TOTP code, then issues a JWT. Accounts are the app's own by default; logging in with a system account through /etc/shadow is off unless I turn it on. The enrollment flow, which lets you register a passkey on first login, can be closed once setup is done.

Deployment

The flake exports two NixOS modules, one for the frontend and one for the API. Each runs as a systemd service under its own system user. Rather than running the API as root, the module adds a polkit rule that lets that one user manage systemd units and reboot or power off the machine, and nothing else.

Keeping privileges narrow

A web page that can restart services and shut the machine down needs each permission scoped on its own: an allowlist for services, a narrow polkit rule instead of root, and a second factor at login. Because it's all NixOS configuration, the service users, the polkit rule and both services are declared together in the flake, next to the code they run.