nexdeck
The live homelab dashboard. Cards that move, actions on the cards, boards for the desk, the phone and the wall.
nexdeck belongs to the nexapps family, next to Nexview, nexmail, nexbeat, nexpulse and the Nexview Home Assistant integration.

What it does
- Live, not polled by your browser. The server asks every service in its own rhythm and pushes changes to every open browser. Ten tabs cost a service one request.
- 172 integrations, listed in full further down. Generic building blocks for everything else: a JSON API widget, a calendar that merges several sources, iframes, notes and bookmarks.
- Actions where the data is. Restart a container, start a VM, pause downloads, approve a request, wake a machine, flip a light. Destructive actions confirm once. Everything is logged.
- Three screens. A free grid of 12, 24 or 36 columns you arrange once: a tablet shows it as arranged, a phone stacks the cards in the same order. An installable phone app with a bottom bar, kiosk links for wall tablets that cycle pages and dim at night, and a sign-in without a password for a tablet on the home network.
- Yours to look at. Thirteen colour themes besides nexdeck's own, Catppuccin, Nord, Dracula, Tokyo Night, Gruvbox and Rosé Pine among them, cards drawn as glass, flat, outline or with a neon edge, and backgrounds that drift, show the stars or follow the time of day. Numbers roll to each new reading, and a card that goes down glows red while the room behind it turns a little red too.
- Made to be shown. Showcase mode replaces addresses, host names, people, devices and appointments with made-up ones that read like real ones, and a board saves as a picture on a frame of colour, ready for a forum or a chat.
- Users, roles and sharing. Administrators, users and guests. Boards are private, shared with people or with a whole role, at view, edit or act level.
- Reachability and notifications. App tiles carry a check with uptime bars; outages reach you through Telegram, e-mail, Web Push, ntfy, Gotify, Discord, Slack or Apprise.
- A head start. Six board templates that fill their slots with whichever of your services fits, and an import from Homepage or Homarr that shows its plan before it makes anything.
- Boards as files. Export a board as YAML, keep it in Git, drop it into
data/boards/to provision it. Docker labels create tiles. - Sign in your way. Local accounts, OpenID Connect with several providers side by side (authentik in one step, Microsoft Entra ID, Keycloak, Authelia, Pocket ID and friends), personal API tokens.
- In English, German, Spanish, French or Italian. The interface and every card, including what the services report. Each account picks the two languages that stand in its top bar.
A board is whatever you put on it
Every card is a widget of one integration, dropped on a free grid and sized by hand. A template is only where you begin.
Media
What is playing, what the library holds, what is on its way in, and the covers of what arrived last. And your own music: a player card plays the library of Plex, Jellyfin or Emby in the browser, keeps playing from board to board, and edits playlists on the server.

Infrastructure
The same grid, a different question. Hosts, containers, pools, disks, certificates and what answers.

