# 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. ```bash 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**. ```bash 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://` | `ws:///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`) ```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.