# 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)
