Files
Dashboard/README.md
T
Syco c1e75f2b19
ci/woodpecker/push/woodpecker Pipeline was successful
Add README
2026-05-16 16:44:45 +02:00

248 lines
6.2 KiB
Markdown

# syco.me — Homelab Dashboard
A personal homelab dashboard built with React + TypeScript on the frontend and an Express proxy server on the backend. Deployed via Woodpecker CI to a Proxmox LXC container.
---
## Features
- **Dashboard** — live widgets for all homelab services
- **Apps** — icon grid of all self-hosted apps with local icons (no CDN)
- **Home** — mobile-optimised page with weather and public transit departures
- **Responsive** — desktop defaults to Dashboard, mobile defaults to Home
- **Collapsible sections** — click any section label to fold it away
- **Header** — live clock, weather summary, and navigation tabs
---
## Stack
| Layer | Technology |
|---|---|
| Frontend | React 18, TypeScript, Vite |
| Backend | Node.js, Express |
| Routing | React Router v6 |
| Fonts | Syne, JetBrains Mono (Google Fonts) |
| CI/CD | Woodpecker CI |
| Deployment | Docker on Proxmox LXC |
---
## Widgets
### Infrastructure
| Widget | Service | API |
|---|---|---|
| Proxmox | Proxmox VE | REST API (API Token) |
| Synology NAS | DSM | Synology Web API |
| AdGuard Home | AdGuard | REST API (Basic Auth) |
| Headscale | Headscale VPN | REST API (API Key) |
| FritzBox | AVM FRITZ!Box | TR-064 SOAP API |
### Media
| Widget | Service | API |
|---|---|---|
| Jellyfin | Jellyfin | REST API (API Key) |
| Navidrome | Navidrome | Subsonic API |
| RomM | RomM | REST API |
| Arr Calendar | Sonarr + Radarr | REST API |
| Arr Stats | Sonarr + Radarr + Lidarr | REST API |
| qBittorrent | qBittorrent | Web API |
### Monitoring
| Widget | Service | API |
|---|---|---|
| Uptime Kuma | Kuma | REST API |
| CrowdSec | CrowdSec LAPI | REST API (Bouncer Key) |
| Grafana | Grafana | REST API |
| Prometheus | Prometheus | REST API |
| Loki | Loki | REST API |
### Access
| Widget | Service | API |
|---|---|---|
| Authentik | Authentik | REST API (API Token) |
| Vaultwarden | Vaultwarden | Admin API |
### Home (mobile)
| Widget | Source |
|---|---|
| Weather | [wttr.in](https://wttr.in) — no API key needed |
| Transit | [VAG PULS API](https://start.vag.de/dm/api/) — no API key needed |
---
## Project Structure
```
├── server/
│ ├── index.ts # Express server + route registration
│ └── routes/ # One file per service proxy
├── src/
│ ├── components/
│ │ ├── Header.tsx # Nav, clock, weather summary
│ │ ├── AppsSection.tsx # Icon tile grid
│ │ └── widgets/ # One component per dashboard widget
│ ├── config/
│ │ ├── apps.ts # App links + icon paths (edit order here)
│ │ └── dashboard.ts # Dashboard sections + widget order (edit order here)
│ ├── hooks/
│ │ └── useIsMobile.ts
│ ├── pages/
│ │ ├── AppsPage.tsx
│ │ └── MobileHome.tsx # Weather + transit for mobile
│ └── App.tsx # Routing
├── public/
│ └── icons/ # All icons stored locally
├── Dockerfile
└── .woodpecker.yml
```
> **To change widget/app order**: edit `src/config/dashboard.ts` (widgets) or `src/config/apps.ts` (app tiles) — no need to touch `App.tsx`.
---
## Environment Variables
Copy `.env.example` to `.env` and fill in your values.
```env
# Proxmox VE
PROXMOX_HOST=https://192.168.178.x:8006
PROXMOX_TOKEN=PVEAPIToken=user@realm!tokenid=...
# Synology DSM
SYNOLOGY_HOST=http://192.168.178.x:5000
SYNOLOGY_USER=...
SYNOLOGY_PASSWORD=...
# AdGuard Home
ADGUARD_HOST=http://192.168.178.x
ADGUARD_USER=...
ADGUARD_PASSWORD=...
# CrowdSec
CROWDSEC_HOST=http://192.168.178.x:8080
CROWDSEC_API_KEY=...
# Headscale
HEADSCALE_HOST=http://192.168.178.x:8085
HEADSCALE_API_KEY=...
# FRITZ!Box
FRITZBOX_HOST=http://192.168.178.1
# Uptime Kuma
KUMA_HOST=http://192.168.178.x:3001
KUMA_USER=...
KUMA_PASSWORD=...
# Authentik
AUTHENTIK_HOST=http://192.168.178.x:9000
AUTHENTIK_TOKEN=...
# Vaultwarden
VAULTWARDEN_HOST=http://192.168.178.x:8087
VAULTWARDEN_ADMIN_TOKEN=...
# qBittorrent
QBT_HOST=http://192.168.178.x:8080
QBT_USER=...
QBT_PASSWORD=...
# *arr suite
RADARR_HOST=http://192.168.178.x:7878
RADARR_API_KEY=...
SONARR_HOST=http://192.168.178.x:8989
SONARR_API_KEY=...
LIDARR_HOST=http://192.168.178.x:8686
LIDARR_API_KEY=...
# Jellyfin
JELLYFIN_HOST=http://192.168.178.x:8096
JELLYFIN_API_KEY=...
# Navidrome
NAVIDROME_HOST=http://192.168.178.x:4533
NAVIDROME_USER=...
NAVIDROME_PASSWORD=...
# RomM
ROMM_HOST=http://192.168.178.x:7998
ROMM_USER=...
ROMM_PASSWORD=...
# Grafana
GRAFANA_HOST=http://192.168.178.x:3000
GRAFANA_TOKEN=
# Prometheus
PROMETHEUS_HOST=http://192.168.178.x:9090
# Loki
LOKI_HOST=http://192.168.178.x:3100
# Weather (wttr.in — no API key needed)
WEATHER_LOCATION='90461 Nürnberg'
# Transit (VAG PULS API — no API key needed)
TRANSIT_STOP_VAG=SCHW
# Server port
PORT=3001
```
> **Note on special characters in passwords**: The `.env` file supports shell-quoted values (`'...'` or `"..."`). The deployment script strips quotes before passing to Docker via `--env-file`.
---
## Local Development
```bash
npm install
npm run dev
```
Runs Vite (port 5173) and the Express server (port 3001) concurrently.
---
## Deployment
Deployment is fully automated via Woodpecker CI on every push to `main`.
The pipeline (`.woodpecker.yml`):
1. Builds a Docker image from `Dockerfile`
2. Strips shell quotes from `.env` (Docker `--env-file` passes values literally)
3. Stops and removes the old container
4. Starts a new container with `docker run --env-file`
The `.env` file lives at `/opt/docker/dashboard/.env` on the host and is mounted into the pipeline as a secret volume — it is never committed to the repository.
---
## Adding a New App Link
Edit `src/config/apps.ts`:
```ts
{ name: 'My App', url: 'https://myapp.syco.me', icon: `${ICONS}/myapp.svg` }
```
Download the icon to `public/icons/` first. Icons are sourced from [selfh.st/icons](https://selfh.st/icons).
## Adding a New Widget
1. Create `src/components/widgets/MyWidget.tsx`
2. Add it to `src/config/dashboard.ts` in the appropriate section
---
## Changing the Transit Stop
Update `TRANSIT_STOP_VAG` in `.env` with a VAG stop ID. Look up stop IDs via:
```
https://start.vag.de/dm/api/haltestellen.json/vag?name=<stop name>
```