Backend Go 1.23+ : - API REST + WebSocket (chi, gorilla/websocket) - Authentification PAM via SSH + JWT RS256 - Chiffrement AES-256-GCM pour secrets SQLite - Pool SSH, client Proxmox REST, hub WebSocket pub/sub - Système de modules compilés à initialisation conditionnelle - Audit log, migrations SQLite versionnées Frontend Vue 3 + Vite + TypeScript : - Thème Neumorphism sombre/clair (CSS custom properties) - Wizard d'installation, Dashboard drag-drop, Terminal xterm.js - Toutes les vues CORE + stubs modules optionnels - i18n EN/FR (vue-i18n v11) Infrastructure : - Docker multi-stage (Go → alpine, Node → nginx) - docker-compose.yml, .gitattributes, LICENSE MIT, README Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
239 lines
8.8 KiB
Markdown
239 lines
8.8 KiB
Markdown
# ProxmoxPanel — CORE
|
|
|
|
A self-hosted web management panel for Proxmox VE infrastructure. Manage LXC containers and VMs, run package updates, open interactive terminals, browse files — all from a single web interface with a dark/light Neumorphism UI.
|
|
|
|
## Features
|
|
|
|
- **Dashboard** — Configurable widget grid with drag-and-drop (LXC/VM status, shortcuts, metrics)
|
|
- **Proxmox** — Real-time LXC/VM list with start/stop actions, live status via WebSocket
|
|
- **Updates** — Run `apt upgrade` on the host or any LXC, with streamed output
|
|
- **Terminal** — Interactive SSH terminal in the browser (xterm.js + PTY)
|
|
- **Settings** — Per-user preferences (theme, language, sidebar position), instance config
|
|
- **Modules** — Enable/disable optional modules without restarting
|
|
|
|
## Requirements
|
|
|
|
- Docker + Docker Compose
|
|
- Proxmox VE 7.x or 8.x
|
|
- SSH access to the Proxmox host (password authentication)
|
|
- A Proxmox API token (read-only `PVEAuditor` role is sufficient for metrics)
|
|
- Reverse proxy recommended (Traefik, Nginx, Caddy) for HTTPS in production
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
git clone <repository-url>
|
|
cd core
|
|
docker compose up -d --build
|
|
```
|
|
|
|
Open `http://localhost` (or your server's IP) in a browser. The installation wizard appears on first launch and guides you through the configuration.
|
|
|
|
## Installation Wizard
|
|
|
|
The wizard runs automatically on first launch and collects:
|
|
|
|
1. **Instance name** and public URL (auto-detected from the HTTP request)
|
|
2. **SSH host** — address and port of the Proxmox host (e.g. `192.168.1.10:22`)
|
|
3. **SSH credentials** — Linux username and password used for PAM authentication
|
|
4. **Proxmox API** — URL and API token (e.g. `https://192.168.1.10:8006`)
|
|
5. **Default language** — `en` or `fr`
|
|
|
|
All sensitive values (SSH password, API token) are encrypted with AES-256-GCM before storage.
|
|
|
|
## Authentication
|
|
|
|
ProxmoxPanel uses **PAM authentication via SSH**: the panel attempts an SSH connection to the Proxmox host using the credentials provided at login. If the connection succeeds, the user is authenticated. Group membership is checked with `id -nG` — users in the `sudo` or `wheel` group are granted admin privileges.
|
|
|
|
No separate user database is required. Any Linux user with SSH access can log in.
|
|
|
|
Sessions use JWT RS256 (15-minute access tokens + 7-day refresh cookies).
|
|
|
|
## Configuration
|
|
|
|
All configuration is stored in SQLite (`/app/data/panel.db`). There are no environment variables or config files to manage. Settings are accessible from the web interface under **Settings → General** (admin only).
|
|
|
|
| Setting | Description |
|
|
|---------|-------------|
|
|
| `ssh_host` | SSH address of the Proxmox host (`host:port`) |
|
|
| `ssh_username` | SSH username |
|
|
| `ssh_password` | SSH password (AES-256-GCM encrypted) |
|
|
| `proxmox_url` | Proxmox API base URL (`https://host:8006`) |
|
|
| `proxmox_token` | Proxmox API token (AES-256-GCM encrypted) |
|
|
| `instance_name` | Display name shown in the UI |
|
|
| `public_url` | Public URL of the panel |
|
|
| `default_lang` | Default language (`en` or `fr`) |
|
|
|
|
## Architecture
|
|
|
|
```
|
|
core/
|
|
├── docker-compose.yml # Two services: backend + frontend
|
|
├── backend/ # Go 1.23+ — REST API + WebSocket server
|
|
│ ├── main.go
|
|
│ ├── internal/
|
|
│ │ ├── api/ # HTTP handlers (chi router)
|
|
│ │ ├── auth/ # PAM-via-SSH + JWT RS256
|
|
│ │ ├── crypto/ # AES-256-GCM secret encryption
|
|
│ │ ├── db/ # SQLite + versioned migrations
|
|
│ │ ├── proxmox/ # Proxmox REST API client
|
|
│ │ ├── ssh/ # SSH connection pool
|
|
│ │ ├── websocket/ # WebSocket hub (pub/sub by channel)
|
|
│ │ └── audit/ # Audit log
|
|
│ └── modules/ # Module system (compiled-in, conditional init)
|
|
└── frontend/ # Vue 3 + Vite + TypeScript — Nginx static
|
|
└── src/
|
|
├── views/ # One view per module
|
|
├── stores/ # Pinia (auth, ui)
|
|
├── styles/ # Neumorphism CSS (dark + light themes)
|
|
└── locales/ # i18n — en.json, fr.json
|
|
```
|
|
|
|
### Backend
|
|
|
|
- **Language**: Go 1.23+
|
|
- **Router**: `go-chi/chi` v5
|
|
- **WebSocket**: `gorilla/websocket`
|
|
- **Database**: `modernc.org/sqlite` (pure Go, no CGO)
|
|
- **JWT**: `golang-jwt/jwt` v5, RS256, keys auto-generated at first start
|
|
- **SSH**: `golang.org/x/crypto/ssh`
|
|
|
|
### Frontend
|
|
|
|
- **Framework**: Vue 3 (Composition API)
|
|
- **Build tool**: Vite 6 — compiled to static HTML/CSS/JS, served by Nginx
|
|
- **State**: Pinia
|
|
- **i18n**: vue-i18n v11
|
|
- **Terminal**: xterm.js + `@xterm/addon-fit` + `@xterm/addon-attach`
|
|
- **File editor**: CodeMirror 6
|
|
- **Design**: Custom Neumorphism CSS, dark/light themes via `data-theme` on `<html>`
|
|
|
|
> Node.js is used **only during the Docker build stage** to compile the frontend. The runtime image is Nginx only.
|
|
|
|
### Data persistence
|
|
|
|
A Docker volume (`proxmoxpanel-data`) stores:
|
|
|
|
- `panel.db` — SQLite database
|
|
- `keys/jwt.key`, `keys/jwt.pub` — RSA-2048 key pair for JWT signing
|
|
- `master.key` — AES master secret for credential encryption
|
|
|
|
**Do not delete this volume without backing up `panel.db` first.**
|
|
|
|
### WebSocket channels
|
|
|
|
| Endpoint | Description |
|
|
|----------|-------------|
|
|
| `GET /ws/proxmox` | LXC/VM status updates (polled every 10s) |
|
|
| `GET /ws/updates/{jobId}` | Streaming `apt` output for an update job |
|
|
| `GET /ws/terminal` | Interactive SSH PTY terminal |
|
|
|
|
WebSocket authentication uses a `?token=` query parameter (standard Authorization header is not supported by browser WebSocket API).
|
|
|
|
## Module System
|
|
|
|
Modules are compiled into the binary but initialized only if enabled in the database. This allows disabling features without rebuilding.
|
|
|
|
Each module implements the `Module` interface:
|
|
|
|
```go
|
|
type Module interface {
|
|
ID() string
|
|
Register(registry Registry) error
|
|
}
|
|
```
|
|
|
|
A module can register HTTP routes, WebSocket channels, dashboard widgets, settings tabs, translations, and database migrations via the `Registry` interface.
|
|
|
|
Core modules (always enabled): `dashboard`, `proxmox`, `updates`, `settings`
|
|
|
|
Optional modules (can be toggled): `files`, `terminal`, `logs`, `services`
|
|
|
|
See `backend/modules/` for available modules and their documentation.
|
|
|
|
## Reverse Proxy
|
|
|
|
ProxmoxPanel listens on port 80 (HTTP). In production, place it behind a reverse proxy for TLS termination.
|
|
|
|
Example Traefik dynamic configuration:
|
|
|
|
```yaml
|
|
http:
|
|
routers:
|
|
proxmoxpanel:
|
|
rule: "Host(`panel.example.com`)"
|
|
entryPoints: [websecure]
|
|
service: proxmoxpanel
|
|
tls:
|
|
certResolver: letsencrypt
|
|
|
|
services:
|
|
proxmoxpanel:
|
|
loadBalancer:
|
|
servers:
|
|
- url: "http://<panel-host>:80"
|
|
healthCheck:
|
|
path: /api/health
|
|
interval: 30s
|
|
```
|
|
|
|
## API
|
|
|
|
All API routes are prefixed with `/api/`.
|
|
|
|
| Method | Path | Auth | Description |
|
|
|--------|------|------|-------------|
|
|
| GET | `/api/health` | — | Health check |
|
|
| GET | `/api/install/check` | — | Installation status |
|
|
| GET | `/api/install/status` | — | Detected URL, pre-fill wizard |
|
|
| POST | `/api/install/test-ssh` | — | Test SSH connectivity |
|
|
| POST | `/api/install/configure` | — | Save initial configuration |
|
|
| POST | `/api/auth/login` | — | Login (PAM via SSH) |
|
|
| POST | `/api/auth/logout` | JWT | Logout |
|
|
| POST | `/api/auth/refresh` | Cookie | Refresh access token |
|
|
| GET | `/api/auth/me` | JWT | Current user profile |
|
|
| PATCH | `/api/auth/preferences` | JWT | Update user preferences |
|
|
| GET | `/api/proxmox/resources` | JWT | All Proxmox resources |
|
|
| GET | `/api/proxmox/lxc` | JWT | LXC list |
|
|
| POST | `/api/proxmox/lxc/{vmid}/start` | JWT+Admin | Start LXC |
|
|
| POST | `/api/proxmox/lxc/{vmid}/stop` | JWT+Admin | Stop LXC |
|
|
| POST | `/api/updates/run` | JWT+Admin | Start update job |
|
|
| GET | `/api/updates/history` | JWT | Update history |
|
|
| GET | `/api/settings` | JWT+Admin | All settings |
|
|
| PUT | `/api/settings/{key}` | JWT+Admin | Update a setting |
|
|
| GET | `/api/settings/audit` | JWT+Admin | Audit log |
|
|
| GET | `/api/modules` | JWT | Module list |
|
|
| POST | `/api/modules/{id}/enable` | JWT+Admin | Enable a module |
|
|
| POST | `/api/modules/{id}/disable` | JWT+Admin | Disable a module |
|
|
|
|
## Development
|
|
|
|
### Backend
|
|
|
|
```bash
|
|
cd backend
|
|
go run .
|
|
# or
|
|
go build -o proxmoxpanel . && ./proxmoxpanel
|
|
```
|
|
|
|
Environment variables (all optional):
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `DATA_DIR` | `/app/data` | Path to persistent data directory |
|
|
| `LISTEN_ADDR` | `:3001` | HTTP listen address |
|
|
| `APP_ENV` | `production` | Set to `development` for verbose logs |
|
|
|
|
### Frontend
|
|
|
|
```bash
|
|
cd frontend
|
|
npm install
|
|
npm run dev # Dev server with proxy to backend at localhost:3001
|
|
npm run build # Production build
|
|
```
|
|
|
|
## License
|
|
|
|
MIT — see [LICENSE](LICENSE)
|