Go to file
boban 3d73489717 feat(wg): clusev-wg-collect timer+service — 5s status collection 2026-06-20 23:29:21 +02:00
app feat(wg): WireGuard help topic (registration + DE/EN content + test) 2026-06-20 22:46:04 +02:00
bootstrap feat(auth): guests-only BlockBannedIp middleware + 403 page 2026-06-20 17:45:16 +02:00
config chore: release 0.9.33 — WireGuard gate + clusev wg CLI (SP1) 2026-06-20 22:59:07 +02:00
database feat(auth): BannedIp model + migration 2026-06-20 17:26:28 +02:00
docker feat(wg): clusev-wg-collect timer+service — 5s status collection 2026-06-20 23:29:21 +02:00
docs docs(wg): SP2 Phase 1 plan — live-status dashboard page 2026-06-20 23:26:15 +02:00
lang feat(wg): WireGuard help topic (registration + DE/EN content + test) 2026-06-20 22:46:04 +02:00
public feat(branding): favicons + PWA manifest, and custom branded error pages 2026-06-14 15:27:49 +02:00
resources feat(wg): WireGuard help topic (registration + DE/EN content + test) 2026-06-20 22:46:04 +02:00
routes feat(update): real phase progress feed + deep-linkable changelog series/page 2026-06-20 22:08:41 +02:00
storage feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
tests feat(wg): WireGuard help topic (registration + DE/EN content + test) 2026-06-20 22:46:04 +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(versions): update completion feedback, instant availability, local time 2026-06-19 19:08:54 +02:00
.gitattributes feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
.gitignore feat(domain): change the panel domain from the dashboard (v0.4.0) 2026-06-14 01:38:16 +02:00
CHANGELOG.md chore: release 0.9.33 — WireGuard gate + clusev wg CLI (SP1) 2026-06-20 22:59:07 +02:00
CLAUDE.md fix(blade): garbled header on every signed-in page + private metrics channel (v0.4.1) 2026-06-14 08:34:07 +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): one-command update.sh + preserve config on install re-run 2026-06-19 17:58:50 +02:00
artisan feat: scaffold — Dockerized Laravel 13 + Livewire 3 + Tailwind 4 + Reverb 2026-06-12 00:31:50 +02:00
composer.json feat(webauthn): install web-auth/webauthn-lib + credential storage 2026-06-14 18:18:05 +02:00
composer.lock feat(webauthn): install web-auth/webauthn-lib + credential storage 2026-06-14 18:18:05 +02:00
docker-compose.prod.yml fix(deploy): apply Caddyfile changes on update (dir mount + recreate) 2026-06-19 20:57:42 +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 style(install): quote set_stage "done" arg to silence shellcheck SC1010 2026-06-20 22:52:50 +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 fix(blade): garbled header on every signed-in page + private metrics channel (v0.4.1) 2026-06-14 08:34:07 +02:00
update.sh feat(update): real phase progress feed + deep-linkable changelog series/page 2026-06-20 22:08:41 +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 for a fleet of Linux servers — one dashboard, agentless over SSH.

Clusev is the control plane: a modern, security-first web UI that administers your servers by talking to them directly over SSH (exec + SFTP via phpseclib). It installs nothing on the target machines and never reimplements their daemons. Multi-server management is free and never paywalled.

Features

  • Dashboard & live metrics — CPU, memory, load and disk per server, streamed in real time.
  • systemd services — list, start/stop/restart, live journal tail.
  • SFTP file manager — browse, edit text files, preview images.
  • Server details & hardening — resource gauges, volumes, interfaces, SSH keys; UFW/firewalld rules and fail2ban status with one-click controls; and a one-click "generate an SSH key and disable password login, safely" flow.
  • Security — optional, pluggable 2FA (TOTP and/or hardware security keys, or off), one-time backup codes, an encrypted SSH-credential vault, and a complete, tamper-evident audit log.
  • Multiple administrators — add further admin accounts; every action is attributed in the audit log; view and revoke active sessions (per device, per user, or globally).
  • Domain, TLS & e-mail — run on a bare IP over HTTP, set a domain for automatic HTTPS, or put your own reverse proxy in front. Configure SMTP in-panel for password-reset e-mails.

