SelfDashboard
Docker app from Svensen's Repository
Overview
Readme
View on GitHub
Self-hosted homelab dashboard — one container, one browser tab, live widgets from a plugin store.
Selbstgehostetes Homelab-Dashboard — ein Container, ein Browser-Tab, Live-Widgets aus dem Plugin-Store.
📰 What's new / Neuigkeiten → CHANGELOG.md
🇬🇧 English
SelfDashboard is your personal control center for homelab and self-hosting: one Docker container, one browser tab — instead of a dozen open admin UIs. Widgets are plugins with real backends (Docker, FRITZ!Box, CrowdSec, calendar, mail …), installed from a Plugin Store and configured entirely in the UI. It is not a plain bookmark page and not a YAML-config dashboard.
Part of the Self family (SelfMailer, SelfStream, SelfArchiver …) — same design system, same deploy style (GHCR → Unraid).
TL;DR — live widgets via plugin store · multiple dashboards · login + 2FA + multi-user · kiosk mode for wall tablets · AES-256-GCM-encrypted credentials · single container · no external DB.
📑 Table of contents
Features · Plugins · How it compares · Architecture · Dashboards & widgets · Kiosk mode · Android app · Login & multi-user · Troubleshooting · Documentation · Quick start · Unraid · Configuration · Backups · Security · Tech stack · Development · Roadmap
✨ Features
Example layout below — SelfMailer calendar, clock, weather, FRITZ! history & power, AdGuard, bookmarks, Zoraxy, media, Uptime Kuma, WireGuard, CrowdSec, two Unraid servers, notes and the navbar mail badge. Every widget is a plugin, freely arrangeable and configurable.

