Nvidia SMI web dashboard for multi-server clusters, built with Next.js 16, shadcn/ui, Lucide icons, Redis, and JWT auth. It fetches real-time GPU metrics from nvidia-smi-web agents, aggregates them via a server-side proxy API, and renders per-server and per-GPU panels with utilization charts and process tables.
This project is based on the original nvidia-smi-web/dashboard idea and backend behavior, but the frontend is rebuilt with shadcn/ui, lucide-react, and recharts.
| Light | Dark |
|---|---|
![]() |
![]() |
- Email verification login with JWT
- Optional no-login mode
- Redis-backed verification codes with resend cooldown
- Access logging to CSV
- Proxy API to securely fetch data from multiple GPU agent servers
- Per-server and per-GPU monitoring cards
- Real-time utilization and memory history charts
- Process table with command tooltip
- Custom top-of-page elements via environment variables
- Responsive UI with dark mode support
- Node.js 24+
- pnpm
- Redis
- SMTP account if login is enabled
- One or more running GPU agents exposing a status endpoint
Agent reference: configure your agents first, then point SERVERS to their status URLs.
- Copy
.env.exampleto.env.localand update the values. - Install dependencies.
- Start the dev server.
pnpm install
pnpm devOpen http://localhost:3000.
Notes:
NEXT_PUBLIC_*variables are exposed to the browser.- Boolean values must be the string
trueorfalse. - Comma-separated values should not contain spaces.
Core UI:
NEXT_PUBLIC_SITE_TITLE- Site title. Default:GPU DashboardNEXT_PUBLIC_SITE_DESCRIPTION- Site description used in the hero section and metadataNEXT_PUBLIC_NO_NEED_LOGIN- Iftrue, disables login and auth guardingNEXT_PUBLIC_SERVERS_ID- Comma-separated server IDs shown on the homepage, for examples1,s2NEXT_PUBLIC_CUSTOM_ELEMENTS- JSON array of custom top-of-page elementsNEXT_PUBLIC_CHART_DATA_LENGTH- Number of points retained in GPU charts. Default:200
Authentication:
JWT_SECRET- Secret used to sign and verify JWT tokensTOKEN- Optional bypass token; if cookieauth_tokenequals this value, auth checks are skippedDEVOPS- Contact shown in allowlist error messagesALLOWED_EMAILS- Comma-separated email allowlist. Empty means all emails are allowed
Server configuration:
SERVERS- JSON string mapping server IDs to{ url, token }
Example:
{
"s1": {
"url": "http://s1.example.com/status?process=C",
"token": "123456"
},
"s2": {
"url": "http://s2.example.com/status?process=C",
"token": "abcdef"
}
}If token is present, it is sent as the Authorization header.
Email:
SMTP_HOSTSMTP_PORTSMTP_SECURESMTP_USERSMTP_PASS
If NEXT_PUBLIC_NO_NEED_LOGIN=true, SMTP is not required.
Redis and logging:
REDIS_URL- Example:redis://localhost:6379ACCESS_LOG_PATH- CSV log path. Default:data/log/access.csvTZ- Timezone for access log timestamps, for exampleAsia/Shanghai
-
POST /api/auth/send-code- Body:
{ email: string } - Sends a 6-digit verification code
- Body:
-
POST /api/auth/login- Body:
{ email: string, code: string } - Validates the code and returns
{ token }
- Body:
-
POST /api/access- Requires
auth_tokencookie unless no-login mode is enabled - Appends a CSV line in the format
email,access_time,ip_address
- Requires
-
POST /api/proxy- Body:
{ serverId: string | string[] } - Fetches data from configured agent endpoints on the server side
- Body:
This project uses proxy.ts to protect routes.
- When login is enabled, unauthenticated access to
/redirects to/login - Authenticated users visiting
/loginare redirected back to/ - API routes other than
/api/auth/*require valid auth unless bypassed byTOKEN
NEXT_PUBLIC_CUSTOM_ELEMENTS accepts a JSON array rendered above the server list.
Supported item types:
textlinkcopyable
Example:
[
{
"type": "text",
"content": "Welcome to the GPU Dashboard",
"breakAfter": true
},
{
"type": "link",
"href": "https://example.com/docs",
"text": "Documentation",
"target": "_blank",
"rel": "noopener noreferrer"
},
{
"type": "copyable",
"label": "SSH",
"code": "ssh user@gpu-server"
}
]app/
api/
access/route.ts # Record access to CSV
auth/login/route.ts # Verify email+code and issue JWT
auth/send-code/route.ts # Send verification code via SMTP
proxy/route.ts # Server-side proxy to fetch GPU agent data
components/
custom-elements.tsx # Custom top-of-page elements renderer
per-gpu.tsx # Per-GPU monitoring card
per-server.tsx # Per-server panel
processes-table.tsx # Process table with command tooltip
theme-provider.tsx # Dark mode theme provider
types.ts # Shared types (GPUInfo, ProcessInfo, etc.)
login/page.tsx # Login page
page.tsx # Dashboard homepage
layout.tsx # Root layout (force-dynamic)
public-env-script.tsx # Inject NEXT_PUBLIC_* into window.__PUBLIC_ENV__
globals.css # Global styles
lib/
access-log.ts # CSV log writer
env.ts # Environment parsing helpers
public-env.ts # Runtime public env accessor
redis.ts # Redis verification storage
utils.ts # cn() utility
components/ui/ # shadcn/ui components
proxy.ts # Route protection (Next.js middleware)
docker-entrypoint.sh # Docker entrypoint (runs pre-run.sh, then server)
pnpm lint
pnpm type-check
pnpm buildPre-commit: Husky runs pnpm lint && pnpm type-check automatically on every commit.
The project supports Docker deployment based on Node 24 Alpine with a two-stage build:
- Builder stage: installs dependencies and builds the app
- Runner stage: copies the standalone output
docker build -t gpu-dashboard .The entrypoint script (docker-entrypoint.sh) runs an optional pre-run.sh first (useful for SSH tunnels etc.), then starts node server.js.
When using Docker Compose, Redis is expected at hostname redis-dashboard.
- Never commit real SMTP credentials, JWT secrets, or production
SERVERSvalues - If the dashboard is public-facing, keep
NEXT_PUBLIC_NO_NEED_LOGIN=false - Use
ALLOWED_EMAILSif you want to restrict access to specific users - Use
TOKENonly when you trust an upstream reverse proxy or integration layer
- Dashboard project: nvidia-smi-web/dashboard
- Agent project: nvidia-smi-web/agent

