<div align="center">

<img src="docs/assets/clusev-banner.svg" alt="Clusev — self-hosted control plane for a fleet of Linux servers" width="100%">

<br>

**One dashboard for your whole fleet. Agentless over SSH. Self-hosted, security-first, open core.**

[![License](https://img.shields.io/badge/license-AGPL--3.0-FF6B2C?style=flat-square&labelColor=0F1318)](#license)
[![Version](https://img.shields.io/badge/release-v0.9.40-FF6B2C?style=flat-square&labelColor=0F1318)](https://git.bave.dev/boban/clusev)
[![Laravel](https://img.shields.io/badge/Laravel-13-9DAAB6?style=flat-square&labelColor=0F1318)](https://laravel.com)
[![Livewire](https://img.shields.io/badge/Livewire-3-9DAAB6?style=flat-square&labelColor=0F1318)](https://livewire.laravel.com)
[![Docker](https://img.shields.io/badge/Docker-ready-43C1D8?style=flat-square&labelColor=0F1318)](#quick-start)
[![Self-hosted](https://img.shields.io/badge/self--hosted-Debian%20%2F%20Ubuntu-35D07F?style=flat-square&labelColor=0F1318)](#requirements)

[**Features**](#features) · [**Architecture**](#architecture) · [**Quick start**](#quick-start) · [**Domain &amp; TLS**](#access-domain--tls) · [**Security**](#security--recovery) · [**License**](#license)

</div>

---

## What is Clusev

**Clusev** is the control plane for a fleet of Linux servers — a modern, security-first web UI that
administers your machines by talking to them **directly over SSH** (exec + SFTP via
[phpseclib](https://phpseclib.com)). It installs **nothing** on the target servers and never
reimplements their daemons; it orchestrates the real ones.

> **Multi-server management is free and never paywalled.** Optional Pro modules (SSO/LDAP, RBAC,
> audit export, alerting) are separate — the core stays open.

<div align="center">

| | | |
|:--|:--|:--|
| **Agentless** | **Security-first** | **Self-hosted** |
| Pure SSH + SFTP. No daemon, no package, no push-agent on your servers. | 2FA, encrypted credential vault, tamper-evident audit log, per-device sessions. | One Docker stack on one VM. Your servers, your data, your keys. |

</div>

---

## Features

| Capability | What you get |
|:--|:--|
| **Dashboard &amp; live metrics** | CPU, memory, load and disk per server, streamed in real time over WebSockets. |
| **systemd services** | List, start / stop / restart, and tail the live journal — per service, per server. |
| **SFTP file manager** | Browse the remote filesystem, edit text files in place, preview images. |
| **Server details &amp; hardening** | Resource gauges, volumes, interfaces and SSH keys; UFW / firewalld rules and fail2ban status with one-click controls; a guided _"generate an SSH key and disable password login, safely"_ flow. |
| **Security** | Pluggable 2FA (TOTP and/or hardware 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 &amp; e-mail** | Run on a bare IP over HTTP, set a domain for automatic Let's Encrypt HTTPS, or sit behind your own reverse proxy. In-panel SMTP for password-reset mail. |
| **WireGuard (built-in)** | Stand up a WireGuard tunnel from the dashboard, manage peers and live status, and optionally gate the panel — and even SSH — to the tunnel only. |

The interface is **German by default** (English available). Status is shown the operational way —
colour, dots and pills — never emoji.

---

## Architecture

<div align="center">
<img src="docs/assets/clusev-architecture.svg" alt="Operator → Clusev control plane → your fleet" width="100%">
</div>

Laravel is the **control plane**, not a re-implementation of your servers. The browser talks to it
over HTTPS and a Reverb WebSocket for live telemetry; it reaches each server over **SSH exec + SFTP**
using credentials sealed in an encrypted vault that never leaves the control plane. Everything runs as
one Docker stack — `app` (php-fpm + nginx + Vite), `reverb`, `queue`, `scheduler`, `mariadb`,
`redis` — on a single VM.

| Layer | Technology |
|:--|:--|
| Framework | **Laravel 13** |
| UI / interactivity | **Livewire 3** (class-based) |
| Styling | **Tailwind v4** (CSS-first, `@theme`) |
| Realtime | **Laravel Reverb** + Echo |
| Queue / cache | **Redis** |
| Database | **MariaDB** |
| SSH transport | **phpseclib** (exec + SFTP) |
| Reverse proxy / TLS | **Caddy** (automatic Let's Encrypt) |
| Packaging | **Docker** + Docker Compose |

---

## Quick start

```bash
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** (default
   **`admin@clusev.local`**), or reads `CLUSEV_DOMAIN` / `CLUSEV_ADMIN_EMAIL` from the environment for
   an unattended install. With 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).

### First login

Log in with your admin e-mail 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 changed. 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.

---

## 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 — the installer sets up Docker and everything else.

---

## Access, domain &amp; 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 &amp; 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 &amp; 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

```bash
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.)

---

## Security &amp; 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:

```bash
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.

<div align="center">

**Project home — [git.bave.dev/boban/clusev](https://git.bave.dev/boban/clusev)**

</div>