On the wall
A kiosk link opens one board without a sign-in, read-only unless you say otherwise. It cycles through the pages and dims at night. The token is handed in once at the door and never rides in an address afterwards.
Quick start
mkdir nexdeck && cd nexdeck curl -fsSL https://raw.githubusercontent.com/DerKezorm/nexdeck/main/docker-compose.yml -o docker-compose.yml docker compose up -d
Open http://your-host:5175. The first start creates the administrator and offers a demo board with invented, moving data, so you can look around before connecting anything.
Mount /var/run/docker.sock (already in the compose file) to see this host's containers, act on them and follow their logs. On Synology the same socket serves Container Manager.
Configuration
| Variable | Default | Purpose |
|---|---|---|
NEXDECK_SECRET_KEY |
generated into /data/secret.key |
Encrypts stored API keys and signs sessions. Set it once and keep it. |
NEXDECK_PUBLIC_URL |
empty | How browsers reach nexdeck. Needed for OpenID Connect and Web Push. |
NEXDECK_DEMO |
0 |
Start every widget with invented data. |
NEXDECK_LOG_LEVEL |
INFO |
DEBUG logs every adapter request. |
NEXDECK_ALLOW_LOOPBACK_TARGETS |
0 |
Let notification channels, Web Push, RSS cards and reachability checks call 127.0.0.1. Connections an administrator made are never affected. |
NEXDECK_UPLOAD_QUOTA_MB |
200 |
What one account may leave lying in /data/uploads. 0 means no ceiling. |
NEXDECK_KEEP_ACTION_LOG_DAYS |
90 |
How long the record of who pressed what is kept. 0 keeps it forever. |
NEXDECK_KEEP_NOTICES_DAYS |
90 |
How long messages in the notice centre are kept. |
NEXDECK_KEEP_OUTAGES_DAYS |
365 |
How long finished outages are kept. A running one is never swept. |
PUID, PGID |
1000 |
Owner of the files in the data volume. |
DOCKER_GID |
detected | Group of the mounted Docker socket, when detection fails. |
Rarely needed, but real:
| Variable | Default | Purpose |
|---|---|---|
NEXDECK_DATA_DIR |
/data |
Where the database, the key file, uploads and caches live. |
NEXDECK_STATIC_DIR |
set in the image | The built frontend. Empty means the API only. |
NEXDECK_COOKIE_SECURE |
auto |
auto sets the Secure flag when the request came over HTTPS, directly or from a proxy named in NEXDECK_TRUSTED_PROXIES; always and never force it. |
NEXDECK_SESSION_DAYS |
30 |
Days a browser stays signed in without activity. |
NEXDECK_BCRYPT_ROUNDS |
12 |
Cost of a password hash. Lower is faster and weaker. |
NEXDECK_DB_POOL_SIZE |
20 |
Database connections held open. |
NEXDECK_DB_MAX_OVERFLOW |
20 |
How many more may be opened under load. |
NEXDECK_REQUEST_THREADS |
24 |
Worker threads for synchronous routes. Keep it below the two above added together. |
NEXDECK_HISTORY_RAW_HOURS |
1 |
How long raw samples are kept before they become minute averages. |
NEXDECK_HISTORY_MINUTE_HOURS |
24 |
How long those minute averages are kept. |
NEXDECK_LOG_HISTORY_HOURS |
6 |
How long container log lines are kept. |
NEXDECK_HEALTH_INTERVAL_SECONDS |
30 |
Default interval for reachability checks. |
NEXDECK_OUTAGE_THRESHOLD_SECONDS |
120 |
How long a service must be down before an outage is announced. |
NEXDECK_ICON_CACHE_DAYS |
30 |
How long a fetched logo is kept. |
NEXDECK_UPDATE_CHECK |
0 |
Ask GitHub whether a newer nexdeck exists. Off by default: it is an outbound call. |
NEXDECK_CORS_ORIGINS |
empty | Origins allowed to call the API from a browser. * is refused at start-up, because with credentials it would let any site act as the signed-in user. |
NEXDECK_BACKUP_EVERY_HOURS |
24 |
How often a snapshot is written by itself. 0 switches it off. |
NEXDECK_TRUSTED_PROXIES |
empty | Addresses or networks of the reverse proxies in front of nexdeck, comma separated. Their X-Forwarded-For is believed when nexdeck decides whether a browser is on the home network; without it, a forwarded request is never signed in automatically. It is also the only list whose X-Forwarded-Proto is believed for the Secure flag of cookies and whose X-Forwarded-Proto and X-Forwarded-Host the sign-in believes for its redirect address; empty, nobody's is (see below). |
A guard test keeps this table in step with the settings in the code.
Reverse proxy
nexdeck speaks plain HTTP on port 8000. It believes X-Forwarded-Proto only from a proxy named in NEXDECK_TRUSTED_PROXIES, and out of the box from nobody: then the scheme is the one the request really came in on, so a visitor cannot choose it. Of a named proxy the right-most value of the last header line counts (the one the nearest proxy wrote), http or https in any case. That scheme decides the Secure flag of the cookies. Behind a proxy that ends TLS, name it in NEXDECK_TRUSTED_PROXIES, or set NEXDECK_COOKIE_SECURE=always; otherwise the cookies go without the Secure flag (until 0.39.0 every sender's header was believed for it). The redirect address the sign-in sends to a provider: with a public address set (System → Sign-in) that address is used and no header is read; without one, scheme and host come from X-Forwarded-Proto and X-Forwarded-Host by the same rule, so a visitor cannot make the sign-in send a provider an address of their choosing. Without a named proxy the sign-in uses the address the request really came in on. This is the setting the authentik card means when it warns that the server sees a request as http: name your proxy, or set the public address. Server-Sent Events need a proxy that does not buffer: for nginx, proxy_buffering off; on the location; Traefik and Caddy need nothing.
Sign-in providers
Under System → Sign-in an administrator adds OpenID Connect providers (each gets a button on the sign-in page, in the order of the list), sets authentik up in one step with a one-time API token, or downloads a blueprint instead. Microsoft Entra ID takes https://login.microsoftonline.com/common/v2.0 (or organizations, or a tenant) as the issuer. A provider's redirect address is <public address>/api/v1/oidc/<short name>/callback; providers set up with nexdeck 0.36 or older keep /api/v1/auth/oidc/<short name>/callback, which their provider already knows. Accounts are found by the provider's subject only, never by an e-mail address; people link their own account under Profile, with their password. Password sign-in can be switched off once a provider is active; administrators can always use their password.
Signing in on the home network (System → Home network) needs the browser's real address. Behind a proxy, name the proxy in NEXDECK_TRUSTED_PROXIES; the page shows what nexdeck makes of your own address. The image starts uvicorn with --no-proxy-headers and reads the forwarding headers itself; a compose file that overrides the command should do the same.
The services it speaks to
Hosts and containers. Docker, Proxmox VE, Proxmox Backup Server, Kopia, Duplicati, Portainer, Nomad, Cup, Coolify, Gitea, Forgejo, GitLab, Semaphore UI, Meilisearch, Synology DSM, Unraid, TrueNAS, openmediavault, Glances, Beszel, Prometheus, Alertmanager, Grafana, Scrutiny, UPS through PeaNUT, Wake-on-LAN, Backrest, Komodo, Arcane, Dockhand, Kubernetes, UrBackup, Elasticsearch and OpenSearch, Netdata, Ollama, Open WebUI, Watchtower, What's Up Docker, Zabbix, nextrmnl, PatchMon.
Network. Public IP address, Cloudflare, UniFi, MikroTik, SNMP (switches and network devices), FRITZ!Box, OPNsense, pfSense, FortiGate, OpenWrt, Traefik, Nginx Proxy Manager, nginx ignition, Pi-hole, AdGuard Home, Technitium, NextDNS, Tailscale, Headscale, NetBird, Pangolin, wg-easy, NetBox, Gluetun, authentik, CrowdSec, Shlink, Speedtest Tracker, nexpulse, nexsift, Uptime Kuma, Healthchecks, ChangeDetection.io, n8n, Blocky, Gatus, NetAlertX, Pocket ID.
Media. Plex, Jellyfin, Emby, Tautulli, Tracearr, Jellystat, Radarr, Sonarr, Lidarr, Readarr, Prowlarr, autobrr, NeutArr, Bazarr, SABnzbd, NZBGet, qBittorrent, Qui, Transmission, Deluge, rTorrent, MeTube, Seerr, Overseerr, Jellyseerr, ReadMeABook, Nexview, nexcrate, nexbeat, Maintainerr, Reclaimerr, Tdarr, Unmanic, FileFlows, RomM, Sportarr, Tube Archivist, Real-Debrid, M3U Editor, Minecraft.
Home and files. Home Assistant, Frigate, Reolink, evcc, Immich, Nextcloud, FileBrowser Quantum, Syncthing, Paperless-ngx, Papra, Firefly III, Actual Budget, Mealie, Grocy, Vikunja, nexlore, nexpaper, nexdiary, nexcanvas, nexbrand, Kimai, Dawarich, wger, Audiobookshelf, Navidrome, Komga, Kavita, Calibre-Web, BookOrbit, Ghostfolio, Homebox, PhotoPrism, Tandoor Recipes, Wallos, OctoPrint.
Feeds, weather and messages. Hacker News, YouTube, GitHub, share prices, Twitch, RSS, Miniflux, FreshRSS, Karakeep, Linkwarden, Linkding, iCal and CalDAV, Weather, ntfy, Gotify, nexmail, IMAP, Mailpit.
Adapters that have not been confirmed against a live instance yet carry a beta badge in the interface. If one misbehaves, please open an issue with the service's version.
Documentation
- Running nexdeck: backups, restoring, updating
- Integrations and widgets
- Docker labels
- Boards as files and provisioning
- Kiosk displays
- API
Development
Backend: Python 3.13, FastAPI, SQLAlchemy, SQLite. Frontend: React 19, Vite 7, Tailwind 4.
# backend cd backend python -m venv .venv && . .venv/bin/activate pip install -r requirements-dev.txt uvicorn app.main:app --reload --port 8000 # frontend, in a second terminal cd frontend npm ci npm run dev
The frontend on http://localhost:5176 proxies /api to the backend. Tests: python -m pytest in backend/, npm test and npm run e2e in frontend/. The whole CI set, read from the workflow: python tools/ci_local.py in backend/ (--tag vX.Y.Z adds the version check, --install the installs). The guards in backend/tests/test_guards.py and frontend/src/i18n/*.test.ts enforce English messages, complete translations, an auth decision on every address and no personal data in the repository.
Adding an adapter
One file in backend/app/adapters/: declare the connection fields and the widgets, implement test, fetch, optionally action, and demo. Every widget maps onto one of fifteen renderers, so no frontend code is needed. See docs/adapters.md.
License
AGPL-3.0-or-later. See LICENSE.