🧩 Plugins & updates
- Volume-only plugin system — install from the Plugin Store (GitHub) or as ZIP; no widgets baked into the image
- Plugin updates — the store compares versions; badge + Update all, no image rebuild; Ctrl+F5 after an update
- Auto-index store — drop a plugin folder into
plugins-pack/<id>/and push;plugins-index.jsonregenerates automatically - Central error log — Settings → Logs: app, API and plugin errors (filter, export, 3–30 day retention), automatic for every registered plugin
📋 Dashboards & design
- Multiple dashboards, each with its own URL (
/dashboard/home,/dashboard/server) - 6 color themes (Dark, Light, Nord, Catppuccin, Dracula, Solarized) + custom colors per dashboard
- Custom logo per dashboard; background images — navbar wallpaper + dashboard (1 or 2 JPG/PNG images) with readability overlay
- Drag & drop, free resizing, per-widget zoom, padding and height
- Dashboard zoom (60 %–150 %), adjustable grid spacing and outer padding
- Navbar options — icon only, text only or both; toggle dashboard tabs
- Responsive layout — phone / tablet / desktop grid based on dashboard width; optional per-widget overrides; compact navbar search (full-width row) on narrow viewports
- Unit system — global metric (°C, km/h) / imperial (°F, mph) / auto switch (Settings → General); Weather, FRITZ! Smart Home, Homematic and Google Home widgets pick up the choice (auto follows locale, defaults to metric)
✉️ Navbar mail (IMAP)
- Unread badge in the navbar — multiple accounts, Synology/MailPlus-friendly, encrypted passwords, click opens webmail
🔐 Security & platform
- Login & multi-user — SQLite auth, admin/user roles, plugin whitelist, optional TOTP 2FA
- Secure by default — non-root container, AES-256-GCM-encrypted credentials, SSRF guard on all proxy plugins
- Kiosk mode — public
/kioskURL, view-only full screen for wall tablets, optional password - Multilingual — German & English interface
- Single container — Next.js 15, no external database (embedded SQLite for auth), no Redis
- Unraid ready — Community Apps template included
🧩 Plugins
Widgets are not bundled in the image — install them from the Plugin Store or upload a ZIP. Each plugin has its own README (EN/DE) under plugins-pack/<id>/. Install & folders: docs/PLUGINS.md · develop plugins: docs/PLUGIN_DEV.md.
Plugins marked (Beta) are new integrations that have not yet been tested against every server version — feedback (with the service version) is welcome.
| Plugin | Category | Description |
|---|---|---|
| AdGuard Home | Network | DNS stats, protection toggle (stat tiles fill the widget) |
| Amazon Alexa | Media | Echo playback & volume, Alexa smart-home devices, routines (unofficial Alexa cloud API) (Beta) |
| Apple Music | Media | In-browser player (Beta) |
| Bambu Lab Camera | Utility | Live printer camera (P1/A1 local or stream URL) (Beta) |
| Bookmarks | Utility | Quick links with groups (e.g. Unraid, Emby, Nextcloud, Immich, SelfMailer) |
| Calendar | Productivity | CalDAV + ICS |
| Clock | Utility | Time, date, timezone |
| CrowdSec | Security | Alerts, active bans, world map (optional) |
| Docker | System | Containers via socket |
| Dreame | Utility | Robot vacuum status + start/pause/dock (cloud) (Beta) |
| Productivity | Navbar IMAP badge, click opens webmail | |
| Emby | Media | Active sessions |
| FRITZ! WAN | Network | Internet throughput chart (down/up Mbit/s) with peaks (TR-064) |
| FRITZ! Energy | Network | Smart-plug power: now, today, 7 days, month (TR-064) |
| FRITZ! Smart Home | Utility | Thermostats, plugs, contacts (AHA) (Beta) |
| Google Home / Nest | Utility | Nest thermostats, sensors, device status (SDM API) (Beta) |
| Home Assistant | Utility | Selected entities (Beta) |
| Homematic | Utility | Heating, switches, sensors, rooms (RaspberryMatic) (Beta) |
| Iframe | Utility | Embed URLs |
| Jellyfin | Media | Active sessions |
| LLM-Cockpit | System | Token counter (today/month, daily history), LLM speed and project status in one tile — needs the small collector service (/tokens, /status) |
| LLM-Tempo | System | Tokens per second of local llama.cpp servers (needs llama-server --metrics) |
| NetzWacht | Security | Live throughput, top devices and Suricata alerts from an ntopng stack (Beta) |
| Nginx Proxy Manager | Network | Proxy hosts overview (Beta) |
| OpenMediaVault | Storage | System info via RPC (Beta) |
| OPNsense | Network | Version, gateways (Beta) |
| Parcel Tracking | Utility | DHL / Hermes / DPD tracking, no API key |
| Philips Hue | Utility | Lights & rooms control (Beta) |
| Pi-hole | Network | Pi-hole v6 stats |
| Plex | Media | Active sessions (Beta) |
| Project status | Utility | Where each project stands and which questions wait for you, read from STATUS.md files of an AI agent |
| Proxmox VE | System | Nodes, VMs/LXC (Beta) |
| Reolink Camera | Utility | Live camera, AI/motion badges, PTZ (Beta) |
| Scratchpad | Utility | Short notes pinned to the dashboard |
| SelfMailer | Productivity | Unread mail across all SelfMailer mailboxes (total, per account, newest) |
| SelfMailer Calendar | Productivity | Month view of upcoming SelfMailer events; create events directly in SelfMailer |
| Selfstream | Media | Live IPTV |
| Selfstream · Emby · Jellyfin | Media | Combined stream list with a configurable title |
| Shelly 3EM | System | 3-phase power, import/export, kWh history |
| Shelly Plug | System | Several plugs per tile, power + on/off switch, kWh today / this month |
| Speedtest Tracker | Network | Latest down/up/ping (Beta) |
| Spotify | Media | Now playing, controls, seek, volume, search & device picker |
| Token counter | System | Tokens used by your AI agent (in, out, largest context), monthly statistics |
| TrueNAS | Storage | System + pool status (Beta) |
| UniFi Controller | Network | WLAN/LAN/WAN status (Beta) |
| Unraid | System | CPU, RAM, array/pool and disks per server (Unraid 7.2+ GraphQL) |
| Unraid Docker | System | Containers via Unraid API |
| Uptime Kuma | Network | Status-page monitors (up / down / pending) in a compact list |
| Waste Collection | Utility | Bin pickup calendar, next-up countdown, local |
| Weather | Utility | Open-Meteo (proxy), day blocks (0–6 … 18–24) + 7-day forecast from tomorrow |
| WireGuard | Network | wg-easy peers — online now / total, handshake history, live up/down traffic (Beta) |
| Zoraxy | Network | Reverse-proxy hosts, valid vs. blocked requests (Beta) |
All plugin READMEs are bilingual (EN/DE). Brand logos in the store via homarr-labs/dashboard-icons.
⚖️ How it compares
Heimdall, Homarr, Dashy and Homepage are all great projects — SelfDashboard just focuses on something different: live widgets with real backends, built-in auth and a kiosk mode, all configured in the UI.
| SelfDashboard | Heimdall | Homarr | Homepage | |
|---|---|---|---|---|
| Widgets with real backend | yes, plugin system | limited | some | via API/YAML |
| Configuration | UI, no YAML | UI | UI | YAML files |
| Login + 2FA + multi-user | built in | no | partial | no |
| Kiosk mode | yes | no | no | no |
| Encrypted credentials | AES-256-GCM | – | – | – |
A good fit if you want
- Live, interactive widgets (Docker control, FRITZ!Box, CrowdSec, calendar, mail) — not just links
- Multi-user with real auth / 2FA and a wall-tablet kiosk
- To configure everything in the UI instead of editing config files
Maybe not for you if
- You just want a simple bookmark/start page (Heimdall or Homepage are lighter for that)
- You can't run a Docker container, or prefer a purely static config-file workflow
- You need a large, established plugin ecosystem today — SelfDashboard's is younger and still growing
⚠️ Note: plugin server code runs with the app's privileges (no sandbox yet) — only install plugins you trust.
🧭 Architecture
GitHub, branch main (catalog) Host volume /app/plugins/custom
plugins-pack/plugins-index.json per plugin: plugin.json
plugins-pack/<id>/widget.js + widget.js
(+ server.mjs) (+ server.mjs for some)
│ ▲ │
└──── Store: Install / Update ─────────┘ │ browser loads widget.js
▼
┌─────────────────────── Docker image (core) ─────────────────────────┐
│ Next.js UI · Plugin Store · dashboards │
│ Built-in APIs: calendar, mail, docker, crowdsec, fritzbox, weather …│
│ Gateway /api/plugins/{id}/… ← plugin server.mjs │
└──────────────────────────────────┬───────────────────────────────────┘
│
Host volume /app/data
dashboards · auth DB · calendar · central log
| Layer | Location | Purpose |
|---|---|---|
| Core app | Docker image ghcr.io/s3lfcod3r/selfdashboard (:latest) |
Dashboard UI, settings, logging, plugin store, most /api/* routes |
| Installed plugins | Host → /app/plugins/custom/<id>/ |
Widgets the browser runs (widget.js); survives image updates |
| Plugin catalog | GitHub plugins-pack/ on branch main (configurable) |
plugins-index.json + files the store downloads on install/update |
| Plugin source (dev) | plugins-pack/<id>/ (index.tsx, widget.js, optional server.ts) |
Store ships UI + bundled server.mjs; image builtins remain fallback |
| App data | Host → /app/data |
dashboard.json, calendar DB, central log |
App update vs. plugin update
| You change… | New Docker image? | What to do |
|---|---|---|
A plugin (widget.js and/or server.mjs on GitHub) |
No | Plugin Store → Update (or Update all) → Ctrl+F5 |
| SelfDashboard core (UI, APIs, store, loader) | Yes | docker pull + restart container; keep /app/data and /app/plugins/custom mounts |
🖥️ Dashboards & widgets
Managing dashboards
Each dashboard gets its own URL. Navigate between dashboards via the tab bar in the navbar or through Settings → Dashboards.
| Action | How |
|---|---|
| Create dashboard | Settings → Dashboards → New Dashboard |
| Switch dashboard | Click tab in navbar or Settings → Dashboards → Open |
| Hide tab from navbar | Settings → Dashboards → 👁️ toggle per dashboard |
| Delete dashboard | Settings → Dashboards → 🗑️ |
| Rename / change icon | Settings → Dashboards → ✏️ |
Widget controls
In Edit Mode (✏️ button), hover over any widget to see controls:
| Control | Function |
|---|---|
| ⠿ Drag handle | Move widget |
🔍 − 100% + |
Zoom widget content |
↔ − 8 + |
Inner padding |
↕ − 4 + |
Widget height |
| ⚙️ | Plugin settings |
| ✕ | Remove widget |
| Resize grip (corner/edge) | Resize width and height freely |
Responsive layout (phone, tablet & desktop)
The dashboard uses three layout bands based on the dashboard grid width (the track that holds the widgets — not only the outer browser window):
| Band | Approx. width | Behaviour |
|---|---|---|
| Phone | < 768 px | Single stacked column; each widget uses layoutPhone height overrides when set, otherwise the desktop layout height. |
| Tablet | 768 – 1023 px | 12-column grid like desktop; optional layoutTablet overrides (w, h, x, y, minH) merge with layout. |
| Desktop | ≥ 1024 px | Full desktop layout — what you usually edit when resizing widgets on a large screen. |
How to tune it: enter Edit mode (✏️), open a widget's ⚙️ settings. Below the plugin-specific options, "Layout: phone & tablet" lets you set optional phone row height / min height and tablet position & size. Leave fields empty to keep using the desktop layout values for that band.
On narrow viewports (about ≤ 1024 px) the navbar web search moves to a second row at full width so it is not squeezed into the corner next to zoom and actions.
Plugins can optionally read the layoutMode prop ('phone' | 'tablet' | 'desktop') for their own responsive UI — see docs/PLUGIN_DEV.md.
Settings overview
- General — language (DE/EN), dashboard title, navbar web search, navbar mail badge, navbar display style, dashboard tab visibility, unit system (metric/imperial/auto)
- Users — change password, 2FA (TOTP), kiosk / wall tablet (admin). Admins also manage users and the plugin whitelist here.
- Dashboards — create, edit, delete dashboards; toggle tab visibility per dashboard; set emoji or custom PNG icon
- Design — navbar display style; grid spacing; navbar background (JPG/PNG + overlay); dashboard background (off / 1 image / 2 images side by side + overlay); logo upload; color theme; custom color overrides
- Email — IMAP accounts, navbar badge, poll interval, connection test
- Logs — central error log for support and debugging: filter by level, source, plugin; download
.txt/ JSONL; retention 3 / 7 / 30 days. Every plugin registered viaregisterPluginlogs render failures and failed/api/*calls automatically. Mail uses the same log with plugin idmail. Details: docs/LOGGING.md.
📺 Kiosk mode (wall tablet)
Public view-only display for a wall-mounted tablet or guest browser — separate from the normal logged-in dashboard. Ideal for a kitchen display, wall tablet or shared screen on your LAN.
| Topic | Details |
|---|---|
| Display URL | http://YOUR-IP:3000/kiosk — no admin login, full-screen widgets, no navbar |
| Configure (admin) | Settings → Users → Kiosk / wall tablet — enable, pick dashboard, optional password, session duration (2 h … unlimited) |
| Edit widgets | Log in as admin → /dashboard/<id> (e.g. /dashboard/kiosk) → edit mode — same as any dashboard |
| Do not confuse | /kiosk = display only · /dashboard/kiosk = edit with login |
| Plugins | Only widgets on the chosen kiosk dashboard are loaded (works in any browser, no SelfDashboard account needed when passwordless) |
| HTTP / LAN | Cookies work on HTTP by default; set SELFDASHBOARD_SECURE_COOKIES=1 only behind HTTPS |
📱 Android app
The SelfDashboard Android app shows the dashboard full screen on wall tablets. It contains no backend code of its own — it only displays your SelfDashboard web app.
| Topic | Details |
|---|---|
| Modes | Login mode (normal dashboard with login) or kiosk mode (view-only, no login) |
| Download (APK) | github.com/s3lfcod3r/selfdashboard/releases/latest — currently v1.0.4 (app version, separate from the dashboard version 2.2.0) |
| Features | WebView, pull-to-refresh, full screen, screen saver |
🔐 Login & multi-user
SelfDashboard requires login. On first start (no users yet) you are redirected to /setup to create the admin account. Existing dashboard.json in appdata is migrated to that admin automatically (backup: dashboard.json.pre-auth-migrated).
| Topic | Details |
|---|---|
| Roles | admin — full access, plugin store, user management · user — only whitelisted plugins |
| User data | /app/data/users/<id>/dashboard.json per user |
| Auth data | /app/data/auth/auth.db (users, sessions, plugin whitelist) |
| Admin UI | Settings → Users — create/delete users, reset passwords, plugin checkmarks, kiosk config |
| Self-service | Settings → Users — change password, enable 2FA (TOTP) |
| 2FA | Optional authenticator at login — setup under Settings → Users |
| Forgot password (no email) | Env reset: SELFDASHBOARD_AUTH_RESET_PASSWORD → restart (see below) |
| Backup | Back up all of /app/data (at least auth/ + users/) |
| Dev only | SELFDASHBOARD_AUTH_DISABLED=1 disables auth (never in production) |
Setup — admin locked out (forgot password)
There is no email reset (would need SMTP — not typical for homelab). Simplest is the env reset on Unraid:
Env password reset (recommended on Unraid) — edit container, add variable:
SELFDASHBOARD_AUTH_RESET_PASSWORD= your new password (min. 8 chars)- optional:
SELFDASHBOARD_AUTH_RESET_USER=admin(default: first admin) - or one field:
SELFDASHBOARD_AUTH_RESET=admin:NewPassword - in production also
SELFDASHBOARD_ENABLE_ENV_RESET=1(see Configuration) - Restart container → sign in → clear the variable(s) → restart again
Direct CLI (shell access):
docker exec selfdashboard node /app/scripts/auth-reset-password.mjs --username admin --password 'NewSecurePass'Second admin — reset password under Settings → Users.
🩺 Troubleshooting
Problems & solutions
| Problem | Solution |
|---|---|
| Dashboard not loading | Check logs: docker logs selfdashboard |
| Dashboard / widgets load slowly | Measure first: browser console (F12) ~10 s after loading → copy(__sdPerfReport.text) shows render time per widget and what blocks the browser; server side docker logs selfdashboard 2>&1 | grep timing shows slow plugin requests (handler = the service behind the plugin) and offline hosts ([upstream]). Widgets of devices that are permanently off cost ~3 s once after each restart — remove them. See docs/PLUGIN_PERFORMANCE.md |
Plugin / mail fails with blocked_url / private_ip_blocked |
The target service runs on a private LAN IP (e.g. 192.168.x), which is blocked by default since 2026-07. Add SELFDASHBOARD_ALLOW_PRIVATE_URLS=1 to the container and recreate it. Affects AdGuard, Pi-hole, FRITZ!, SelfMailer and any other LAN-hosted backend. |
500 error after update (SQLITE_READONLY in logs) |
The container runs non-root (PUID/PGID). The entrypoint fixes volume ownership automatically on start; if you set SELFDASHBOARD_SKIP_CHOWN=1, run chown -R <PUID>:<PGID> on your appdata folder yourself. |
CrowdSec: unable to open database file (often after nightly backups) |
Set the container's PUID/PGID to the same values as your CrowdSec container (Unraid default 99/100). Then SelfDashboard reads crowdsec.db as the owner — permanently, no chmod. |
Plugin shows 401 / stats_failed / auth error (AdGuard, Pi-hole, FRITZ!, …) although credentials are correct |
The encryption key changed. Fix once: set a fixed SELFDASHBOARD_SECRET_KEY (long random string) in Docker, restart, then re-enter the plugin's password in its settings and Save. The key never changes again → stays working. (On an older core image, also set SELFDASHBOARD_CALENDAR_KEY to the same value until you pull the new :latest.) |
| Config lost after update | Image updates do not remove your appdata volume; your layout lives in /app/data/users/<userId>/dashboard.json (plus a localStorage cache). If a new browser shows an empty dashboard, check /app/data is mounted and writable (see Unraid). |
| Plugin store empty / "GitHub not configured" | Set SELFDASHBOARD_PLUGINS_GITHUB_* or use the official :latest image defaults |
| Widget stuck on "Loading plugin…" | Wait a few seconds; Plugin Store → Reload plugins; check files under /app/plugins/custom/<id>/widget.js |
| Update installed, UI unchanged | Ctrl+F5 (hard reload) — browser caches widget.js |
| Plugin not found after install | Confirm Plugins Storage mount; folder must contain plugin.json + widget.js (not index.tsx) |
| Port already in use | Change host port: -p 3001:3000 |
| Widgets invisible in edit mode | Try refreshing the page |
| Theme not applying | Hard refresh: Ctrl+Shift+R |
CrowdSec widget: crowdsec.db not found |
Set CrowdSec Data (optional) in the Unraid template (host folder with crowdsec.db → /crowdsec-data:ro), or remove the widget if you do not use CrowdSec |
CrowdSec: no country flags / all ?? |
Ensure GeoLite2-City.mmdb (or Country) is in the mounted CrowdSec data folder, or set CROWDSEC_GEOIP_PATH |
| CrowdSec: unban fails | Mount Docker Socket, check container name in plugin settings, enable unban there |
| Mail badge red/yellow, count 0 | Settings → Email → re-enter password → Save. Set fixed SELFDASHBOARD_SECRET_KEY in Docker. Check Logs filter mail |
Mail: ENOTFOUND host:5000 |
IMAP host must be IP/hostname only (e.g. 192.168.1.15), port 993 separate; webmail URL goes in Webmail URL field |
| Mail test OK, navbar empty | Enable Navbar email (General or Email tab); save account; badge needs unread > 0 |
| Mail badge shows mail that is gone in MailPlus | IMAP may still list deleted/read messages until the server cleans up. Use Show unread in email settings to see subjects. After update, SelfDashboard ignores \Deleted and \Seen ghosts. In MailPlus: empty trash / expunge if needed, then Refresh all accounts. |
| MailPlus shows 1 unread, preview listed 2 (old FRITZ mail) | Synology IMAP can keep ancient UNSEEN UIDs. Use Settings → Email → Unread age filter (default 30 days; 0 = off). Preview shows how many were ignored as too old or duplicate Message-ID. |
| Weather: HTTP 404 on plugin API | New app image required — route is in the core app (/api/plugins/weather/…), not a volume-only plugin |
| Weather: no data / API error | Container must reach api.open-meteo.com and geocoding-api.open-meteo.com (HTTPS outbound). Test: http://HOST:PORT/api/plugins/weather/resolve?name=Berlin&language=de → JSON |
| Weather plugin old UI (hourly strip only) | Plugin Store → Weather → Update → Ctrl+F5 (target 1.3.x) |
Unraid: Failed to fetch |
Browser calls Unraid directly (https://NAS/graphql). Not a 7.3-only issue — check API key, URL, HTTPS cert, and CORS / allowed origins for your dashboard URL (e.g. http://192.168.x.x:3010) on each NAS |
| Unraid works on one NAS, not another | Compare API enabled, key permissions, and CORS on the failing box (7.2.3 and 7.3 both supported if GraphQL API is active) |
| Background image not visible | Design → mode not Off; image uploaded; after change Ctrl+F5; very large images are capped (~4–5 MB in config) |
| Kiosk shows login instead of widgets | Use /kiosk, not /dashboard/…. Enable kiosk under Settings → Users → Kiosk |
| Kiosk: "Plugin not found" | Open /kiosk once as admin (updates plugin list), then retry guest browser; Ctrl+F5 |
Home dashboard broken after visiting /kiosk |
Update to latest image (kiosk cookie no longer overrides admin session); Ctrl+F5 |
📚 Documentation
| Topic | Document |
|---|---|
| Install & update plugins | docs/PLUGINS.md |
| Write & publish plugins | docs/PLUGIN_DEV.md |
| Plugin architecture | docs/PLUGIN_ARCHITECTURE.md |
| Plugin distribution model | docs/PLUGIN_DISTRIBUTION.md |
| Plugins as volume + ZIP | docs/CUSTOM_PLUGINS_VOLUME.md |
| Plugin performance (dev) | docs/PLUGIN_PERFORMANCE.md |
| Builtin servers in git / CI | docs/PLUGINS_IN_REPO.md |
| Docker image build | docs/DOCKER_BUILD.md |
| Per-plugin setup (EN/DE) | docs/plugins/README.md |
| Recent API/plugin changes | docs/CHANGELOG.md |
| Error log | docs/LOGGING.md |
Unraid template details (NODE_TLS_REJECT_UNAUTHORIZED) |
unraid/README.md |
🚀 Quick start (Docker)
docker run -d \
--name selfdashboard \
--restart unless-stopped \
-p 3000:3000 \
-e TZ=Europe/Berlin \
-v /mnt/user/appdata/selfdashboard:/app/data \
-v /mnt/user/appdata/selfdashboard/plugins:/app/plugins/custom \
-v /var/run/docker.sock:/var/run/docker.sock \
ghcr.io/s3lfcod3r/selfdashboard:latest
Or with docker compose (see docker-compose.yml):
git clone https://github.com/s3lfcod3r/selfdashboard.git
cd selfdashboard
docker compose up -d
Open http://<host>:3000 → /setup creates the admin account → Plugin Store → From GitHub, install the widgets you need → + to place them → Ctrl+F5 if a widget stays blank.
- Required: map
/app/data(dashboard.json, calendar, logs) and/app/plugins/custom(installed plugins). Without the plugins folder, the store can install files but they will not persist. - Optional: Docker socket — Docker plugin only; CrowdSec mount — CrowdSec plugin only.
- Image tags: the Unraid template uses
ghcr.io/s3lfcod3r/selfdashboard:latest. The plugin catalog is loaded from GitHub branchmain(SELFDASHBOARD_PLUGINS_GITHUB_REF, normally left as-is). - LAN services: if your widgets talk to LAN addresses (AdGuard, Pi-hole, FRITZ!, Home Assistant …), set
SELFDASHBOARD_ALLOW_PRIVATE_URLS=1.
📦 Unraid
Add the template from
https://raw.githubusercontent.com/s3lfcod3r/selfdashboard/main/unraid/selfdashboard.xml
or import it under Docker → Add Container → Template.
Setup — Unraid Community Apps (recommended)
- Open Community Apps → search for SelfDashboard
- Install — set Config Storage, Plugins Storage, port (default
3000) - Open
http://YOUR-IP:3000 - Plugin Store → From GitHub — install widgets you need (Calendar, Bookmarks, …)
- Click + to place widgets on the dashboard → Ctrl+F5 if a widget stays blank
| Mount / setting | Content |
|---|---|
/app/data (Config Storage) |
Per-user dashboards (users/), auth DB (auth/), calendar, central log — back up regularly |
/app/plugins/custom (Plugins Storage) |
Installed plugins (<id>/plugin.json, widget.js, optional server.mjs) — back up with appdata |
| GitHub env vars | Pre-set in :latest image: repo s3lfcod3r/selfdashboard, ref main, path plugins-pack |
| Docker Socket (optional) | Local host only — Docker plugin |
| CrowdSec Data (optional) | crowdsec.db read-only — CrowdSec plugin |
Both Config Storage and Plugins Storage are required for a normal setup. After a plugin update: Store → Update → Ctrl+F5. After an app update: pull new image, restart — layouts and installed plugins stay on the volumes.
⚠️ Secret key: set a fixed
SELFDASHBOARD_SECRET_KEYand never change it afterwards — it encrypts all stored credentials. Changing it makes them unreadable.⚠️ Permissions: the container runs non-root. The template sets PUID/PGID 99/100 (
nobody:users); on start the entrypoint remaps to your PUID/PGID and chowns/app/data+/app/plugins/customautomatically (opt-out:SELFDASHBOARD_SKIP_CHOWN=1). CrowdSec tip: set PUID/PGID to the same values as your CrowdSec container — then SelfDashboard owns and readscrowdsec.dbdirectly, surviving nightly backups that restart CrowdSec (no chmod needed).⚠️ LAN access: the template pre-sets
SELFDASHBOARD_ALLOW_PRIVATE_URLS=1(recommended in a home network), so widgets can reach LAN services.⚠️ Self-signed HTTPS: leave
NODE_TLS_REJECT_UNAUTHORIZEDempty;0disables certificate checks for all outgoing HTTPS. Details: unraid/README.md.
⚙️ Configuration
Environment variables, mostly with the prefix SELFDASHBOARD_, plus a few runtime and plugin variables.
| Variable | Required | Default | Purpose |
|---|---|---|---|
TZ |
– | Europe/Berlin |
Timezone |
NODE_ENV |
– | production |
Node.js environment |
PUID / PGID |
– | 1001 (image), 99 / 100 (Unraid template) |
User/group the app runs as; entrypoint remaps and chowns the volumes |
SELFDASHBOARD_SKIP_CHOWN |
– | 0 |
1 = never touch volume ownership on start |
SELFDASHBOARD_FIX_CROWDSEC_PERMS |
– | 1 |
0 = don't add read permissions on /crowdsec-data |
SELFDASHBOARD_DATA_DIR |
– | /app/data (in the official image) |
Directory inside the container where dashboard.json is stored. Must match your /app/data bind-mount unless you intentionally use another path. |
SELFDASHBOARD_SECRET_KEY |
– | auto-generated file in data dir | Central secret key for encrypting all stored credentials: calendar, mail and widget passwords/tokens (AdGuard, Pi-hole, FRITZ!, Speedtest, …). Strongly recommended: set a fixed value so credentials survive image updates and volume moves. Once set, never change it. (Legacy alias SELFDASHBOARD_CALENDAR_KEY still works as a fallback.) |
SELFDASHBOARD_ALLOW_PRIVATE_URLS |
– | off (private IPs blocked); 1 in the Unraid template |
1 lets plugins reach private/LAN IPs (10/8, 172.16/12, 192.168/16). Since 2026-07 private targets are blocked by default (SSRF protection). Home-lab setups that point AdGuard, Pi-hole, FRITZ!, SelfMailer, Home Assistant … at LAN addresses must set this to 1 — otherwise those widgets fail with private_ip_blocked / blocked_url. (Legacy SELFDASHBOARD_BLOCK_PRIVATE_CALENDAR_URLS is no longer needed.) |
SELFDASHBOARD_SECURE_COOKIES |
– | off | 1 marks session/kiosk cookies Secure (HTTPS only). Default off so HTTP on LAN works. Set to 1 when exposing the app over HTTPS. |
SELFDASHBOARD_INSECURE_COOKIES |
– | – | 1 forces non-Secure cookies (same as default on HTTP) |
SELFDASHBOARD_TRUST_PROXY |
– | off | 1 only when a reverse proxy in front sets X-Forwarded-For/X-Real-IP. When off, those (client-spoofable) headers are ignored for rate limiting. Account brute-force protection works regardless (persistent per-account lockout). |
SELFDASHBOARD_AUTH_RESET_PASSWORD |
– | – | One-shot admin password reset on container start (see Login & multi-user) |
SELFDASHBOARD_AUTH_RESET_USER |
– | first admin | User for the env password reset |
SELFDASHBOARD_AUTH_RESET |
– | – | Combined form user:password for the env password reset |
SELFDASHBOARD_ENABLE_ENV_RESET |
– | off | In production (NODE_ENV=production, the default in the official image) the env password reset is ignored unless this is 1. Safety net so a forgotten NODE_ENV cannot leave the reset path silently active. |
SELFDASHBOARD_AUTH_DISABLED |
– | – | 1 disables auth — dev only, never in production |
SELFDASHBOARD_PLUGINS_CUSTOM |
– | <app>/plugins/custom |
Installed plugins (Unraid: map host folder here) |
SELFDASHBOARD_PLUGINS_GITHUB_REPO |
– | s3lfcod3r/selfdashboard in :latest image |
GitHub repo for the store (owner/repo) |
SELFDASHBOARD_PLUGINS_GITHUB_REF |
– | main |
Branch/tag for plugins-pack/ |
SELFDASHBOARD_PLUGINS_GITHUB_PATH |
– | plugins-pack |
Path in repo to plugin files |
MAIL_DATA_DIR |
– | <plugins/custom>/mail |
Directory for mail.json (optional override) |
CALENDAR_SYNC_INTERVAL_SECONDS |
– | 300 |
Calendar background sync interval |
CROWDSEC_DATA_DIR |
– | /crowdsec-data |
Allowed root for DB paths (CrowdSec widget only) |
CROWDSEC_GEOIP_PATH |
– | – | Full path to GeoLite2-*.mmdb if not in the data folder |
CROWDSEC_DB_PATH |
– | – | Default DB file if widget path is empty |
CROWDSEC_CONTAINER |
– | crowdsec |
Docker container name for optional unban via cscli |
NODE_TLS_REJECT_UNAUTHORIZED |
– | empty | 0 disables TLS certificate checks for all outgoing HTTPS — only for self-signed homelab certs; see unraid/README.md |
SELFDASHBOARD_PLUGIN_READ_CACHE |
– | on | 0 turns off the central read cache for plugin APIs (plugins opt in via readCache in their plugin.json) |
SELFDASHBOARD_HOST_DOWN_MS |
– | on | 0 turns off the offline-host memory (unreachable LAN hosts are answered instantly instead of waiting ~3 s each time) |
SELFDASHBOARD_STALE_MAX_MS |
– | per cache | Global maximum age (ms) for "stale" plugin data served while refreshing in the background; 0 = fresh data only |
SELFDASHBOARD_TIMING_LOG |
– | off | 1 logs every plugin request with its server timing (otherwise only slow ones) |
SELFDASHBOARD_TIMING_SLOW_MS |
– | 500 |
Plugin requests slower than this (ms) are always logged |
💾 Backups
Back up both host folders regularly — ideally offline / immutable, so ransomware on the mount cannot take data and key:
/app/data— per-user dashboards (users/), images moved out of widget settings (blobs/, e.g. bookmark icons), auth DB (auth/auth.db), calendar, central log and the auto-generated key files (.calendar-key,.secret-salt)/app/plugins/custom— installed plugins
Also keep your SELFDASHBOARD_SECRET_KEY in a password manager — without it, stored credentials cannot be decrypted.
Restore — stop the container, copy the backup back into the mapped folders, start again:
docker stop selfdashboard
cp -a /path/to/backup/selfdashboard/. /mnt/user/appdata/selfdashboard/
docker start selfdashboard
🛡️ Security
SelfDashboard is built for a trusted home LAN. A security review (2026-06) hardened the auth and plugin surfaces; the points below matter if you expose the app beyond your LAN.
Hardened in code
- Login brute-force: failed attempts are counted persistently per account in SQLite (10 / 15 min → temporary lockout) — survives restarts, independent of client IP, so spoofing
X-Forwarded-Fordoes not bypass it - Spoofable proxy headers are ignored unless
SELFDASHBOARD_TRUST_PROXY=1 - Admin actions require completed MFA: user/role/plugin-grant management is blocked for sessions that have not passed the second factor
- Rate limits on change password and disable TOTP; TOTP replay protection (each code valid once)
- TOTP secrets encrypted at rest (AES-256-GCM via
SELFDASHBOARD_SECRET_KEY) — a leakedauth.dbalone cannot mint valid 2FA codes - Credentials encrypted — calendar, mail and widget passwords/tokens sealed with AES-256-GCM; the browser only sees ciphertext
- Per-install salt — the key derivation uses a random salt that every installation generates once in
/app/data/.secret-salt(no environment variable); keep it in your backups - Docker container actions (start/stop/restart) require an admin with completed MFA — read-only listing stays available to widget users
- Plugin pack extraction validates every zip entry against path traversal (zip-slip) and enforces entry-count limits
- Plugin SVG assets are served with
Content-Disposition: attachment,X-Content-Type-Options: nosniffand a locked-down CSP (no stored XSS via SVGs) - Remote plugin integrity: if
plugins-index.jsonships asha256per file, every downloaded file (incl. executableserver.mjs) is verified before it is written - Internal identity headers (
x-sd-user-id/x-sd-role) are stripped from client requests and not echoed on responses - Env password reset is ignored in production unless
SELFDASHBOARD_ENABLE_ENV_RESET=1 - SSRF guard on all outbound requests: loopback / link-local / cloud-metadata always blocked, private/LAN IPs blocked by default (opt in with
SELFDASHBOARD_ALLOW_PRIVATE_URLS=1); CalDAV re-checks the resolved IP before connecting (DNS-rebinding protection), like IMAP/FRITZ! - Non-root container, reproducible
npm cibuild, container HEALTHCHECK
Operator responsibilities / when exposing publicly
- Use HTTPS and set
SELFDASHBOARD_SECURE_COOKIES=1— over the internet, session cookies must be Secure - Strip internal headers at the reverse proxy: drop incoming
x-sd-user-id,x-sd-roleandx-sd-kioskrequest headers (defense in depth) - TLS verification for IMAP/FRITZ! can be disabled per connection — leave it on unless you have a specific reason
- Use a strong admin password and a fixed
SELFDASHBOARD_SECRET_KEY - Docker socket = host root equivalent — mount it only for trusted admins and never expose it; read-only does not protect
:latest+ Watchtower (label indocker-compose.yml) rolls out new images without human approval — consider pinning a fixed version tag and removing the label for this powerful container
Deliberate trade-offs (documented)
- Plugin code runs with full server privileges — uploaded/remote
server.mjsfiles execute in the Node process without a sandbox. Only install plugins you trust and treat the admin account as equivalent to shell access. - Secure cookies are off by default so plain-HTTP LAN setups keep working
- Known lower-priority follow-ups:
script-srcstill allows'unsafe-inline' 'unsafe-eval'; DNS-rebinding/TOCTOU on generic outbound fetches would need connection pinning
Security update history → CHANGELOG.md (entries marked 🔒).
🧱 Tech stack
| Part | Tech |
|---|---|
| Frontend | Next.js 15 · React 18 · Tailwind CSS · react-grid-layout |
| State | Zustand — persisted to localStorage (cache) and to dashboard.json on the server when /app/data (or SELFDASHBOARD_DATA_DIR) is available |
| Server | Next.js API routes · better-sqlite3 (auth) · imapflow (mail) |
| Plugins | Volume-only — dynamic widget.js load + pluginRegistry · catalog from GitHub plugins-pack/ |
| Tests | Vitest · ESLint |
| Deploy | Docker (multi-stage, Node.js 22 Alpine, Next.js standalone, non-root) · GHCR · Unraid |
🛠️ Development
npm ci
npm run dev # Next.js dev server in the repo root
npm run lint # ESLint
npm run build # production build (vendors builtin plugins first)
npm run publish:plugin-pack # build plugins-pack/ for the store
npm run generate:plugins-index # regenerate plugins-pack/plugins-index.json
Tests:
npm run test
Docker image build: docs/DOCKER_BUILD.md · plugin development: docs/PLUGIN_DEV.md.
🗺️ Roadmap
- Volume-only plugin system · GitHub Plugin Store · ZIP upload · auto-generated index
- Multiple dashboards · 6 themes · backgrounds · responsive phone/tablet/desktop layout
- Login · multi-user · TOTP 2FA · kiosk mode
- Non-root container · AES-256-GCM credentials · SSRF guard (private IPs blocked by default)
- Central error log
- Vitest test setup with first SSRF tests
- Plugin sandbox (plugin server code currently runs with app privileges)
- Nonce-based CSP instead of
'unsafe-inline' 'unsafe-eval' - Connection pinning against DNS rebinding on outbound fetches
- Beta plugins tested against more server versions
🇩🇪 Deutsch
SelfDashboard ist dein persönliches Kontrollzentrum für Homelab und Self-Hosting: ein Docker-Container, ein Browser-Tab — statt zwölf geöffneter Admin-Oberflächen. Widgets sind Plugins mit echtem Backend (Docker, FRITZ!Box, CrowdSec, Kalender, Mail …), werden aus einem Plugin-Store installiert und komplett in der Oberfläche eingerichtet. Es ist keine reine Lesezeichenseite und kein Dashboard mit YAML-Konfiguration.
Teil der Self-Familie (SelfMailer, SelfStream, SelfArchiver …) — gleiches Design-System, gleicher Deploy-Stil (GHCR → Unraid).
Kurz — Live-Widgets aus dem Plugin-Store · mehrere Dashboards · Login + 2FA + Mehrbenutzer · Kiosk-Modus fürs Wand-Tablet · AES-256-GCM-verschlüsselte Zugangsdaten · ein Container · keine externe DB.
📑 Inhaltsverzeichnis
Funktionen · Plugins · Vergleich · Architektur · Dashboards & Widgets · Kiosk-Modus · Android-App · Login & Mehrbenutzer · Fehlerbehebung · Dokumentation · Schnellstart · Unraid · Konfiguration · Backups · Sicherheit · Tech-Stack · Entwicklung · Roadmap
✨ Funktionen
Beispiel-Layout unten — SelfMailer-Kalender, Uhr, Wetter, FRITZ! Verlauf & Strom, AdGuard, Lesezeichen, Zoraxy, Media, Uptime Kuma, WireGuard, CrowdSec, zwei Unraid-Server, Notizzettel und E-Mail-Badge in der Navbar. Jedes Widget ist ein Plugin, frei anordbar und einstellbar.

🧩 Plugins & Updates
- Plugin-System nur per Volume — Installation aus dem Plugin-Store (GitHub) oder als ZIP; keine Widgets im Image
- Plugin-Updates — der Store vergleicht Versionen; Badge + Alle aktualisieren, kein Image-Rebuild; danach Strg+F5
- Auto-Index-Store — Plugin-Ordner nach
plugins-pack/<id>/legen und pushen;plugins-index.jsonwird automatisch neu erzeugt - Zentrales Protokoll — Einstellungen → Protokoll: App-, API- und Plugin-Fehler (Filter, Export, 3–30 Tage Aufbewahrung), automatisch für jedes registrierte Plugin
📋 Dashboards & Design
- Mehrere Dashboards, jedes mit eigener URL (
/dashboard/home,/dashboard/server) - 6 Farbthemen (Dark, Light, Nord, Catppuccin, Dracula, Solarized) + eigene Farben pro Dashboard
- Eigenes Logo pro Dashboard; Hintergrundbilder — Navbar-Hintergrund + Dashboard (1 oder 2 JPG/PNG) mit Lesbarkeits-Overlay
- Drag & Drop, freies Skalieren, Zoom, Innenabstand und Höhe pro Widget
- Dashboard-Zoom (60 %–150 %), einstellbare Grid-Abstände und Außenrand
- Navbar-Optionen — nur Icon, nur Text oder beides; Dashboard-Tabs ein-/ausblendbar
- Responsives Layout — Handy / Tablet / Desktop-Raster je nach Dashboard-Breite; optionale Overrides pro Widget; Navbar-Suche auf schmalen Bildschirmen in eigener voller Zeile
- Einheitssystem — globales Metrisch (°C, km/h) / Imperial (°F, mph) / Automatisch (Einstellungen → Allgemein); die Wetter-, FRITZ! Smart Home-, Homematic- und Google-Home-Widgets übernehmen die Wahl (automatisch folgt der Sprache, Standard metrisch)
✉️ Navbar E-Mail (IMAP)
- Ungelesen-Badge in der Navbar — mehrere Konten, Synology/MailPlus-tauglich, verschlüsselte Passwörter, Klick öffnet das Webmail
🔐 Sicherheit & Plattform
- Login & Mehrbenutzer — SQLite-Anmeldung, Admin-/Nutzer-Rollen, Plugin-Freigaben, optional TOTP-2FA
- Sicher ab Werk — Container ohne Root, AES-256-GCM-verschlüsselte Zugangsdaten, SSRF-Schutz in allen Proxy-Plugins
- Kiosk-Modus — öffentliche URL
/kiosk, Nur-Ansicht im Vollbild fürs Wand-Tablet, optional mit Passwort - Mehrsprachig — Deutsch & Englisch
- Ein Container — Next.js 15, keine externe Datenbank (eingebettetes SQLite für die Anmeldung), kein Redis
- Unraid-tauglich — Community-Apps-Vorlage dabei
🧩 Plugins
Widgets stecken nicht im Image — Installation über den Plugin-Store oder per ZIP-Upload. Jedes Plugin hat eine eigene README (DE/EN) unter plugins-pack/<id>/. Installation & Ordner: docs/PLUGINS.md · Plugins entwickeln: docs/PLUGIN_DEV.md.
Mit (Beta) markierte Plugins sind neue Integrationen, die noch nicht gegen jede Server-Version getestet sind — Rückmeldungen (mit Versionsangabe) sind willkommen.
| Plugin | Kategorie | Beschreibung |
|---|---|---|
| AdGuard Home | Netzwerk | DNS-Statistik, Schutz umschalten (Kacheln füllen das Widget) |
| Amazon Alexa | Media | Echo-Wiedergabe & Lautstärke, Alexa-Smart-Home-Geräte, Routinen (inoffizielle Alexa-Cloud-API) (Beta) |
| Apple Music | Media | Player im Browser (Beta) |
| Bambu Lab Kamera | Utility | Live-Druckerkamera (P1/A1 lokal oder Stream-URL) (Beta) |
| Lesezeichen | Utility | Schnelllinks mit Gruppen (z. B. Unraid, Emby, Nextcloud, Immich, SelfMailer) |
| Kalender | Productivity | CalDAV + ICS |
| Uhr | Utility | Zeit, Datum, Zeitzone |
| CrowdSec | Sicherheit | Alerts, aktive Banns, Weltkarte (optional) |
| Docker | System | Container per Socket |
| Dreame | Utility | Saugroboter-Status + Start/Pause/Basis (Cloud) (Beta) |
| Productivity | IMAP-Badge in der Navbar, Klick öffnet das Webmail | |
| Emby | Media | Aktive Sessions |
| FRITZ! Internet | Netzwerk | Internet-Durchsatz-Kurve (rauf/runter Mbit/s) mit Spitzen (TR-064) |
| FRITZ! Energie | Netzwerk | Steckdosen-Leistung: aktuell, heute, 7 Tage, Monat (TR-064) |
| FRITZ! Smart Home | Utility | Thermostate, Steckdosen, Kontakte (AHA) (Beta) |
| Google Home / Nest | Utility | Nest-Thermostate, Sensoren, Gerätestatus (SDM-API) (Beta) |
| Home Assistant | Utility | Ausgewählte Entitäten (Beta) |
| Homematic | Utility | Heizung, Schalter, Sensoren, Räume (RaspberryMatic) (Beta) |
| Iframe | Utility | Webseite einbetten |
| Jellyfin | Media | Aktive Sessions |
| LLM-Cockpit | System | Token-Zähler (heute/Monat, Tagesverlauf), LLM-Tempo und Projektstatus in einer Kachel — braucht den kleinen Sammel-Dienst (/tokens, /status) |
| LLM-Tempo | System | Token pro Sekunde lokaler llama.cpp-Server (braucht llama-server --metrics) |
| NetzWacht | Sicherheit | Live-Durchsatz, Top-Geräte und Suricata-Alarme aus einem ntopng-Stack (Beta) |
| Nginx Proxy Manager | Netzwerk | Übersicht der Proxy-Hosts (Beta) |
| OpenMediaVault | Storage | Systeminfo per RPC (Beta) |
| OPNsense | Netzwerk | Version, Gateways (Beta) |
| Paketverfolgung | Utility | Sendungsverfolgung DHL / Hermes / DPD, ohne API-Key |
| Philips Hue | Utility | Lampen & Räume steuern (Beta) |
| Pi-hole | Netzwerk | DNS-Statistik Pi-hole v6 |
| Plex | Media | Aktive Sessions (Beta) |
| Projektstatus | Utility | Wo jedes Projekt steht und welche Fragen auf dich warten, gelesen aus den STATUS.md-Dateien eines KI-Agenten |
| Proxmox VE | System | Nodes, VMs/LXC (Beta) |
| Reolink Kamera | Utility | Live-Kamera, KI-/Bewegungs-Badges, PTZ (Beta) |
| Notizzettel | Utility | Kurznotizen direkt auf dem Dashboard |
| SelfMailer | Productivity | Ungelesene Mails über alle SelfMailer-Postfächer (gesamt, je Konto, neueste) |
| SelfMailer Kalender | Productivity | Monatsansicht der kommenden SelfMailer-Termine; Termine direkt in SelfMailer anlegen |
| Selfstream | Media | IPTV-Streams live |
| Selfstream · Emby · Jellyfin | Media | Kombinierte Stream-Liste mit einstellbarem Titel |
| Shelly 3EM | System | 3-Phasen-Leistung, Bezug/Einspeisung, kWh-Verlauf |
| Shelly Plug | System | Mehrere Steckdosen je Kachel, Leistung + An/Aus, kWh heute / laufender Monat |
| Speedtest Tracker | Netzwerk | Letzter Down/Up/Ping (Beta) |
| Spotify | Media | Aktueller Titel, Steuerung, Spulen, Lautstärke, Suche & Gerätewahl |
| Token-Zähler | System | Token-Verbrauch deines KI-Agenten (rein, raus, größter Kontext), Monatsstatistik |
| TrueNAS | Storage | System + Pool-Status (Beta) |
| UniFi Controller | Netzwerk | WLAN/LAN/WAN-Status (Beta) |
| Unraid | System | CPU, RAM, Array/Pool und Festplatten pro Server (Unraid 7.2+ GraphQL) |
| Unraid Docker | System | Container per Unraid-API |
| Uptime Kuma | Netzwerk | Status-Page-Monitore (OK / Down / Pending) in kompakter Liste |
| Müllabfuhr | Utility | Abholkalender pro Tonne, Countdown, komplett lokal |
| Wetter | Utility | Open-Meteo (Proxy), Tagesabschnitte (0–6 … 18–24) + 7-Tage-Vorschau ab morgen |
| WireGuard | Netzwerk | wg-easy-Peers — jetzt online / gesamt, Handshake-Verlauf, Live-Traffic rauf/runter (Beta) |
| Zoraxy | Netzwerk | Reverse-Proxy-Hosts, gültige vs. geblockte Anfragen (Beta) |
Alle Plugin-READMEs sind zweisprachig (DE/EN). Marken-Logos im Store via homarr-labs/dashboard-icons.
⚖️ Vergleich
Heimdall, Homarr, Dashy und Homepage sind alle super Projekte — SelfDashboard setzt einfach einen anderen Schwerpunkt: Live-Widgets mit echtem Backend, eingebaute Anmeldung und ein Kiosk-Modus, alles in der Oberfläche eingerichtet.
| SelfDashboard | Heimdall | Homarr | Homepage | |
|---|---|---|---|---|
| Widgets mit echtem Backend | ja, Plugin-System | begrenzt | einige | per API/YAML |
| Konfiguration | Oberfläche, kein YAML | Oberfläche | Oberfläche | YAML-Dateien |
| Login + 2FA + Mehrbenutzer | eingebaut | nein | teilweise | nein |
| Kiosk-Modus | ja | nein | nein | nein |
| Verschlüsselte Zugangsdaten | AES-256-GCM | – | – | – |
Passt gut, wenn du willst
- Live-Widgets, die wirklich etwas tun (Docker-Steuerung, FRITZ!Box, CrowdSec, Kalender, Mail) — nicht nur Links
- Mehrbenutzer mit echter Anmeldung / 2FA und einen Kiosk fürs Wand-Tablet
- Alles in der Oberfläche einrichten statt Config-Dateien zu bearbeiten
Vielleicht nichts für dich, wenn
- du nur eine einfache Lesezeichen-/Startseite willst (dafür sind Heimdall oder Homepage schlanker)
- du keinen Docker-Container betreiben kannst oder einen rein statischen Config-Datei-Ablauf bevorzugst
- du heute ein großes, etabliertes Plugin-Angebot brauchst — das von SelfDashboard ist jünger und wächst noch
⚠️ Hinweis: Plugin-Server-Code läuft mit den Rechten der App (noch keine Sandbox) — installiere nur Plugins, denen du vertraust.
🧭 Architektur
GitHub, Branch main (Katalog) Host-Volume /app/plugins/custom
plugins-pack/plugins-index.json pro Plugin: plugin.json
plugins-pack/<id>/widget.js + widget.js
(+ server.mjs) (+ server.mjs bei manchen)
│ ▲ │
└── Store: Installieren / Aktualisieren┘ │ Browser lädt widget.js
▼
┌─────────────────────── Docker-Image (Kern) ─────────────────────────┐
│ Next.js-Oberfläche · Plugin-Store · Dashboards │
│ Eingebaute APIs: Kalender, Mail, Docker, CrowdSec, FRITZ!, Wetter … │
│ Gateway /api/plugins/{id}/… ← server.mjs des Plugins │
└──────────────────────────────────┬───────────────────────────────────┘
│
Host-Volume /app/data
Dashboards · Anmelde-DB · Kalender · zentrales Protokoll
| Schicht | Ort | Zweck |
|---|---|---|
| Kern-App | Docker-Image ghcr.io/s3lfcod3r/selfdashboard (:latest) |
Oberfläche, Einstellungen, Protokoll, Plugin-Store, die meisten /api/*-Routen |
| Installierte Plugins | Host → /app/plugins/custom/<id>/ |
Widgets im Browser (widget.js); überleben Image-Updates |
| Plugin-Katalog | GitHub plugins-pack/ auf Branch main (einstellbar) |
plugins-index.json + Dateien für Installation/Update |
| Plugin-Quellcode (Entwicklung) | plugins-pack/<id>/ (index.tsx, widget.js, optional server.ts) |
Store liefert Oberfläche + gebündeltes server.mjs; eingebaute Plugins im Image als Rückfall |
| App-Daten | Host → /app/data |
dashboard.json, Kalender-DB, zentrales Protokoll |
App-Update vs. Plugin-Update
| Du änderst… | Neues Docker-Image? | Vorgehen |
|---|---|---|
Ein Plugin (widget.js und/oder server.mjs auf GitHub) |
Nein | Plugin-Store → Aktualisieren (oder Alle aktualisieren) → Strg+F5 |
| SelfDashboard-Kern (Oberfläche, APIs, Store, Loader) | Ja | docker pull + Container neu starten; Mounts /app/data und /app/plugins/custom behalten |
🖥️ Dashboards & Widgets
Dashboards verwalten
Jedes Dashboard hat eine eigene URL. Zwischen Dashboards wechselst du per Tab in der Navbar oder über Einstellungen → Dashboards.
| Aktion | So geht's |
|---|---|
| Dashboard erstellen | Einstellungen → Dashboards → Neues Dashboard |
| Dashboard wechseln | Tab in der Navbar klicken oder Einstellungen → Dashboards → Öffnen |
| Tab ausblenden | Einstellungen → Dashboards → 👁️ Schalter pro Dashboard |
| Dashboard löschen | Einstellungen → Dashboards → 🗑️ |
| Umbenennen / Icon ändern | Einstellungen → Dashboards → ✏️ |
Widget-Steuerung
Im Bearbeitungsmodus (✏️-Button) mit der Maus über ein Widget fahren, dann erscheinen die Bedienelemente:
| Element | Funktion |
|---|---|
| ⠿ Griff | Widget verschieben |
🔍 − 100% + |
Widget-Inhalt zoomen |
↔ − 8 + |
Innenabstand |
↕ − 4 + |
Widget-Höhe |
| ⚙️ | Plugin-Einstellungen |
| ✕ | Widget entfernen |
| Größen-Griff (Ecke/Rand) | Breite und Höhe frei ändern |
Responsives Layout (Handy, Tablet & Desktop)
Das Dashboard schaltet anhand der Raster-Breite (der Bereich mit den Widgets — nicht nur die Breite des Browserfensters) zwischen drei Modi:
| Modus | Ca. Breite | Verhalten |
|---|---|---|
| Handy | < 768 px | Eine Spalte, Widgets untereinander; nutzt layoutPhone-Höhen, falls gesetzt, sonst die Höhe aus dem Desktop-layout. |
| Tablet | 768 – 1023 px | 12-Spalten-Raster wie Desktop; optionale layoutTablet-Werte (w, h, x, y, minH) werden mit layout gemischt. |
| Desktop | ≥ 1024 px | Normales Desktop-Layout — das, was du am großen Bildschirm per Ziehen anpasst. |
Anpassen: Bearbeitungsmodus (✏️) aktivieren, beim Widget ⚙️ öffnen. Unter den Plugin-Optionen kannst du bei „Layout: Handy & Tablet“ optional Höhe / Mindesthöhe für die Handy-Ansicht sowie Tablet-Position und -Größe setzen. Felder leer lassen = für diesen Modus die Werte vom Desktop-Layout übernehmen.
Bei schmalen Bildschirmen (ca. ≤ 1024 px) rutscht die Navbar-Websuche in eine zweite Zeile in voller Breite, damit sie nicht neben Zoom und Buttons eingequetscht wird.
Plugins können optional die Prop layoutMode ('phone' | 'tablet' | 'desktop') für ihre eigene Darstellung nutzen — siehe docs/PLUGIN_DEV.md.
Einstellungen im Überblick
- Allgemein — Sprache (DE/EN), Dashboard-Titel, Navbar-Websuche, E-Mail-Badge in der Navbar, Navbar-Darstellung, Sichtbarkeit der Dashboard-Tabs, Einheitssystem (metrisch/imperial/auto)
- Benutzer — Passwort ändern, 2FA (TOTP), Kiosk / Wand-Tablet (Admin). Admins verwalten hier zusätzlich Benutzer und Plugin-Freigaben.
- Dashboards — Dashboards erstellen, bearbeiten, löschen; Tab-Sichtbarkeit pro Dashboard; Emoji oder eigenes PNG-Icon setzen
- Design — Navbar-Darstellung; Grid-Abstände; Navbar-Hintergrund (JPG/PNG + Overlay); Dashboard-Hintergrund (aus / 1 Bild / 2 Bilder nebeneinander + Overlay); Logo hochladen; Farbthema; Farben einzeln anpassen
- E-Mail — IMAP-Konten, Navbar-Badge, Abfrage-Intervall, Verbindungstest
- Protokoll — zentrales Fehlerprotokoll für Support und Fehlersuche: Filter nach Stufe, Quelle, Plugin; Download
.txt/ JSONL; Aufbewahrung 3 / 7 / 30 Tage. Jedes perregisterPlugineingebundene Plugin protokolliert Darstellungsfehler und fehlgeschlagene/api/*-Aufrufe automatisch. E-Mail nutzt dasselbe Protokoll mit Plugin-IDmail. Details: docs/LOGGING.md.
📺 Kiosk-Modus (Wand-Tablet)
Öffentliche Nur-Ansicht für ein Wand-Tablet oder einen Gast-Browser — getrennt vom normalen Dashboard mit Login. Ideal für Küchendisplay, Wand-Tablet oder einen gemeinsamen Bildschirm im LAN.
| Thema | Details |
|---|---|
| Anzeige-URL | http://DEINE-IP:3000/kiosk — kein Admin-Login, Widgets im Vollbild, keine Navbar |
| Einrichten (Admin) | Einstellungen → Benutzer → Kiosk / Wand-Tablet — aktivieren, Dashboard wählen, optional Passwort, Sitzungsdauer (2 Std. … unbegrenzt) |
| Widgets bearbeiten | Als Admin einloggen → /dashboard/<id> (z. B. /dashboard/kiosk) → Bearbeitungsmodus — wie bei jedem Dashboard |
| Nicht verwechseln | /kiosk = nur Anzeige · /dashboard/kiosk = Bearbeiten mit Login |
| Plugins | Nur Widgets vom gewählten Kiosk-Dashboard werden geladen (funktioniert in jedem Browser, ohne SelfDashboard-Konto, wenn kein Passwort gesetzt ist) |
| HTTP / LAN | Cookies funktionieren standardmäßig auch per HTTP; SELFDASHBOARD_SECURE_COOKIES=1 nur hinter HTTPS |
📱 Android-App
Die SelfDashboard Android-App zeigt das Dashboard bildschirmfüllend auf Wand-Tablets. Sie enthält keinen eigenen Backend-Code — sie zeigt nur deine SelfDashboard-Web-App an.
| Thema | Details |
|---|---|
| Modi | Login-Modus (normales Dashboard mit Login) oder Kiosk-Modus (nur Ansicht, kein Login) |
| Download (APK) | github.com/s3lfcod3r/selfdashboard/releases/latest — aktuell v1.0.4 (App-Version, getrennt von der Dashboard-Version 2.2.0) |
| Funktionen | WebView, Pull-to-Refresh, Vollbild, Bildschirmschoner |
🔐 Login & Mehrbenutzer
SelfDashboard verlangt eine Anmeldung. Beim ersten Start (noch kein Benutzer) landest du auf /setup und legst das Admin-Konto an. Ein vorhandenes dashboard.json im Appdata-Ordner wird automatisch diesem Admin zugeordnet (Sicherung: dashboard.json.pre-auth-migrated).
| Thema | Details |
|---|---|
| Rollen | admin — alles, Plugin-Store, Benutzerverwaltung · user — nur freigegebene Plugins |
| Benutzerdaten | /app/data/users/<id>/dashboard.json pro Benutzer |
| Anmeldedaten | /app/data/auth/auth.db (Benutzer, Sitzungen, Plugin-Freigaben) |
| Admin-Bereich | Einstellungen → Benutzer — Benutzer anlegen/löschen, Passwörter zurücksetzen, Plugin-Häkchen, Kiosk-Einstellungen |
| Selbst verwalten | Einstellungen → Benutzer — Passwort ändern, 2FA (TOTP) einschalten |
| 2FA | Optional Authenticator-App beim Login — einrichten unter Einstellungen → Benutzer |
| Passwort vergessen (ohne E-Mail) | Reset per Umgebungsvariable: SELFDASHBOARD_AUTH_RESET_PASSWORD → Neustart (siehe unten) |
| Backup | Den ganzen Ordner /app/data sichern (mindestens auth/ + users/) |
| Nur Entwicklung | SELFDASHBOARD_AUTH_DISABLED=1 schaltet die Anmeldung ab (nie im Produktivbetrieb) |
Einrichtung — Admin ausgesperrt (Passwort vergessen)
Es gibt keinen E-Mail-Reset (bräuchte SMTP — im Homelab unüblich). Am einfachsten auf Unraid per Umgebungsvariable:
Passwort per Umgebungsvariable (empfohlen auf Unraid) — Container bearbeiten, Variable setzen:
SELFDASHBOARD_AUTH_RESET_PASSWORD= neues Passwort (mind. 8 Zeichen)- optional:
SELFDASHBOARD_AUTH_RESET_USER=admin(Standard: erster Admin) - oder kombiniert:
SELFDASHBOARD_AUTH_RESET=admin:NeuesPasswort - im Produktivbetrieb zusätzlich
SELFDASHBOARD_ENABLE_ENV_RESET=1(siehe Konfiguration) - Container neu starten → einloggen → Variable(n) leeren → erneut starten
Direkt per Kommandozeile (Shell-Zugang):
docker exec selfdashboard node /app/scripts/auth-reset-password.mjs --username admin --password 'NeuesPasswort'Zweiter Admin — Passwort unter Einstellungen → Benutzer zurücksetzen.
🩺 Fehlerbehebung
Probleme & Lösungen
| Problem | Lösung |
|---|---|
| Dashboard lädt nicht | Logs prüfen: docker logs selfdashboard |
| Dashboard / Widgets laden langsam | Erst messen: Browser-Konsole (F12) ~10 s nach dem Laden → copy(__sdPerfReport.text) zeigt die Renderzeit pro Widget und was den Browser blockiert; serverseitig zeigt docker logs selfdashboard 2>&1 | grep timing langsame Plugin-Anfragen (handler = der Dienst hinter dem Plugin) und nicht erreichbare Hosts ([upstream]). Widgets von dauerhaft ausgeschalteten Geräten kosten nach jedem Neustart einmal ~3 s — entfernen. Siehe docs/PLUGIN_PERFORMANCE.md |
Plugin / E-Mail scheitert mit blocked_url / private_ip_blocked |
Der Zieldienst läuft auf einer privaten LAN-IP (z. B. 192.168.x), die seit 07/2026 standardmäßig blockiert ist. SELFDASHBOARD_ALLOW_PRIVATE_URLS=1 am Container ergänzen und ihn neu erstellen. Betrifft AdGuard, Pi-hole, FRITZ!, SelfMailer und jeden anderen Dienst im LAN. |
500-Fehler nach Update (SQLITE_READONLY im Log) |
Der Container läuft ohne Root (PUID/PGID). Der Entrypoint korrigiert die Volume-Rechte beim Start automatisch; bei SELFDASHBOARD_SKIP_CHOWN=1 selbst chown -R <PUID>:<PGID> auf den Appdata-Ordner ausführen. |
CrowdSec: unable to open database file (oft nach nächtlichem Backup) |
PUID/PGID des Containers auf dieselben Werte wie dein CrowdSec-Container setzen (Unraid-Standard 99/100). Dann liest SelfDashboard die crowdsec.db als Eigentümer — dauerhaft, ohne chmod. |
Plugin zeigt 401 / stats_failed / Anmeldefehler (AdGuard, Pi-hole, FRITZ!, …), obwohl die Zugangsdaten stimmen |
Der Verschlüsselungs-Schlüssel hat sich geändert. Einmalig beheben: festen SELFDASHBOARD_SECRET_KEY (langer Zufallswert) in Docker setzen, neu starten, dann das Plugin-Passwort in den Einstellungen neu eingeben und Speichern. Der Schlüssel bleibt danach gleich → läuft dauerhaft. (Bei älterem Kern-Image zusätzlich SELFDASHBOARD_CALENDAR_KEY auf denselben Wert setzen, bis du das neue :latest ziehst.) |
| Konfiguration nach Update weg | Image-Updates löschen das Appdata-Volume nicht; dein Layout liegt in /app/data/users/<userId>/dashboard.json (plus localStorage-Cache). Zeigt ein neuer Browser ein leeres Dashboard, prüfen, ob /app/data eingebunden und beschreibbar ist (siehe Unraid). |
| Plugin-Store leer / „GitHub nicht konfiguriert“ | SELFDASHBOARD_PLUGINS_GITHUB_* setzen oder die Standardwerte des offiziellen :latest-Images nutzen |
| Widget hängt bei „Plugin wird geladen…“ | Kurz warten; Plugin-Store → Plugins neu laden; Dateien unter /app/plugins/custom/<id>/widget.js prüfen |
| Update installiert, Oberfläche unverändert | Strg+F5 (hart neu laden) — der Browser speichert widget.js zwischen |
| Plugin nach Installation nicht gefunden | Mount Plugins Storage prüfen; der Ordner braucht plugin.json + widget.js (nicht index.tsx) |
| Port schon belegt | Host-Port ändern: -p 3001:3000 |
| Widgets im Bearbeitungsmodus unsichtbar | Seite neu laden |
| Theme wird nicht übernommen | Hart neu laden: Strg+Shift+R |
CrowdSec-Widget: crowdsec.db not found |
CrowdSec Data (optional) in der Unraid-Vorlage setzen (Host-Ordner mit crowdsec.db → /crowdsec-data:ro) oder das Widget entfernen, wenn du CrowdSec nicht nutzt |
CrowdSec: keine Länderflaggen / nur ?? |
GeoLite2-City.mmdb (oder Country) in den eingebundenen CrowdSec-Ordner legen oder CROWDSEC_GEOIP_PATH setzen |
| CrowdSec: Entsperren schlägt fehl | Docker Socket einbinden, Container-Namen in den Plugin-Einstellungen prüfen, Entsperren dort aktivieren |
| E-Mail-Badge rot/gelb, 0 Mails | Einstellungen → E-Mail → Passwort neu eingeben → Speichern. Festen SELFDASHBOARD_SECRET_KEY in Docker setzen. Im Protokoll nach mail filtern |
E-Mail: ENOTFOUND host:5000 |
IMAP-Host nur als IP/Name (z. B. 192.168.1.15), Port 993 extra; die Webmail-Adresse gehört ins Feld Webmail-URL |
| Test OK, Navbar leer | Navbar E-Mail einschalten (Reiter Allgemein oder E-Mail); Konto speichern; das Badge erscheint nur bei Ungelesen > 0 |
| Badge zeigt Mail, die in MailPlus schon weg ist | IMAP kann gelöschte/gelesene Mails noch auflisten, bis der Server aufräumt. Mit Ungelesen anzeigen in den E-Mail-Einstellungen die Betreffzeilen ansehen. Nach dem Update ignoriert SelfDashboard \Deleted- und \Seen-Geister. In MailPlus ggf. Papierkorb leeren, dann Alle Konten aktualisieren. |
| MailPlus zeigt 1 ungelesen, Vorschau listete 2 (alte FRITZ-Mail) | Synology-IMAP behält manchmal uralte UNSEEN-UIDs. Einstellungen → E-Mail → Altersfilter ungelesen nutzen (Standard 30 Tage; 0 = aus). Die Vorschau zeigt, wie viele als zu alt oder doppelte Message-ID ignoriert wurden. |
| Wetter: HTTP 404 auf der Plugin-API | Neues App-Image nötig — die Route liegt in der Kern-App (/api/plugins/weather/…), nicht im Volume-Plugin |
| Wetter: keine Daten / API-Fehler | Der Container muss api.open-meteo.com und geocoding-api.open-meteo.com erreichen (HTTPS nach außen). Test: http://HOST:PORT/api/plugins/weather/resolve?name=Berlin&language=de → JSON |
| Wetter-Plugin mit alter Oberfläche (nur Stunden-Leiste) | Plugin-Store → Wetter → Aktualisieren → Strg+F5 (Ziel 1.3.x) |
Unraid: Failed to fetch |
Der Browser ruft Unraid direkt auf (https://NAS/graphql). Kein reines 7.3-Problem — API-Key, URL, HTTPS-Zertifikat und CORS / erlaubte Origins für deine Dashboard-URL (z. B. http://192.168.x.x:3010) auf jedem NAS prüfen |
| Unraid läuft auf einem NAS, auf dem anderen nicht | API aktiv?, Key-Rechte?, CORS auf dem betroffenen Server vergleichen (7.2.3 und 7.3 werden beide unterstützt, wenn die GraphQL-API läuft) |
| Hintergrundbild nicht sichtbar | Design → Modus nicht Aus; Bild hochgeladen; nach Änderung Strg+F5; sehr große Bilder werden begrenzt (~4–5 MB in der Config) |
| Kiosk zeigt Login statt Widgets | /kiosk nutzen, nicht /dashboard/…. Kiosk unter Einstellungen → Benutzer → Kiosk aktivieren |
| Kiosk: „Plugin nicht gefunden“ | Einmal /kiosk als Admin öffnen (aktualisiert die Plugin-Liste), dann im Gast-Browser erneut versuchen; Strg+F5 |
Home-Dashboard kaputt nach Besuch von /kiosk |
Neuestes Image ziehen (das Kiosk-Cookie überschreibt die Admin-Sitzung nicht mehr); Strg+F5 |
📚 Dokumentation
| Thema | Datei |
|---|---|
| Plugins installieren & aktualisieren | docs/PLUGINS.md |
| Plugins entwickeln & veröffentlichen | docs/PLUGIN_DEV.md |
| Plugin-Architektur | docs/PLUGIN_ARCHITECTURE.md |
| Verteilungsmodell der Plugins | docs/PLUGIN_DISTRIBUTION.md |
| Plugins als Volume + ZIP | docs/CUSTOM_PLUGINS_VOLUME.md |
| Plugin-Performance (Entwicklung) | docs/PLUGIN_PERFORMANCE.md |
| Eingebaute Plugin-Server in Git / CI | docs/PLUGINS_IN_REPO.md |
| Docker-Image bauen | docs/DOCKER_BUILD.md |
| Anleitung pro Plugin (DE/EN) | docs/plugins/README.md |
| Aktuelle API-/Plugin-Änderungen | docs/CHANGELOG.md |
| Fehlerprotokoll | docs/LOGGING.md |
Details zur Unraid-Vorlage (NODE_TLS_REJECT_UNAUTHORIZED) |
unraid/README.md |
🚀 Schnellstart (Docker)
docker run -d \
--name selfdashboard \
--restart unless-stopped \
-p 3000:3000 \
-e TZ=Europe/Berlin \
-v /mnt/user/appdata/selfdashboard:/app/data \
-v /mnt/user/appdata/selfdashboard/plugins:/app/plugins/custom \
-v /var/run/docker.sock:/var/run/docker.sock \
ghcr.io/s3lfcod3r/selfdashboard:latest
Oder mit docker compose (siehe docker-compose.yml):
git clone https://github.com/s3lfcod3r/selfdashboard.git
cd selfdashboard
docker compose up -d
http://<host>:3000 öffnen → /setup legt das Admin-Konto an → Plugin-Store → Von GitHub die gewünschten Widgets installieren → mit + aufs Dashboard legen → Strg+F5, falls ein Widget leer bleibt.
- Pflicht:
/app/data(dashboard.json, Kalender, Protokoll) und/app/plugins/custom(installierte Plugins) einbinden. Ohne Plugin-Ordner gehen Store-Installationen beim Neustart verloren. - Optional: Docker-Socket — nur für das Docker-Plugin; CrowdSec-Mount — nur für das CrowdSec-Plugin.
- Image-Tags: die Unraid-Vorlage nutzt
ghcr.io/s3lfcod3r/selfdashboard:latest. Der Plugin-Katalog kommt vom GitHub-Branchmain(SELFDASHBOARD_PLUGINS_GITHUB_REF, normalerweise unverändert lassen). - Dienste im LAN: sprechen deine Widgets LAN-Adressen an (AdGuard, Pi-hole, FRITZ!, Home Assistant …),
SELFDASHBOARD_ALLOW_PRIVATE_URLS=1setzen.
📦 Unraid
Vorlage von
https://raw.githubusercontent.com/s3lfcod3r/selfdashboard/main/unraid/selfdashboard.xml
hinzufügen oder unter Docker → Add Container → Template importieren.
Einrichtung — Unraid Community Apps (empfohlen)
- Community Apps öffnen → nach SelfDashboard suchen
- Installieren — Config Storage, Plugins Storage und Port (Standard
3000) setzen http://DEINE-IP:3000öffnen- Plugin-Store → Von GitHub — benötigte Widgets installieren (Kalender, Lesezeichen, …)
- Mit + Widgets aufs Dashboard legen → Strg+F5, falls ein Widget leer bleibt
| Mount / Einstellung | Inhalt |
|---|---|
/app/data (Config Storage) |
Dashboards pro Benutzer (users/), Anmelde-DB (auth/), Kalender, zentrales Protokoll — regelmäßig sichern |
/app/plugins/custom (Plugins Storage) |
Installierte Plugins (<id>/plugin.json, widget.js, optional server.mjs) — mit Appdata sichern |
| GitHub-Variablen | Im :latest-Image voreingestellt: Repo s3lfcod3r/selfdashboard, Ref main, Pfad plugins-pack |
| Docker Socket (optional) | Nur lokaler Host — Docker-Plugin |
| CrowdSec Data (optional) | crowdsec.db nur lesend — CrowdSec-Plugin |
Config Storage und Plugins Storage sind für den Normalbetrieb beide nötig. Nach einem Plugin-Update: Store → Aktualisieren → Strg+F5. Nach einem App-Update: neues Image ziehen, neu starten — Layouts und installierte Plugins bleiben auf den Volumes.
⚠️ Geheimschlüssel: festen
SELFDASHBOARD_SECRET_KEYsetzen und danach nie ändern — er verschlüsselt alle gespeicherten Zugangsdaten. Eine Änderung macht sie unlesbar.⚠️ Rechte: der Container läuft ohne Root. Die Vorlage setzt PUID/PGID 99/100 (
nobody:users); beim Start passt der Entrypoint auf deine PUID/PGID an und setzt den Besitzer von/app/data+/app/plugins/customautomatisch (abschaltbar mitSELFDASHBOARD_SKIP_CHOWN=1). CrowdSec-Tipp: PUID/PGID auf dieselben Werte wie dein CrowdSec-Container setzen — dann besitzt und liest SelfDashboard diecrowdsec.dbdirekt, auch nach nächtlichen Backups, die CrowdSec neu starten (kein chmod nötig).⚠️ LAN-Zugriff: die Vorlage setzt
SELFDASHBOARD_ALLOW_PRIVATE_URLS=1bereits (im Heimnetz empfohlen), damit Widgets Dienste im LAN erreichen.⚠️ Selbstsigniertes HTTPS:
NODE_TLS_REJECT_UNAUTHORIZEDleer lassen;0schaltet die Zertifikatsprüfung für alle ausgehenden HTTPS-Verbindungen ab. Details: unraid/README.md.
⚙️ Konfiguration
Umgebungsvariablen, meist mit dem Präfix SELFDASHBOARD_, dazu einige Laufzeit- und Plugin-Variablen.
| Variable | Pflicht | Standard | Zweck |
|---|---|---|---|
TZ |
– | Europe/Berlin |
Zeitzone |
NODE_ENV |
– | production |
Node.js-Umgebung |
PUID / PGID |
– | 1001 (Image), 99 / 100 (Unraid-Vorlage) |
Benutzer/Gruppe, unter der die App läuft; der Entrypoint passt an und setzt den Besitzer der Volumes |
SELFDASHBOARD_SKIP_CHOWN |
– | 0 |
1 = Besitzer der Volumes beim Start nie anfassen |
SELFDASHBOARD_FIX_CROWDSEC_PERMS |
– | 1 |
0 = keine Leserechte auf /crowdsec-data ergänzen |
SELFDASHBOARD_DATA_DIR |
– | /app/data (im offiziellen Image) |
Verzeichnis im Container für dashboard.json. Muss zum /app/data-Mount passen, außer du nutzt bewusst einen anderen Pfad. |
SELFDASHBOARD_SECRET_KEY |
– | automatisch erzeugte Datei im Data-Ordner | Zentraler Schlüssel für alle gespeicherten Zugangsdaten: Kalender, E-Mail und Widget-Passwörter/-Tokens (AdGuard, Pi-hole, FRITZ!, Speedtest, …). Dringend empfohlen: festen Wert setzen, damit Zugangsdaten Image-Updates und Volume-Umzüge überleben. Einmal gesetzt, nie mehr ändern. (Alter Name SELFDASHBOARD_CALENDAR_KEY funktioniert weiter als Rückfall.) |
SELFDASHBOARD_ALLOW_PRIVATE_URLS |
– | aus (private IPs blockiert); 1 in der Unraid-Vorlage |
1 = Plugins dürfen private/LAN-IPs erreichen (10/8, 172.16/12, 192.168/16). Seit 07/2026 sind private Ziele standardmäßig blockiert (SSRF-Schutz). Wer AdGuard, Pi-hole, FRITZ!, SelfMailer, Home Assistant … über LAN-Adressen einbindet, muss dies auf 1 setzen — sonst scheitern diese Widgets mit private_ip_blocked / blocked_url. (Das alte SELFDASHBOARD_BLOCK_PRIVATE_CALENDAR_URLS wird nicht mehr gebraucht.) |
SELFDASHBOARD_SECURE_COOKIES |
– | aus | 1 = Sitzungs-/Kiosk-Cookies nur per HTTPS (Secure). Standard aus, damit HTTP im LAN funktioniert. Bei Betrieb über HTTPS auf 1 setzen. |
SELFDASHBOARD_INSECURE_COOKIES |
– | – | 1 = ausdrücklich Cookies ohne Secure (wie Standard bei HTTP) |
SELFDASHBOARD_TRUST_PROXY |
– | aus | Nur auf 1 setzen, wenn ein Reverse-Proxy davor X-Forwarded-For/X-Real-IP setzt. Sonst werden diese (vom Client fälschbaren) Header beim Rate-Limiting ignoriert. Der Brute-Force-Schutz pro Konto wirkt unabhängig davon (dauerhafte Konto-Sperre). |
SELFDASHBOARD_AUTH_RESET_PASSWORD |
– | – | Einmaliger Admin-Passwort-Reset beim Container-Start (siehe Login & Mehrbenutzer) |
SELFDASHBOARD_AUTH_RESET_USER |
– | erster Admin | Benutzer für den Passwort-Reset per Umgebungsvariable |
SELFDASHBOARD_AUTH_RESET |
– | – | Kombinierte Form benutzer:passwort für den Passwort-Reset |
SELFDASHBOARD_ENABLE_ENV_RESET |
– | aus | Im Produktivbetrieb (NODE_ENV=production, Standard im offiziellen Image) wird der Passwort-Reset per Umgebungsvariable ignoriert, außer dies steht auf 1. Schutznetz, falls NODE_ENV vergessen wurde. |
SELFDASHBOARD_AUTH_DISABLED |
– | – | 1 schaltet die Anmeldung ab — nur Entwicklung, nie im Produktivbetrieb |
SELFDASHBOARD_PLUGINS_CUSTOM |
– | <app>/plugins/custom |
Installierte Plugins (Unraid: Host-Ordner hierher einbinden) |
SELFDASHBOARD_PLUGINS_GITHUB_REPO |
– | s3lfcod3r/selfdashboard im :latest-Image |
GitHub-Repo für den Store (owner/repo) |
SELFDASHBOARD_PLUGINS_GITHUB_REF |
– | main |
Branch/Tag für plugins-pack/ |
SELFDASHBOARD_PLUGINS_GITHUB_PATH |
– | plugins-pack |
Pfad im Repo zu den Plugin-Dateien |
MAIL_DATA_DIR |
– | <plugins/custom>/mail |
Verzeichnis für mail.json (optional) |
CALENDAR_SYNC_INTERVAL_SECONDS |
– | 300 |
Intervall des Kalender-Abgleichs im Hintergrund |
CROWDSEC_DATA_DIR |
– | /crowdsec-data |
Erlaubtes Wurzelverzeichnis für DB-Pfade (nur CrowdSec-Widget) |
CROWDSEC_GEOIP_PATH |
– | – | Voller Pfad zu GeoLite2-*.mmdb, falls nicht im Data-Ordner |
CROWDSEC_DB_PATH |
– | – | Standard-DB-Datei, wenn im Widget kein Pfad gesetzt ist |
CROWDSEC_CONTAINER |
– | crowdsec |
Docker-Container-Name für optionales Entsperren per cscli |
NODE_TLS_REJECT_UNAUTHORIZED |
– | leer | 0 schaltet die Zertifikatsprüfung für alle ausgehenden HTTPS-Verbindungen ab — nur für selbstsignierte Homelab-Zertifikate; siehe unraid/README.md |
SELFDASHBOARD_PLUGIN_READ_CACHE |
– | an | 0 schaltet den zentralen Lese-Cache für Plugin-APIs ab (Plugins melden sich per readCache in ihrer plugin.json an) |
SELFDASHBOARD_HOST_DOWN_MS |
– | an | 0 schaltet den Offline-Merker ab (nicht erreichbare LAN-Hosts werden sofort beantwortet statt jedes Mal ~3 s zu warten) |
SELFDASHBOARD_STALE_MAX_MS |
– | je Cache | Globales Höchstalter (ms) für ältere Plugin-Daten, die während des Auffrischens im Hintergrund ausgeliefert werden; 0 = nur frische Daten |
SELFDASHBOARD_TIMING_LOG |
– | aus | 1 protokolliert jede Plugin-Anfrage mit Server-Timing (sonst nur langsame) |
SELFDASHBOARD_TIMING_SLOW_MS |
– | 500 |
Plugin-Anfragen, die länger dauern (ms), werden immer protokolliert |
💾 Backups
Beide Host-Ordner regelmäßig sichern — am besten offline / unveränderbar, damit Ransomware auf dem Mount nicht Daten und Schlüssel erwischt:
/app/data— Dashboards pro Benutzer (users/), aus Widget-Einstellungen ausgelagerte Bilder (blobs/, z. B. Bookmark-Icons), Anmelde-DB (auth/auth.db), Kalender, zentrales Protokoll und die automatisch erzeugten Schlüsseldateien (.calendar-key,.secret-salt)/app/plugins/custom— installierte Plugins
Bewahre außerdem deinen SELFDASHBOARD_SECRET_KEY im Passwort-Manager auf — ohne ihn lassen sich gespeicherte Zugangsdaten nicht mehr entschlüsseln.
Wiederherstellen — Container stoppen, die Sicherung zurück in die eingebundenen Ordner kopieren, wieder starten:
docker stop selfdashboard
cp -a /path/to/backup/selfdashboard/. /mnt/user/appdata/selfdashboard/
docker start selfdashboard
🛡️ Sicherheit
SelfDashboard ist für ein vertrauenswürdiges Heimnetz gebaut. Eine Sicherheitsprüfung (06/2026) hat Anmeldung und Plugin-Schnittstellen gehärtet; die folgenden Punkte zählen, sobald du die App über das LAN hinaus erreichbar machst.
Im Code gehärtet
- Login-Brute-Force: Fehlversuche werden dauerhaft pro Konto in SQLite gezählt (10 / 15 Min → vorübergehende Sperre) — übersteht Neustarts, unabhängig von der Client-IP, ein gefälschter
X-Forwarded-For-Header umgeht es nicht - Fälschbare Proxy-Header werden ignoriert, außer
SELFDASHBOARD_TRUST_PROXY=1 - Admin-Aktionen verlangen abgeschlossene MFA: Benutzer-/Rollen-/Plugin-Verwaltung ist für Sitzungen ohne zweiten Faktor gesperrt
- Rate-Limits für Passwort ändern und TOTP abschalten; TOTP-Replay-Schutz (jeder Code gilt nur einmal)
- TOTP-Geheimnisse verschlüsselt gespeichert (AES-256-GCM über
SELFDASHBOARD_SECRET_KEY) — eine abgeflosseneauth.dballein erzeugt keine gültigen 2FA-Codes - Zugangsdaten verschlüsselt — Kalender-, Mail- und Widget-Passwörter/-Tokens mit AES-256-GCM versiegelt; der Browser sieht nur Geheimtext
- Eigener Salt pro Installation — die Schlüsselableitung nutzt einen Zufalls-Salt, den jede Installation einmalig in
/app/data/.secret-salterzeugt (keine Umgebungsvariable); im Backup mitsichern - Docker-Container-Aktionen (Start/Stopp/Neustart) verlangen einen Admin mit abgeschlossener MFA — die reine Liste bleibt für Widget-Nutzer sichtbar
- Entpacken von Plugin-Paketen prüft jeden Zip-Eintrag gegen Path-Traversal (Zip-Slip) und begrenzt die Anzahl der Einträge
- Plugin-SVG-Dateien werden mit
Content-Disposition: attachment,X-Content-Type-Options: nosniffund strenger CSP ausgeliefert (kein gespeichertes XSS über SVGs) - Integrität von Remote-Plugins: liefert
plugins-index.jsoneinensha256pro Datei, wird jede heruntergeladene Datei (inkl. ausführbarerserver.mjs) vor dem Schreiben geprüft - Interne Identitäts-Header (
x-sd-user-id/x-sd-role) werden aus Client-Anfragen entfernt und nicht in Antworten zurückgegeben - Passwort-Reset per Umgebungsvariable wird im Produktivbetrieb ignoriert, außer
SELFDASHBOARD_ENABLE_ENV_RESET=1 - SSRF-Schutz bei allen ausgehenden Anfragen: Loopback / Link-Local / Cloud-Metadaten immer blockiert, private/LAN-IPs standardmäßig blockiert (Freigabe mit
SELFDASHBOARD_ALLOW_PRIVATE_URLS=1); CalDAV prüft die aufgelöste IP vor dem Verbinden erneut (Schutz gegen DNS-Rebinding), wie IMAP/FRITZ! - Container ohne Root, reproduzierbarer
npm ci-Build, Container-HEALTHCHECK
Deine Aufgaben als Betreiber / bei öffentlicher Erreichbarkeit
- HTTPS nutzen und
SELFDASHBOARD_SECURE_COOKIES=1setzen — über das Internet müssen Sitzungs-Cookies Secure sein - Interne Header am Reverse-Proxy entfernen: eingehende
x-sd-user-id-,x-sd-role- undx-sd-kiosk-Header verwerfen (zusätzliche Absicherung) - TLS-Prüfung für IMAP/FRITZ! lässt sich pro Verbindung abschalten — lass sie an, außer es gibt einen konkreten Grund
- Ein starkes Admin-Passwort und einen festen
SELFDASHBOARD_SECRET_KEYnutzen - Docker-Socket = Root-Zugriff auf den Host — nur für vertrauenswürdige Admins einbinden und nie nach außen freigeben; nur lesend schützt nicht
:latest+ Watchtower (Label indocker-compose.yml) spielt neue Images ohne menschliche Freigabe ein — für diesen mächtigen Container besser eine feste Version pinnen und das Label entfernen
Bewusste Kompromisse (dokumentiert)
- Plugin-Code läuft mit vollen Server-Rechten — hochgeladene/Remote-
server.mjs-Dateien laufen ohne Sandbox im Node-Prozess. Installiere nur vertrauenswürdige Plugins und behandle das Admin-Konto wie Shell-Zugriff. - Secure-Cookies sind standardmäßig aus, damit reine HTTP-Setups im LAN funktionieren
- Bekannte nachrangige Punkte:
script-srcerlaubt noch'unsafe-inline' 'unsafe-eval'; DNS-Rebinding/TOCTOU bei allgemeinen ausgehenden Anfragen bräuchte Connection-Pinning
Verlauf der Sicherheitsupdates → CHANGELOG.md (Einträge mit 🔒).
🧱 Tech-Stack
| Teil | Technik |
|---|---|
| Frontend | Next.js 15 · React 18 · Tailwind CSS · react-grid-layout |
| Zustand | Zustand — gespeichert im localStorage (Cache) und in dashboard.json auf dem Server, sobald /app/data (bzw. SELFDASHBOARD_DATA_DIR) verfügbar ist |
| Server | Next.js-API-Routen · better-sqlite3 (Anmeldung) · imapflow (Mail) |
| Plugins | Nur per Volume — dynamisches Laden von widget.js + pluginRegistry · Katalog von GitHub plugins-pack/ |
| Tests | Vitest · ESLint |
| Deploy | Docker (Multi-Stage, Node.js 22 Alpine, Next.js standalone, ohne Root) · GHCR · Unraid |
🛠️ Entwicklung
npm ci
npm run dev # Next.js-Entwicklungsserver im Repo-Ordner
npm run lint # ESLint
npm run build # Produktions-Build (bindet vorher die eingebauten Plugins ein)
npm run publish:plugin-pack # plugins-pack/ für den Store bauen
npm run generate:plugins-index # plugins-pack/plugins-index.json neu erzeugen
Tests:
npm run test
Docker-Image bauen: docs/DOCKER_BUILD.md · Plugins entwickeln: docs/PLUGIN_DEV.md.
🗺️ Roadmap
- Plugin-System nur per Volume · GitHub-Plugin-Store · ZIP-Upload · automatisch erzeugter Index
- Mehrere Dashboards · 6 Themes · Hintergrundbilder · responsives Handy/Tablet/Desktop-Layout
- Login · Mehrbenutzer · TOTP-2FA · Kiosk-Modus
- Container ohne Root · AES-256-GCM-Zugangsdaten · SSRF-Schutz (private IPs standardmäßig blockiert)
- Zentrales Fehlerprotokoll
- Vitest-Testgerüst mit ersten SSRF-Tests
- Plugin-Sandbox (Plugin-Server-Code läuft derzeit mit den Rechten der App)
- Nonce-basierte CSP statt
'unsafe-inline' 'unsafe-eval' - Connection-Pinning gegen DNS-Rebinding bei ausgehenden Anfragen
- Beta-Plugins gegen weitere Server-Versionen testen
⚖️ Lizenz / License
🇩🇪 Alle Rechte vorbehalten. © 2026 s3lfcod3r / SelfCoder
Du darfst die Software privat und nicht-kommerziell installieren und benutzen (z. B. im Homelab, über Docker oder Unraid).
Ohne schriftliche Erlaubnis verboten: kommerzielle Nutzung · Kopieren · Verändern · Weitergeben · Einbauen in eigene Projekte (auch Closed Source) · Verkaufen.
Details: LICENSE
🇬🇧 All rights reserved. © 2026 s3lfcod3r / SelfCoder
You may install and use the software privately and non-commercially (e.g. in your home lab, via Docker or Unraid).
Not permitted without written permission: commercial use · copying · modifying · redistributing · incorporating into other projects (including closed source) · selling.
Details: LICENSE
SelfDashboard · part of the Self family · Teil der Self-Familie
made with 🖥️ for self-hosting
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/s3lfcod3r/selfdashboard:latestRuntime arguments
- Web UI
http://[IP]:[PORT:3000]- Network
bridge- Shell
sh- Privileged
- false
- Extra Params
--group-add=281
Template configuration
Port der Weboberfläche.
- Target
- 3000
- Default
- 3000
- Value
- 3000
Zeitzone, z. B. Europe/Berlin
- Target
- TZ
- Default
- Europe/Berlin
- Value
- Europe/Berlin
App-Daten (/app/data): pro User dashboard.json unter users/, ausgelagerte Bilder aus Widget-Einstellungen unter blobs/, Auth unter auth/auth.db, Kalender, Logs, Schlüsseldateien (.calendar-key, .secret-salt). Backup dieses Host-Ordners empfohlen (inkl. blobs/). Optional: SELFDASHBOARD_DATA_DIR überschreibt den Pfad im Container.
- Target
- /app/data
- Default
- /mnt/user/appdata/selfdashboard
- Value
- /mnt/user/appdata/selfdashboard
Pflicht für Plugin-Verteilung: Host → /app/plugins/custom. Pro Plugin plugin.json und widget.js (Store „Von GitHub“ oder ZIP); API-Plugins zusätzlich server.mjs vom Store. Image-API nur Fallback. Nach Update: Strg+F5.
- Target
- /app/plugins/custom
- Default
- /mnt/user/appdata/selfdashboard/plugins
- Value
- /mnt/user/appdata/selfdashboard/plugins
User-ID, unter der die App läuft. Setze sie auf DENSELBEN Wert wie dein CrowdSec-Container (Unraid-Standard 99 = nobody), damit SelfDashboard die crowdsec.db direkt lesen kann — auch nach nächtlichen Backups. Ohne CrowdSec einfach 99 lassen.
- Default
- 99
- Value
- 99
Gruppen-ID, unter der die App läuft (Unraid-Standard 100 = users). Wie bei PUID: passend zu CrowdSec setzen.
- Default
- 100
- Value
- 100
EMPFOHLEN — fester Schlüssel für ALLE gespeicherten Zugangsdaten (Kalender, E-Mail, Widget-Passwörter wie AdGuard/Pi-hole/FRITZ!/Speedtest). Beliebiger langer Zufallsstring (30+ Zeichen). Ohne ihn hängt die Verschlüsselung an einer Datei im Volume und kann bei Image-Updates verloren gehen. WICHTIG: einmal setzen, NIE mehr ändern — sonst werden gespeicherte Passwörter unlesbar (dann neu eintragen).
- Target
- SELFDASHBOARD_SECRET_KEY
GitHub-Repository für den Plugin-Store (owner/repo). Lädt plugins-pack/plugins-index.json.
- Target
- SELFDASHBOARD_PLUGINS_GITHUB_REPO
- Default
- s3lfcod3r/selfdashboard
- Value
- s3lfcod3r/selfdashboard
GitHub-Branch oder Tag mit dem Plugin-Katalog (Standard: main). Muss plugins-pack/ mit plugins-index.json enthalten. Normalerweise nicht ändern.
- Target
- SELFDASHBOARD_PLUGINS_GITHUB_REF
- Default
- main
- Value
- main
Ordner im Repo mit Plugin-Dateien (Standard: plugins-pack).
- Target
- SELFDASHBOARD_PLUGINS_GITHUB_PATH
- Default
- plugins-pack
- Value
- plugins-pack
OPTIONAL — leer lassen ohne CrowdSec-Widget. z. B. /mnt/user/appdata/crowdsec/data → /crowdsec-data (read-only). crowdsec.db; optional GeoLite2-*.mmdb. Entsperren: Docker-Socket + Plugin-Einstellung.
- Target
- /crowdsec-data
Optional für Docker-Widget (nur dieser Host). Bei EACCES: --group-add=281 in Extra Parameters anpassen (GID mit stat -c '%g' /var/run/docker.sock prüfen).
- Target
- /var/run/docker.sock
- Default
- /var/run/docker.sock
- Value
- /var/run/docker.sock
OPTIONAL — Admin-Passwort per Env zurücksetzen (wenn vergessen). Neues Passwort setzen (min. 8 Zeichen) UND „Env-Reset erlauben“ auf 1 setzen (sonst wird der Reset bei NODE_ENV=production ignoriert), Container neu starten, einloggen, dann BEIDE Variablen LEEREN und erneut starten. Optional SELFDASHBOARD_AUTH_RESET_USER=admin (sonst erster Admin). Alternative: SELFDASHBOARD_AUTH_RESET=admin:NeuesPasswort
- Target
- SELFDASHBOARD_AUTH_RESET_PASSWORD
OPTIONAL — Benutzername für Passwort-Reset (mit SELFDASHBOARD_AUTH_RESET_PASSWORD). Leer = erster Admin.
- Target
- SELFDASHBOARD_AUTH_RESET_USER
OPTIONAL — nur zusammen mit dem Passwort-Reset oben auf 1 setzen. Im Produktivbetrieb (NODE_ENV=production) wird der Env-Reset sonst bewusst ignoriert. Nach dem Reset wieder leeren.
- Target
- SELFDASHBOARD_ENABLE_ENV_RESET
Normalerweise production.
- Target
- NODE_ENV
- Default
- production
- Value
- production
Wofür: HTTPS aus dem Container (CalDAV, Fritzbox, Pi-hole, Plugin-Store, Wetter, …). Standard (leer): Zertifikate prüfen — empfohlen. Nur 0 bei Zertifikatsfehlern auf internen https://-URLs (self-signed). Dann gilt für alle HTTPS-Aufrufe — unsicher. Nicht nötig für Open-Meteo/GitHub. Besser: gültiges Zertifikat oder eigene CA.
- Target
- NODE_TLS_REJECT_UNAUTHORIZED
Wofür: Plugins/Widgets dürfen Dienste auf privaten LAN-IPs (192.168.x, 10.x, 172.16-31.x) erreichen — z. B. AdGuard, Pi-hole, FRITZ!, SelfMailer, Home Assistant. Seit 07/2026 sind private Ziele aus Sicherheitsgründen (SSRF-Schutz gegen bösartige Kalender-/iframe-URLs) standardmäßig blockiert. Im Heimnetz auf 1 lassen — sonst scheitern LAN-Widgets mit 'private_ip_blocked'/'blocked_url'. Leeren oder 0 = strikt blockieren (nur öffentliche Adressen).
- Target
- SELFDASHBOARD_ALLOW_PRIVATE_URLS
- Default
- 1
- Value
- 1
Auf 1 setzen, sobald das Dashboard über HTTPS erreichbar ist (z. B. hinter einem Reverse-Proxy). Dann werden Sitzungs-Cookies nur noch über HTTPS gesendet. Leer = auch HTTP im LAN funktioniert.
- Target
- SELFDASHBOARD_SECURE_COOKIES
Nur auf 1 setzen, wenn ein Reverse-Proxy davor X-Forwarded-For / X-Real-IP setzt (für die IP-Ratenbegrenzung). Ohne Proxy leer lassen — diese Header kann sonst jeder Client fälschen. Der Schutz gegen Passwort-Raten pro Konto wirkt unabhängig davon.
- Target
- SELFDASHBOARD_TRUST_PROXY
Zentraler Lese-Cache für Plugin-APIs (seit 10/2026): Lese-Anfragen werden in höchstens ~300 ms beantwortet, notfalls mit der letzten Antwort, während im Hintergrund neu geladen wird. Gilt nur für Plugins, die das in ihrer plugin.json freigeben; Aktionen werden nie gecacht. 0 = aus (zur Fehlersuche).
- Target
- SELFDASHBOARD_PLUGIN_READ_CACHE
- Default
- 1
- Value
- 1
Seit 10/2026: Ist ein LAN-Gerät nicht erreichbar, antworten Widgets sofort statt jedes Mal ~3 s zu warten; alle 15 s wird im Hintergrund geprüft, ob es wieder da ist. 0 = aus.
- Target
- SELFDASHBOARD_HOST_DOWN_MS
- Default
- 1
- Value
- 1
OPTIONAL — wie alt zwischengespeicherte Plugin-Daten höchstens sein dürfen, die sofort gezeigt werden, während neu geladen wird. Leer = Standard je Plugin (z. B. 10 Minuten). 0 = nur frische Daten (langsamer).
- Target
- SELFDASHBOARD_STALE_MAX_MS
OPTIONAL — 1 schreibt jede Plugin-Anfrage mit ihrer Dauer ins Container-Log (zur Fehlersuche). Leer = nur langsame Anfragen.
- Target
- SELFDASHBOARD_TIMING_LOG
Plugin-Anfragen, die länger dauern, landen immer im Container-Log.
- Target
- SELFDASHBOARD_TIMING_SLOW_MS
- Default
- 500
- Value
- 500
OPTIONAL — 1 = beim Start die Besitzer von /app/data und /app/plugins/custom nicht auf PUID/PGID setzen.
- Target
- SELFDASHBOARD_SKIP_CHOWN
OPTIONAL — 0 = beim Start keine Leserechte auf /crowdsec-data ergänzen. Leer = Standard (Leserechte ergänzen).
- Target
- SELFDASHBOARD_FIX_CROWDSEC_PERMS