clusev/README.md

84 lines
3.5 KiB
Markdown

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