Web-based KVM/QEMU virtual machine management panel.
Express + EJS + SQLite + WebSocket console + SSH terminal, packaged as a
single self-contained binary with pkg.
- Multi-user with roles (
user/admin) - VM lifecycle: create, start, stop, restart, resize disk, reinstall, snapshots
- Browser console over WebSocket, with a live QEMU log tail
- Built-in SSH terminal to the guest over
ssh2 - OS template library with cached downloads and per-VM cloud-init seeds
- Port forwarding, resource limits, bandwidth quota accounting
- Discord OAuth login, API keys for automation
- Admin area for users, templates, API keys and panel settings
| Node.js | 20 or newer (22+ recommended) |
| Host OS | Linux with KVM (/dev/kvm); Windows also works for management-only use |
| QEMU | qemu-system-x86_64, qemu-img |
| Optional | genisoimage / mkisofs / cloud-utils for cloud-init seed images |
| Optional | websocat or nc for the guest SSH terminal |
git clone https://github.com/4x1t3l/libre-hkvm.git hkvm-panel
cd hkvm-panel
npm install
npm startnpm 11+ note.
sqlite3andssh2need their install scripts to build a native binding. npm 11 blocks those by default. The repository already ships anallowScriptsblock inpackage.json, so a plainnpm installworks. If you hitCannot find module 'node_sqlite3.node', run:npm install-scripts approve sqlite3 ssh2 npm rebuild sqlite3 ssh2
The panel listens on :8080 and creates its database at ~/.hkvm/hkvm.db.
A default admin / admin account is created on first boot — change it
immediately (Admin → Users).
All optional, via environment variables or a .env file in the project root
(the app calls dotenv.config()). See .env.example.
| Variable | Default | Meaning |
|---|---|---|
PORT |
8080 |
HTTP port |
HKVM_DATA_DIR |
~/.hkvm |
Where the SQLite database lives |
PANEL_NAME |
Librefied by 4x1t3l |
Name shown in the UI |
PANEL_VERSION |
V3.0 |
Version string shown in the UI |
DEFAULT_LOGO_URL |
an imgur URL | Logo used by the EJS templates |
VM images, ISOs, templates and cloud-init seeds live under ~/vms/:
~/vms/vm-<id>-disk.qcow2 VM disk images
~/vms/vm-<id>-seed.iso cloud-init seed images
~/vms/iso/ uploaded ISOs
~/vms/templates/ cached OS template images
~/vms/cloudvm/ cloud-init working directories
npm install -g pkg
npm run build # -> dist/apppkg bundles app.js plus views/** and public/** into a single
executable. The default target is node18-linux-x64, because pkg 5.8.1 is
the latest release and the only one still publishing base binaries (it has
none for node20 or node22).
Two things to know:
-
Build on Linux.
pkgbundles the nativesqlite3binding, so the Linux build of it is the one that has to be present.sqlite35.x ships an N-API (napi-v6) prebuild, which is ABI-stable, so the same.nodeworks inside the packaged binary whatever Node version it embeds. -
To target a newer Node.js you need a matching base binary and a
sqlite3build for that ABI:export PKG_NODE_PATH=/path/to/node22-base-binaries npm run build
Add more targets by editing the pkg block in package.json.
app.js the entire application (routes, DB, WebSocket, CLI)
views/ EJS templates
users/ user-facing pages
admin/ admin pages
partials/ shared layout fragments
public/ static assets (css, images)
Authenticated with a session cookie or an X-API-Key header.
GET /api/vps list your VMs
POST /api/vps create a VM
PUT /api/vms/:id/edit update configuration
DELETE /api/vms/:id delete a VM
POST /api/vms/:id/start start / stop / restart / reinstall / snapshot
GET /api/vms/:id/console console log
GET /api/vms/:id/edit configuration
GET /api/settings panel settings
POST /api/admin/users user management (admin)
POST /api/admin/api-keys issue an API key (admin)
Read SECURITY.md before you expose this panel to the internet.
This release fixes the issues that were present in the original build:
the WebSocket console and SSH terminal are now authenticated, every route
that takes a VM id checks ownership, disk_size is validated and no
longer reaches a shell, the session secret is no longer hardcoded, the
default administrator password is generated rather than admin, and the
login endpoint is rate limited. SECURITY.md lists each fix and what you
still have to do yourself.
The one thing the panel cannot do for you: it speaks plain HTTP and trusts the reverse proxy in front of it. Put it behind a proxy that terminates TLS, authenticates every request (including WebSocket upgrades) and restricts which addresses can reach it.
| Variable | Purpose |
|---|---|
SESSION_SECRET |
Session signing key, minimum 32 characters. Generated and persisted if unset. |
HKVM_ADMIN_PASSWORD |
Password for the admin account on first boot. A random one is printed once if unset. |
HKVM_DATA_DIR |
Where the database and the generated session secret live. |
HKVM_TRUST_PROXY |
Set to 1 behind a TLS-terminating proxy. |
HKVM_SECURE_COOKIES |
Set to 1 to force the Secure cookie flag outside production. |
HKVM_LOGIN_LIMIT_PER_IP |
Login attempts per address per 15 minutes (default 30). |
HKVM_LOGIN_LIMIT_PER_ACCOUNT |
Failed login attempts per account per 15 minutes (default 5). |
HKVM_ALLOW_PRIVATE_DOWNLOADS |
Set to 1 to allow template downloads from private addresses. |
See CONTRIBUTING.md.
MIT — see LICENSE.
Originally developed as a commercial product with a licence server; the licence check has been removed in this open-source edition.