Client Portal
Self-service portal for hosting customers
The Client Portal is a built-in plugin that gives hosting customers a simplified, branded web interface to manage their assigned VMs - without exposing the full PegaProx dashboard. Customers access it at /portal and can only see VMs assigned to them via VM ACLs.
VM Dashboard
Customers see their VMs with real-time CPU, RAM, disk usage bars, IP addresses, and uptime. Auto-refreshes every 30 seconds.
Power Actions
Start, stop, shutdown, and reboot VMs - the hoster decides which of them the portal offers (see Allowed actions). Each action is logged in the audit trail and appears in the admin task bar.
VNC Console
Embedded noVNC console directly in the portal. Customers can access their VM desktops without any additional software.
Snapshot Management
Create, revert, and delete snapshots with configurable limits (e.g., max 5 per VM). Hosters control whether snapshots are allowed.
2FA Self-Service
Customers can set up TOTP two-factor authentication themselves - scan QR code, verify, done. Uses the same 2FA infrastructure as the main app.
Password Change
Change password directly from the portal header. Validates against the server's password policy.
VM ACLs & Permissions
The Client Portal relies entirely on PegaProx's existing VM ACL system to determine which VMs a customer can see and control. No separate permission model is needed - the portal reads the same ACLs as the main dashboard.
Create a User
Go to Settings → Users → Add User. Set the role to Viewer (or a custom role). Enable the "Portal Only" checkbox so the user can only log in via /portal.
Assign VM ACLs
Go to Settings → Permissions → VM ACLs Add the user to the VMs they should manage. The portal will only show VMs where the user has an ACL entry.
Required Permissions
The user needs no cluster-level permissions - not even cluster.view. The one permission it does need is plugins.view: every portal call goes through the plugin API, which checks it. The built-in Viewer and User roles have it; a custom role needs it ticked, otherwise every portal call answers 403 and the portal stays empty. The portal bypasses the cluster permission check and queries VM ACLs directly. Each action then needs two things: the hoster offers it in the plugin's config.json (see Allowed actions), and the user holds the matching permission on that guest, through a VM permission, a pool grant or their role.
💡 How ACL matching works: For each connected cluster, the portal loads all VM ACLs and checks if the authenticated username appears in the users list of any VM. A wildcard * in the users list grants access to all users. The portal never exposes cluster configuration, node details, or VMs without an ACL entry.
Portal-Only Users
Users with the portal_only flag can only log in via /portal. If they try to access the main dashboard at /, they are immediately logged out. This is enforced both during login (the main dashboard rejects portal-only sessions) and during session restore (navigating to / with an existing portal session triggers an automatic logout). Set this flag when creating or editing users in Settings → Users (the "Portal Only" checkbox).
Hoster Configuration
The portal is configured via plugins/client_portal/config.json (editable in Settings → Plugins → Edit; the file is in the plugin folder of your install, and from 1.4.0 an update keeps it):
| Setting | Default | Description |
|---|---|---|
portal_title |
"Client Portal" | Title shown in the portal header and login page |
allowed_actions |
["vm.view", "vm.start", "vm.stop", "vm.console"] | Which actions customers can perform |
allow_snapshots |
true | Enable snapshot management for customers |
max_snapshots_per_vm |
5 | Maximum snapshots a customer can create per VM |
allow_password_change |
true | Allow customers to change their own password |
show_resource_usage |
true | Show CPU/RAM/disk bars on VM cards |
show_ip_addresses |
true | Show VM IP addresses (requires guest agent) |
theme_color |
"#e57000" | Accent color for the portal UI |
custom_logo_url |
"" | URL to custom logo shown in the portal header |
Allowed actions
allowed_actions lists what the portal offers at all, and the portal asks it first: an action the hoster does not list is refused with "Action not allowed by hoster", whatever the user may do elsewhere in PegaProx. An action the hoster lists still needs the user's own permission on that guest.
| Portal button | Entry in allowed_actions |
Permission the user needs on the guest |
|---|---|---|
| Start | vm.start |
vm.start |
| Shutdown, Stop | vm.stop |
vm.stop |
| Reboot | vm.restart |
vm.restart |
| Console | vm.console |
vm.console |
The shipped list has no vm.restart, so reboot is off until the hoster adds it. To offer reboot as well:
"allowed_actions": ["vm.view", "vm.start", "vm.stop", "vm.restart", "vm.console"]
vm.view has no effect here: the portal always lists the guests the user's VM ACLs, pool grants or tenant give them. On 1.4.1 and earlier the Reboot button shows as soon as vm.start is listed, but a reboot still needs vm.restart in this list.
Snapshots, deleting a guest and creating containers are not in this list, they have switches of their own:
| Setting | Default | What the user needs as well |
|---|---|---|
allow_snapshots |
true | vm.snapshot on the guest, at most max_snapshots_per_vm snapshots |
allow_destroy |
false | The guest is one of theirs, vm.stop on it, and its name typed to confirm |
allow_ct_create with the ct_create block |
false | Room in their tenant quota |
allow_iso_mount with allowed_isos or iso_storage |
false | vm.config on the guest, QEMU guests only |
allow_password_change |
true | - |
ISO mounting offers the ISOs listed in allowed_isos (volume ids such as local:iso/debian.iso) and every ISO on the storage named in iso_storage, and puts the chosen one into a CD-ROM slot of the guest (ide2 unless the call names another of ide0-ide3 or sata0-sata5). From 1.5.0 the portal shows the ISO button when allow_iso_mount is on, and refuses every ISO call while it is off; on 1.4.1 and earlier the button does not show.
AGPL Branding
The portal includes a "Powered by PegaProx" footer with an AGPL-3.0 license notice. This footer is protected by an integrity check - removing or hiding it displays a license violation warning instead of the portal content. Hosters may add their own branding (logo, title, colors) but must not remove the PegaProx attribution.
Self-service container creation
Portal users can create LXC containers themselves (self-service) within their tenant quota. The feature is disabled by default - an administrator must enable it.
Enabling it (administrator)
Set allow_ct_create and add a ct_create block to the portal config. The block configures where and how containers are created:
| Setting | Description |
|---|---|
cluster_id |
The cluster containers are created on |
node |
The node containers are created on |
storage |
The storage used for the container root disk |
bridge |
The network bridge attached to new containers |
| allowed-templates list | The whitelist of templates portal users may choose from |
| max cores / memory / disk caps | The upper limits for CPU, memory, and disk on new containers |
Creating a container (portal user)
Once enabled, portal users get a "+Container" button. They:
- choose from the admin-whitelisted templates,
- set a hostname, and
- set resources (cores, memory, disk) within the configured caps.
Creation is quota-enforced - a request is blocked if it would exceed the tenant quota. On success, the new container is ACL-granted to its creator.
From 1.3 the configured cluster_id must be a cluster of the customer's tenant, the one its quota counts; a target outside that tenant is refused.
Security hardening
The container-creation endpoint is security-hardened: the template whitelist is enforced, resource values are clamped to the configured caps, and the hostname and password are validated.
API Endpoints
All endpoints are under /api/plugins/client_portal/api/ and require authentication via session cookie.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/plugins/client_portal/api/config |
Portal configuration (public, no secrets) |
GET |
/api/plugins/client_portal/api/my-vms |
List VMs assigned to the authenticated user |
POST |
/api/plugins/client_portal/api/vm/power |
Start/stop/shutdown/reboot a VM |
GET |
/api/plugins/client_portal/api/vm/console |
Get VNC console ticket + WebSocket token |
GET |
/api/plugins/client_portal/api/vm/snapshots |
List snapshots for a VM |
POST |
/api/plugins/client_portal/api/vm/snapshots |
Create a snapshot |
POST |
/api/plugins/client_portal/api/vm/snapshot-rollback |
Revert VM to a snapshot |
POST |
/api/plugins/client_portal/api/vm/snapshot-delete |
Delete a snapshot |
POST |
/api/plugins/client_portal/api/account/change-password |
Change the authenticated user's password |