Go to file
boban b9b0f62d78 feat(ssh): wire real fleet data over SSH (FleetService + live poller)
Replace the page mock data with real reads from the target host via the
phpseclib SSH layer. New FleetService parses raw command output into the exact
shapes the Livewire pages already consume; all parsing forces LC_ALL=C and reads
/proc to stay locale-independent.

- app/Services/FleetService.php: metrics (cpu via two /proc/stat samples, mem via
  /proc/meminfo, disk via df), full snapshot (identity/specs incl. virt+disk_gb,
  volumes, interfaces from ip+/proc/net/dev, sshd/fail2ban/ufw hardening, authorized
  keys), systemd units + journal, and an ls-based directory listing. One compound
  command per read; connect/parse failures bubble up.
- clusev:poll-metrics command replaces the mock emitter in the dev supervisor:
  polls every credentialed server, persists cpu/mem/disk/status, broadcasts
  MetricsTicked(server) — unreachable boxes flagged offline, loop never dies.
- Pages wired with graceful failure (offline state, never a 500):
  Dashboard (live cached metrics + notable units), Services (real units+journal),
  Files (real listing + dir navigation via open/go/up), Server-Details (live
  snapshot persisted onto the row + offline banner).
- WithFleetContext prefers a credentialed, non-offline server as the default.
- dualChart filters ticks by server name so the chart tracks the active host.

Verified live against a real Debian 13 box: metrics/services(91)/journal(25)/
files(navigable)/snapshot(5 ifaces, real hardening, real key) all parse correctly.
Credentials are stored encrypted in the vault — never in source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 21:34:13 +02:00
app feat(ssh): wire real fleet data over SSH (FleetService + live poller) 2026-06-12 21:34:13 +02:00
bootstrap feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
config feat(r5): wire-elements/modal confirmations for destructive actions 2026-06-12 15:05:50 +02:00
database feat: auth + 2FA (login wall + TOTP + forced onboarding) 2026-06-12 13:57:02 +02:00
docker feat(ssh): wire real fleet data over SSH (FleetService + live poller) 2026-06-12 21:34:13 +02:00
docs fix: apply v1 UI review (a11y, contrast, live-chart robustness) 2026-06-12 06:16:52 +02:00
public feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
resources feat(ssh): wire real fleet data over SSH (FleetService + live poller) 2026-06-12 21:34:13 +02:00
routes feat: auth + 2FA (login wall + TOTP + forced onboarding) 2026-06-12 13:57:02 +02:00
storage feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
tests feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
.dockerignore feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
.editorconfig feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
.env.example feat(deploy): install.sh + Caddy auto-TLS + prod hardening 2026-06-12 15:17:32 +02:00
.gitattributes feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
.gitignore feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
CLAUDE.md feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
Dockerfile feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
README.md feat(deploy): install.sh + Caddy auto-TLS + prod hardening 2026-06-12 15:17:32 +02:00
artisan feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
composer.json feat: auth + 2FA (login wall + TOTP + forced onboarding) 2026-06-12 13:57:02 +02:00
composer.lock feat: auth + 2FA (login wall + TOTP + forced onboarding) 2026-06-12 13:57:02 +02:00
docker-compose.prod.yml feat(deploy): install.sh + Caddy auto-TLS + prod hardening 2026-06-12 15:17:32 +02:00
docker-compose.yml feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
handoff.md feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
install.sh feat(deploy): install.sh + Caddy auto-TLS + prod hardening 2026-06-12 15:17:32 +02:00
kickoff-prompt.md chore: project bootstrap — rules.md, CLAUDE.md, .gitignore 2026-06-11 23:12:58 +02:00
package-lock.json feat: live metrics over Reverb (mock emitter) 2026-06-12 01:23:10 +02:00
package.json feat: live metrics over Reverb (mock emitter) 2026-06-12 01:23:10 +02:00
phpunit.xml feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
rules.md feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
vite.config.js feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00

README.md

Clusev

Self-hosted control panel to administer a fleet of Linux servers from one dashboard, agentless over SSH. Clusev is the control-plane (UI + orchestration); it talks to real servers with phpseclib (exec + SFTP) — it never reimplements daemons. Security-first: 2FA, encrypted SSH-credential vault, and a full audit log. Multi-server is free and never paywalled.

Status: v1 — dashboard/live metrics, systemd services, SFTP file manager, server details, auth + 2FA. UI copy is German; meta-docs are English.

Stack: Laravel 13 · Livewire 3 · Tailwind v4 · Reverb (realtime) · Redis · MariaDB · phpseclib3. Everything runs in Docker. See CLAUDE.md for architecture and rules.md for the hard conventions.


Development

The host needs only Docker (no PHP/Composer/Node). The dev app container runs php-fpm + nginx + Vite via supervisor; reverb, queue, mariadb, redis are their own services.

cp .env.example .env                 # then set DB_PASSWORD / DB_ROOT_PASSWORD
docker compose up -d --build         # app on :80, Vite HMR on :5173
docker compose run --rm --no-deps -u "${HOST_UID:-1002}:${HOST_GID:-1002}" app php artisan key:generate
docker compose exec app php artisan migrate --seed

Run any tooling inside the container, e.g. docker compose exec app php artisan make:livewire Servers/Show (class-based — never Volt).


Production install

One host, only Docker + a sudo user. Caddy is the single host-exposed service: auto-TLS when a domain is set, plain HTTP on the bare IP otherwise. install.sh is idempotent — it generates secrets once (never regenerates), brings up the prod stack, migrates, and creates the first admin with a one-time random password printed only on the terminal.

git clone https://git.bave.dev/boban/clusev.git && cd clusev
./install.sh

Prompts (non-interactive: set CLUSEV_DOMAIN / CLUSEV_ADMIN_EMAIL in the environment):

Domain (empty = access by IP over HTTP):   clusev.example.com
Admin e-mail (login + Let's Encrypt):       admin@example.com

The closing banner shows the URL + the one-time admin password. On first login Clusev forces a password change and 2FA enrolment before the panel unlocks.

One knob: APP_DOMAIN

APP_DOMAIN proxy URL Reverb
(empty) Caddy serves plain HTTP on APP_PORT http://<ip> ws://<ip>/app/*
clusev.example.com Caddy gets a Let's Encrypt cert, forces HTTPS https://… wss://…/app/*

SITE_ADDRESS, APP_URL, REVERB_* are derived from it by the installer — nothing hardcoded. Bare-IP mode serves 2FA/audit over cleartext HTTP; the installer warns loudly. Let's Encrypt needs publicly reachable 80/443 — a private (RFC1918) target needs a DNS-01 Caddy build instead.

Manual deploy (for operators who don't curl | bash)

docker compose -f docker-compose.prod.yml build
docker compose -f docker-compose.prod.yml up -d
docker compose -f docker-compose.prod.yml exec -u app app php artisan migrate --force
docker compose -f docker-compose.prod.yml exec -u app app php artisan clusev:install --email=admin@example.com

In-dashboard updates (signed intent file + host-side updater, digest-pinned, cosign-verified, 2FA-gated, with backup + rollback) are designed in docs/install-update-design.md and land in v1.x — they are intentionally not shipped yet.


License

AGPL core + commercial Pro modules (open-core). Multi-server fleet management is always free.