SysDeck/QUICKSTART.md

428 lines
23 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SysDeck — Quick Start
Author: **Jeremy Anderson** · <info@dcos.net> · <https://dcos.net>
Version: **0.2.0** (Master Edition)
Five-minute path from tarball to 26 sidebar entries in your Cockpit — plus the Web Edition with Fester pre-integrated (section 9).
---
## 1. Prerequisites
| Component | Why | Install |
|-----------|-----|---------|
| `cockpit-bridge` ≥ 239 | The plugin runtime | `pacman -S cockpit` / `apt install cockpit` / `dnf install cockpit` |
| `python3` ≥ 3.9 | Bridge helpers | Universal on modern Linux |
| `polkit` | Privilege escalation (the cockpit way) | `pacman -S polkit` / `apt install policykit-1` / `dnf install polkit` |
| `appstream` (optional) | Cockpit Applications menu | `pacman -S appstream` / `apt install appstream` |
Cockpit itself ships its own `cockpit-bridge` package — that is the only hard dependency. SysDeck degrades gracefully when optional backends (podman, nftables, mkosi, bpftool, apparmor, …) are absent — each panel renders an install hint instead of crashing.
## 2. Install
```bash
# Get the tarball
ls sysdeck-0.0.35.tar.bz2 # download from your release source
# Extract and install
tar xjf sysdeck-0.0.35.tar.bz2
cd sysdeck-0.0.35
sudo make install
# Restart cockpit so it re-scans the plugin directory
sudo systemctl restart cockpit.socket
```
`make install` does:
- Copies each `plugins/sysdeck-*/{manifest.json,index.html,*.js}` to `/usr/share/cockpit/sysdeck-*/`
- Copies `shared/{manifest.json,bridge.js,sysdeck.css}` to `/usr/share/cockpit/sysdeck-common/`
- Copies each `bridge/*.py` (executable, 0755) to `/usr/lib/sysdeck/bridge/`
- Copies `firewall/templates/*.sh` (executable, 0755) to `/usr/share/sysdeck/firewall/templates/`
- Installs the AppStream metainfo at `/usr/share/metainfo/sysdeck.metainfo.xml`
- Installs the polkit policy at `/usr/share/polkit-1/actions/org.sysdeck.policy`
- Reloads polkit and refreshes the AppStream cache
## 3. Verify the install
Open `https://<host>:9090` in your browser and authenticate as a wheel/sudo user. The Cockpit sidebar should now list **23** entries under the `SysDeck <Name>` prefix:
| # | Module | # | Module |
|---|--------|---|--------|
| 1 | SysDeck Containers | 13 | SysDeck Themes |
| 2 | SysDeck Firewall | 14 | SysDeck Hardware Auth |
| 3 | SysDeck Integrity | 15 | SysDeck Glances |
| 4 | SysDeck Network Security | 16 | SysDeck Sensors |
| 5 | SysDeck Service Mesh | 17 | SysDeck Benchmark |
| 6 | SysDeck Vault | 18 | SysDeck Packages |
| 7 | SysDeck Fleet | 19 | SysDeck Policy |
| 8 | SysDeck Kata | 20 | SysDeck Databases |
| 9 | SysDeck Fester | 21 | SysDeck Jellyfin |
| 10 | SysDeck Firmware | 22 | SysDeck Photos |
| 11 | SysDeck Image Builder | 23 | SysDeck Remote FS |
| 12 | SysDeck Mining | | |
If any are missing, run the diagnostic:
```bash
sudo /usr/share/sysdeck/sysdeck-diagnose.sh
```
It prints exactly what cockpit sees on your system — installed manifests, bridge helpers present, polkit actions loaded, and the cockpit-bridge version.
## 4. First-use walkthrough
### 4a. Firewall (the cockpit way)
Open **SysDeck Firewall**. The panel renders:
1. **Capability matrix** — confirms nftables is installed.
2. **Template selector** — pick `vps-webserver` (service-aware firewall that auto-detects SSH/Caddy/Varnish/Forgejo) or `no-services` (locked-down host with no public services except SSH).
3. **Detect Services** — runs the template's `detect` action and shows the OS, interface, IPv4/IPv6, and which services the template found.
4. **Apply Template** — cockpit prompts for the superuser password via polkit. The bridge runs the template's `start` action under the `org.sysdeck.firewall.modify` action.
5. **Banned IPs** — live `ssh_abuse` / `port_scanners` / `connlimit_abuse` ban sets, with per-IP **Unban** buttons and a **Clear All** button.
6. **Active Ruleset** — the live nftables rules table, refreshed after each operation.
To drop in your own template, copy a `*.sh` file into `/usr/share/sysdeck/firewall/templates/` — the panel's `templates` subcommand discovers it automatically. The script must implement `start / stop / restart / detect / status` subcommands (see the shipped templates for reference).
### 4b. Packages (the cockpit way)
Open **SysDeck Packages**. Click **⬆ Update All**. Cockpit prompts for the superuser password via polkit. The bridge runs `pacman -Syu` / `apt upgrade -y` / `dnf upgrade -y` directly via subprocess — no `sudo` shell-out from JS. Live stdout/stderr stream into the in-panel `<pre>` log. The **👁 Preview Command** button shows the exact command that will be run before you confirm.
### 4c. Policy & Permissions
Open **SysDeck Policy**. The panel renders:
1. **LSM Stack** — a badge row in the header showing which LSMs the kernel has stacked (`/sys/kernel/security/lsm`), and a table of all 9 supported LSMs with their securityfs paths and active/inactive status.
2. **Capability Matrix** — confirms availability of ACLs, cgroups v2, VLANs, eBPF, namespaces, file caps, and each LSM. Absent concerns show a red "no" badge plus the install command.
3. **ACL Manager** — pick a path, type an entry like `group:www-data:rwx`, click `setfacl -m` (or `setfacl -x` to remove, `set default ACL` for directory inheritance).
4. **cgroups v2** — the unified hierarchy tree under `/sys/fs/cgroup/` with per-cgroup process counts and controllers. Use **Show** to inspect one cgroup's processes and control files; **mkdir** to create a new one; **move** to migrate a PID; **write** to set `memory.max`, `cpu.weight`, etc.
5. **VLANs** — list and create/delete 802.1Q VLANs via `ip link add ... type vlan id <vid>`.
6. **eBPF programs** — list loaded BPF programs via `bpftool prog show -j`, list maps, pin a program to `/sys/fs/bpf/...`.
7. **Namespaces** — `lsns -J` output as a table.
8. **File Capabilities** — `getcap -r /` enumeration with `setcap` / `getcap` / `setcap -r` controls.
9. **AppArmor** (optional) — if the kernel compiled AppArmor in, shows the enforcement mode and lets you switch profiles between `enforce` and `complain` modes. If absent, renders an install hint.
10. **Smack / TOMOYO / Yama / LoadPin / Lockdown / BPF-LSM / Landlock** — each has its own card with the live state and any management controls the LSM supports. Each card follows the same shape: if the LSM is not active, the card shows the kernel cmdline that enables it; if active, it shows the live state.
### 4d. Databases
Open **SysDeck Databases**. The panel auto-detects 32+ engines across SQL (PostgreSQL/MySQL/MariaDB/SQLite/CockroachDB/TiDB), NoSQL (MongoDB/CouchDB/RethinkDB/DynamoDB-local), Vector (Milvus/Qdrant/Weaviate/Chroma/pgvector), TimeSeries (InfluxDB/TimescaleDB/QuestDB/ClickHouse), Graph (Neo4j/ArangoDB/OrientDB), Embedded (Redis/KeyDB/ValKey/RocksDB/LMDB/BadgerDB), Cloud (Firestore-emulator/Supabase-local), and AI (LanceDB/DuckDB/Tile38). Each row has **▶ Start / ■ Stop / ↻ Restart / 🔍 Status** buttons. The **Run SQL Query** card lets you execute arbitrary SQL against SQL-family engines via the engine's CLI client (`psql -tAc`, `mysql -e`, etc.).
## 5. Build from source
```bash
cd sysdeck-0.0.35
make check # 7 build-time guards: manifests, metainfo, tabs, no-broken-import, no-broken-module, bridge-subcommands cross-check, version sync
make dist # builds sysdeck-0.0.35.tar.bz2
make distcheck # extracts + runs make check inside the tarball tree
```
`make check` is a hard pre-flight: it cross-checks every `bridgeCmd("<module>", ["<sub>", ...])` call in `shared/bridge.js` against the `COMMANDS` dict declared in each `bridge/<module>.py`. If the JS calls a subcommand the Python helper doesn't implement, `make check` fails with a clear message naming the file, line, and missing subcommand.
## 6. Uninstall
```bash
sudo make uninstall
sudo systemctl restart cockpit.socket
```
`make uninstall` removes every trace of every prior version (the v0.0.9-v0.0.19 single-plugin `/usr/share/cockpit/sysdeck/` directory, the v0.0.20+ multi-plugin `/usr/share/cockpit/sysdeck-*/` directories, the Python bridge helpers, the diagnostic scripts, the firewall templates, the AppStream metainfo, the polkit policy, and any pacman-installed `sysdeck` package).
## 7. Where to go next
- [README.md](./README.md) — full module catalog, architecture, coding standards.
- [BLOG.md](./BLOG.md) — release narrative for v0.0.33 and prior versions.
- [docs/INSTALL.md](./docs/INSTALL.md) — RPM, DEB, pip, and manual install paths.
- [QA.md](./QA.md) — QA notes per release.
- [worklog.md](./worklog.md) — per-task development log.
## 8. Reporting issues
Open the in-panel error view: every SysDeck plugin's `index.html` installs `window.addEventListener('error')` and `'unhandledrejection'` handlers that replace the "Loading…" placeholder with the actual error message on the page — no devtools required. The same page tells you whether `cockpit.js` itself loaded, whether `bridge.js` imported cleanly, and whether the panel's `mount()` threw.
## 9. The Web Edition (master tarball)
The master tarball also ships the **SysDeck Web Edition** at `web/` — a standalone browser console (no cockpit required) with 29 bridge modules, real `/proc` / `/sys` collectors, and **Fester pre-integrated** (vendored at `web/mini-services/fester`, independent version 0.2.1):
```bash
make web-dev # fester service in the background (:3010) + web console (:3000)
```
Manual equivalent:
```bash
make fester-start # terminal 1: fester on :3010
cd web && bun install && bun run db:push # terminal 2: web edition setup
bun run dev # web console on :3000
```
Open `http://localhost:3000`. The master tarball can be rebuilt any time with `make master`.
## 10. The AI Gateway (master tarball, v0.3.0)
The master tarball also vendors **klanker-gate** — the Frosty Deno LLM gateway (independent version 0.9.0, Apache-2.0, **by TykoDev: https://github.com/TykoDev/klanker-gate — not SysDeck code**, see `klanker-gate/ATTRIBUTION.md`) — at `klanker-gate/`, with the new **AI Gateway** module in both editions. On Arch Linux the whole gateway is one package away:
```bash
cd klanker-gate/arch
pacman -S --needed deno base-devel # deno is in [extra]
makepkg -si # /usr/share/klanker-gate + systemd unit
sudoedit /etc/klanker-gate/env # FROSTY_PG_URL + one provider key (+ token)
sudo systemctl enable --now klanker-gate
curl http://localhost:8080/healthz
```
Then point SysDeck at it (cockpit bridge env, or `web/.env` for the web edition, then restart):
```bash
KLANKER_URL=http://127.0.0.1:8080
KLANKER_ADMIN_TOKEN=<the FROSTY_ADMIN_TOKEN you set>
```
Both the cockpit AI Gateway panel and the web edition's AI Gateway panel flip from their offline/demo state to live data automatically. The full runbook — postgres provisioning, multi-worker serving (`FROSTY_WORKERS`, an Arch bonus via `SO_REUSEPORT`), the optional control-UI build — is `klanker-gate/arch/INSTALL-ARCH.md`.
### 10.1 Running an all-local stack (ollama · llama.cpp · koboldcpp)
The gateway is **not SaaS-only** — no API key is required anywhere in this
setup. Five provider types are local-first upstream: `ollama`, `lmstudio`,
`sgl` (SGLang) natively, plus the generic `openai-compatible` type that
llama.cpp (llama-server), KoboldCpp, vLLM and TGI all speak:
| backend | provider type | base URL | auth |
|---|---|---|---|
| Ollama | `ollama` | `http://127.0.0.1:11434/v1` | none |
| llama.cpp (llama-server) | `openai-compatible` | `http://127.0.0.1:8081/v1` | optional |
| KoboldCpp | `openai-compatible` | `http://127.0.0.1:5001/v1` | optional |
| LM Studio | `lmstudio` | `http://127.0.0.1:1234/v1` | none |
| SGLang | `sgl` | `http://127.0.0.1:30000/v1` | none |
Env wiring (in `/etc/klanker-gate/env` or the gateway's `.env`):
```bash
OLLAMA_BASE_URL=http://127.0.0.1:11434/v1
OLLAMA_MODELS=qwen3:14b,llama3.1:8b,nomic-embed-text
LMSTUDIO_BASE_URL=http://127.0.0.1:1234/v1
OPENAI_COMPAT_BASE_URL=http://127.0.0.1:8081/v1 # ONE openai-wire server
```
Env registers one `openai-compatible` account — to run llama.cpp **and**
koboldcpp (and vLLM) side by side, register each via the admin API, then
auto-discover its catalog:
```bash
curl -s http://127.0.0.1:8080/api/providers -H 'Authorization: Bearer $FROSTY_ADMIN_TOKEN' \
-H 'content-type: application/json' \
-d '{"id":"llama-server","type":"openai-compatible","baseUrl":"http://127.0.0.1:8081/v1","enabled":true}'
curl -s -X POST http://127.0.0.1:8080/api/providers/llama-server/refresh-models \
-H 'Authorization: Bearer $FROSTY_ADMIN_TOKEN'
```
**Port note:** llama-server defaults to `:8080` — the same port the gateway
listens on. Run it on another port (`--port 8081`) or move the gateway.
Both editions ship a **Local stack wiring** card (in the AI Gateway panel)
that live-probes each backend's `/v1/models` from the host and shows these
recipes with copy buttons — `klanker localstack` at the bridge level.
### 10.2 Turning the AI Gateway off (module toggles)
Not using the gateway (or switched to a different assistant stack)?
Both editions let you remove it from the console without uninstalling
anything:
- **web edition** — every sidebar module carries a power toggle (hover
a row → ⏻). Clicking it hides the module from the sidebar AND the
⌘K palette; a **Disabled (N)** section appears at the sidebar bottom
with one-click re-enable (plus a restore-all ↻). State is persisted
in SQLite (`shell.disabled` via the `shell` bridge module) and
survives restarts; Overview is protected. If you disable the module
you are viewing, the console jumps back to Overview.
- **cockpit edition** — plugins are discovered by directory: `sudo rm
-rf /usr/share/cockpit/sysdeck-klanker` removes the sidebar entry
(bridge helper stays at `/usr/lib/sysdeck/bridge/klanker.py` for
scripts); restore with `sudo make install`.
### 10.3 The 0.3.0 security audit (both editions + the vendored gateway)
A full-codebase security review shipped with 0.3.0 — the cockpit bridge
helpers, the 27 plugin panels, the web edition, and the vendored
klanker-gate tree. What changed:
- **bridge helpers fail closed now.** `cgroup-set` validates both the
cgroup path (must resolve under `/sys/fs/cgroup`) and the control-file
name (real controller knobs only); `artifacts-clear` /
`build-delete` / `build-log` / `artifacts` validate ids as single
path components before touching state/artifacts/logs dirs;
`profile-create` rejects names that aren't single components (was
directory traversal + config injection into root-executed build
configs); hwalert's `sudo sh -c` is gone (direct write, device path
validated under the scanned sysfs bases); `db start/stop/restart`
resolve engines through the registry; `db query` now actually
enforces the read-only promise (SELECT/WITH/SHOW/… only);
`themes set` rejects newlines (cockpit.conf section injection);
`packages install/remove/update` reject option-shaped names.
- **every plugin escapes its data.** The 8 oldest panels (packages,
benchmark, auth, sensors, vault, firmware, mesh, and the auth quick
actions) now escape every interpolated string — package metadata,
USB reader descriptors, fwupd device fields, sensor labels, spawn
errors — before it lands in `innerHTML`. All 27 manifests dropped
`unsafe-eval` from their CSP. Every external link carries
`rel="noopener noreferrer"`.
- **the web edition binds loopback.** `bun run dev` → `127.0.0.1:3000`,
the fester service → `127.0.0.1:3010`, the production start script
pins `HOSTNAME=127.0.0.1`; the bridge endpoint gained a body-size
cap, a per-IP rate limit and generic error responses (details go to
the server log).
- **the vendored gateway got audited, not modified.** Findings live in
`klanker-gate/arch/SECURITY-UPSTREAM.md` (10 findings, 3 critical:
no-token admin mode, 0.0.0.0 default bind, open `/v1/*` until the
first virtual key exists). Upstream source stays byte-identical per
the attribution contract; the SysDeck `arch/` packaging layer
mitigates: the systemd unit refuses to start without
`FROSTY_ADMIN_TOKEN`, `INSTALL-ARCH.md` §9 carries the firewall +
first-vkey runbook.
- **fixed along the way (functional):** the Packages panel's
firewall-backend install path (`packages.py install --` choke), the
auth panel's quick-action buttons (called a bridge.spawn that never
existed), and the mesh panel's table (read a data shape the bridge
never returned).
### 10.4 The web edition login (Unix accounts, cockpit-style)
SysDeck is a **LAN-side console** — loopback binding stays the outer
boundary. What 0.4.0 changes is the login itself: instead of the 0.3.1
shared password, you now sign in with a **Unix account — the username
and password are verified by the host's PAM stack**, exactly the
mechanism Cockpit uses at its own login screen. The host decides; the
console keeps no password data of its own.
- **PAM path:** `web/scripts/pam-auth.py` (stdlib-only ctypes client of
`libpam`) runs the `pam_start` → `pam_authenticate` → `pam_acct_mgmt`
sequence under the **`sysdeck`** service when `/etc/pam.d/sysdeck`
exists, else the stock **`login`** stack. Credentials travel over
stdin (never argv — `/proc` would leak them). Ship your own
`/etc/pam.d/sysdeck` (e.g. `auth required pam_unix.so`, plus
`pam_google_authenticator` for MFA if you want it) to tailor the
stack — `SYSDECK_PAM_SERVICE` renames it.
- **Root, or pam+local:** pam_unix needs root to read `/etc/shadow`
for *arbitrary* users (non-root processes only get the invoking uid
via `unix_chkpwd` — a pam_unix guarantee). So the modes are
`SYSDECK_AUTH_MODE=pam` (default; run the service as root, like
cockpit-ws), `pam+local` (PAM first, then the `SdUser` scrypt table
for installs that can't run privileged), or `local` (console
accounts only). Manage the local table with
`bun scripts/manage-users.mjs list|add|passwd|disable|enable|remove`
from `web/`.
- **Session:** an HttpOnly, SameSite=Lax cookie (`sd_session`) holding
an HMAC-SHA256-signed token **bound to the username**
(`v2.<exp>.<userB64>.<hmac>`), **12h** expiry. The HMAC key is random
per install and persists in the SQLite DB, so sessions survive
restarts — including the 0.3.1 → 0.4.0 upgrade (old v1 tokens still
verify as a legacy "operator" session until they age out).
- **Gate scope:** the page itself is server-rendered as the login
screen until the cookie verifies, every `/api/*` route answers 401
until signed in, and the **fester service verifies the identical
v2 token** on its REST + WebSocket surface — no unauthenticated path
into the console's data.
- **Lockout:** wrong attempts are rate limited per-IP **and**
per-username (5 per 60s each — the same shape the sshd stack
applies). Wrong-user and wrong-password return the same generic
answer; nothing enumerates accounts.
- **Identity in the shell:** the header carries an account menu —
avatar, `user@host`, unix-account provenance (PAM vs local), the
wheel/sudo "Administrative access" badge, and a live session-expiry
countdown with a draining life bar; the status bar shows
`user@host` next to the vitals. Login/logout are audited with the
unix username as the actor.
- **TLS:** LAN deployments typically run plain http; front the console
with TLS and set `SYSDECK_SESSION_SECURE=1` to add the `Secure`
cookie flag. Sign out lives in the account menu (clears the cookie).
The login/logout actions are audited (`module: web`, actions
`login` / `login-failed` / `logout`, actor = the unix username, with
source IP). This is deliberately *not* MFA-by-default or rate-proof
crypto — it is the host's own account system doing what it already
does at every other login surface on the box, recorded here so nobody
mistakes it for more or less than that.
### 10.5 Cockpit module detection in the web console (v0.4.1)
The console scans the host the same way the cockpit shell discovers
pages — every `/usr/share/cockpit/<pkg>/manifest.json` with a `menu`
entry is a module — and **loads each one into its own navigation**:
- a **Cockpit** sidebar group (with a LIVE/DEMO provenance badge) lists
every detected module — distro modules (`cockpit-machines`,
`cockpit-podman`, networking, storage, accounts, updates, SELinux,
PCP metrics, kdump, tuned...) and third-party addons alike;
- each module opens a detail view with its manifest identity, shipped
files, **live backend presence probes** (`virsh`/`podman`/`nmcli`/
`pkcon`/... — real `which()` checks), and a jump to the native
console panel covering the domain when one exists;
- `sysdeck-*` modules never duplicate (native panels already ship), and
menu-less chrome (`base1`, `shell`) is skipped — exactly the cockpit
shell's own rules;
- `SYSDECK_COCKPIT_SCAN` (colon-separated paths) adds extra scan roots
for staged trees; with no cockpit tree on the host, a clearly-badged
typical-distro set keeps the surface explorable;
- the **Cockpit Modules** hub panel (Integrations group) summarizes
detection: counts, backend availability, native coverage, and the
scan paths in play.
This is the piece that makes the console/host pair 100% compatible:
install a cockpit module on the box, and it shows up here — no cockpit
login required to browse it.
## 11. Run without Cockpit (the complete standalone runbook, v0.3.0)
The web edition needs **nothing from sections 1–8** — no cockpit, no Python
bridge, no systemd, no root. One Bun runtime serves the whole console:
```bash
tar xjf sysdeck-0.4.1-master.tar.bz2
cd sysdeck-0.4.1-master
make web-dev # bun install + db:push + fester + next dev :3000
```
Production path (standalone build, systemd on Arch, reverse proxy with the
`?XTransformPort=` websocket gateway, environment reference, troubleshooting):
```bash
cd web
bun run build # self-contained .next/standalone/
PORT=3000 HOSTNAME=0.0.0.0 bun run start # or: node .next/standalone/server.js
```
The complete runbook — with the two systemd units (web + fester), the
`.env` reference table, the Caddy/nginx websocket-gateway configs and a
troubleshooting matrix — lives in two places, kept in sync:
- **`web/README.md`** in this tarball (plain markdown)
- the **"Run without Cockpit" panel** in the web console (system group,
right under Overview) — every command block has a copy button
## 12. The web-edition skin for Cockpit (v0.3.0)
Since 0.3.0 the Cockpit plugin pages wear the **web-edition skin** by
default: every plugin's `index.html` links
`../sysdeck-common/sysdeck-web.css` after the base stylesheet, porting
the Next.js console's midnight/teal design (teal accent `#3fc9b0`,
soft-tinted badges, 10px radii, tabular numerals, thin teal-edged
scrollbars) onto the classic cockpit panels. Nothing else changes — the
class vocabulary, the bridge, and every module are untouched.
```bash
# revert the plugin pages to the classic 0.1.x skin:
sudo rm /usr/share/cockpit/sysdeck-common/sysdeck-web.css
# also theme the Cockpit SHELL chrome (sidebar, header, login) to match:
sudo make install-branding # backs up any existing branding.css first
sudo make uninstall-branding # restore the backup
```
`install-branding` installs `shared/branding.css` as
`/usr/share/cockpit/branding.css` — Cockpit's documented override point
for the shell. It targets both PatternFly v5 (`pf-v5-*`, Cockpit ≥ 300)
and v4 (`pf-c-*`) selector generations, so unmatched rules simply no-op.
Author: **Jeremy Anderson** · <info@dcos.net> · <https://dcos.net>