The panel is built on Laravel 13, Livewire 3, Tailwind v4, Laravel Reverb (realtime), Redis, MariaDB and phpseclib — all running in Docker. The interface is in German (English available).

Requirements

  • A Debian or Ubuntu server (a small VM is enough) with root access.
  • A public IP. Optionally a domain whose DNS points at the server (for automatic HTTPS).
  • Only git to fetch the repo (one line below) — the installer sets up Docker and everything else.

Install

sudo apt-get update && sudo apt-get install -y git   # minimal images often lack git
git clone https://git.bave.dev/boban/clusev.git
cd clusev
sudo ./install.sh

The installer is idempotent (safe to re-run) and, in one pass:

  1. Installs Docker (Debian/Ubuntu, from Docker's official repository) if it isn't already present.
  2. Creates a dedicated clusev system user — in the docker group, owning and running the stack — with a random password.
  3. Asks for a domain (leave empty for IP access) and an admin e-mail (leave empty for the default admin@clusev.local), or reads CLUSEV_DOMAIN / CLUSEV_ADMIN_EMAIL from the environment for an unattended install. If you give a domain it checks whether DNS already points here: if so a certificate is obtained automatically; if not, it warns you and lets you take the domain anyway (HTTP until DNS is correct) or continue on the IP.
  4. Generates all secrets (once — never regenerated on re-run), builds the image, starts the stack, runs the migrations, and creates the first administrator with the default password clusev (you are forced to change it on first login).
  5. Installs a themed host login banner (MOTD) showing the dashboard address and live stack status.

When it finishes, the terminal prints a single summary: the dashboard URL, the admin login (your e-mail — admin@clusev.local if you left it empty — plus the default password clusev), and the clusev host user + its random password (shown only once — note it down).

Log in with your admin e-mail (default admin@clusev.local) and the password clusev — the panel then forces you to set a new password immediately. Do this right away: clusev is a known default, so the account is only safe once you've changed it. You can change the login e-mail later under Settings → Profile. 2FA is optional but recommended — enable TOTP and/or a security key from Settings → Security whenever you like.

Access, domain & TLS

  • Bare IP (no domain): served over plain HTTP at http://<server-ip>. This address always stays reachable as a recovery path, even after a domain is configured.
  • With a domain: set it during install or later under System → Domain & TLS. The panel obtains and renews a Let's Encrypt certificate automatically and serves HTTPS — just point DNS at the server. (Let's Encrypt needs publicly reachable ports 80/443.)
  • Behind your own reverse proxy (one that already terminates TLS): switch TLS-Terminierung to Externer Reverse-Proxy in System → Domain & TLS. The panel then serves HTTP only and trusts the proxy's forwarded scheme — set TRUSTED_PROXY_CIDR to the proxy's address and firewall the HTTP port so only the proxy can reach it.

Domain/TLS changes apply on a stack restart — use the "Jetzt neu starten" button in System (no terminal needed; a small, scoped host service performs the restart).

Updating

cd clusev
sudo ./update.sh         # pulls the latest code, then rebuilds, restarts and migrates

update.sh fast-forwards the repo (it never discards local changes), re-runs the idempotent installer non-interactively, and updates itself if the script changed. Secrets and the configured domain / e-mail are preserved. (The older two-step git pull && sudo ./install.sh still works.)

Account recovery

The forgot-password screen offers self-service recovery: an e-mail reset link (valid 15 minutes) when SMTP is configured, or an inline 2FA-proof reset (e-mail + TOTP or a backup code + new password) as a fallback.

Completely locked out (lost password and 2FA, no SMTP)? Recover from the host:

cd clusev
docker compose -f docker-compose.prod.yml exec app php artisan clusev:reset-admin

This clears the second factor so you can set a new password on the next login. The bare-IP http://<server-ip> address is also always available if a domain becomes unreachable. (This command is documented in-panel under Settings → Security and is deliberately not shown on the public forgot-password screen.)

License

Open core, AGPL-3.0 — multi-server fleet management is always free; optional Pro modules (SSO/LDAP, RBAC, audit export, alerting) are separate. Project home: https://git.bave.dev/boban/clusev.