Proxmox VM Self Service (PVMSS)

PVMSS is a web application that simplifies the creation of virtual machines for users without having to go through the web interface or command line of Proxmox VE.

By leaving the choice of parameters such as the amount of virtual processors and memory, the size of the virtual storage, the boot ISO image, the user will be autonomous and able to create as many virtual machines as they are authorized by the administrators. PVMSS is compatible with Proxmox VE 9.0 and above. It is not compatible with versions 8 and below because the roles have changed in PVE.

Context#

My observation in June 2025, after more than 10 years of observing and responding to needs in different situations where I have used Proxmox, is that there is a lack of on-demand virtual machine creation interface.

More recently, colleagues have asked me for machines to perform tests and be autonomous, which I could not provide on demand, at any minute.

That’s when I had the idea of “Proxmox VM Self-Service” (abbreviated PVMSS). PVMSS does not support PVE’s LXC containers.

Why not use the Proxmox web console directly?#

The creation of virtual machines in PVE is done via the web interface after authentication, or via the command line.

As a user, you can create virtual machines via the web interface, but you need to have the access and rights set up by the administrators.

However, for non-initiates, the Proxmox virtual machine creation web interface can be confusing, or even unusable. There are many parameters to choose from without knowing quickly what they are for. The Proxmox web interface is reserved for the initiated (even though their documentation is well provided).

Features for users#

  • Create a VM : Create a new virtual machine with customizable resources (CPU, RAM, storage, description, machine name, operating system).
  • Access to the VM console: integrated web client (noVNC console).
  • VM management : Start, stop, restart and delete virtual machines, resize CPU, RAM and network card quantities, choose network bridges.
  • VM search : Find virtual machines by their VMID, tag or name, or all three.
  • VM details : Display complete VM information including status, description, tags, uptime, CPU, memory, disk usage and network configuration.
  • Profile management : View your list of VMs, reset your password.
  • Multi-language : The interface is available in French and English.- Documentation : A help document for using PVMSS is available in both languages, to help users exploit PVMSS.

Features for administrators#

  • PVMSS app informations : Many informations of the state of PVMSS as an administrator.
  • Nodes management: Display the Proxmox cluster and nodes available for VM deployment.
  • User pool management : Add or remove users accessing PVMSS.
  • Tags management : Create and manage tags for VM organization.
  • ISO management : Configure ISO images available for VM installation (does not allow adding models or ISOs from PVMSS).
  • Network configuration: Manage accessible network bridges (VMBRs) for VM networking, and the number of network cards a VM can have.
  • Storage management : Configure storage locations for VM disks, and the amount of virtual disk space a VM can have.
  • Resource limits : Define CPU, RAM and disk limits for VM creation, the amount of disk and network cards a VM can have (having imposed limits) and the limits a Proxmox node can support for PVMSS.

User interface#

Todo

Administrator interface#

Todo

An administration interface for the application allows administrators to limit resources, organize and distribute everything necessary for users.

Thus, the choice of ISO images, tags, network bridges, and resource limits for VMs are in the hands of administrators.

Workflow#

You must create two secrets, one for the local security of the PVMSS application and the other for the password of the local administrator account of PVMSS.

For the first, you can freely enter what you wish or use, for example, the result of the command openssl rand -hex 32. For the administrator account password, you will need to enter the result of a bcrypt hash. You can easily create this hash with the htpasswd utility under Linux: htpasswd -bnBC 12 "" my_secret_password | cut -d : -f 2 (source ).

Before deploying PVMSS, the administrator must prepare the Proxmox server. You need to create an API token (token api), then add the necessary rights for the proper functioning of the PVMSS application.

Creation of the API token in command line and assignment of rights: TODO

Via the Proxmox web interface:

  • go to Datacenter > Permissions > Users
  • click on the Add button, enter the username, select the realm (realm) on “Proxmox VE Authentication” and enter a strong password (you will not need the password, but it is crucial to put one to avoid abuse of connection with this privileged account). For the example, I created a user “jhdocker”.
  • then, go to Datacenter > Permissions > API Tokens
  • click on the Add button, select the user you just created (jhdocker@pve) and enter a name for the API token.
  • by clicking on the ‘Add’ button of the form, the API token secret will be displayed only once. Copy the secret to a secure location, you will need it for the proper functioning of the app. For the example, my token is called “test”
  • finally, go to Datacenter > Permissions, click on the “Add” button then on API Token Permissions, select the path “/” and your API token that you just created (in my case, “jhdocker@pve!test”), select the role “PVEAdmin”, and check the “propagate” box.

Once the application is started, access the administration interface by logging in as an administrator and the password you generated. Then navigate through the different tabs on the left of the application to apply, activate and create your configuration according to your environment. Finally, create users from PVMSS. The creation of these users via PVMSS will use the API token to create local accounts on the Proxmox server, create a specific pool for the user and assign the necessary rights. Thus, each user will have their own personal space for their virtual machines, which will not be visible to other users.

Configure the environment variables#

You can use the provided example file env.example to create your own .env file. Or you can modify the example file directly.

  • ADMIN_PASSWORD_HASH : A bcrypt hash of the password for the administration panel. You can generate one using an online tool or a simple script
  • LOG_LEVEL : Set the log level of the application: INFO or DEBUG (default: INFO).
  • PROXMOX_API_TOKEN_NAME : The name of your Proxmox API token for backend operations (e.g., user@pve!token).
  • PROXMOX_API_TOKEN_VALUE : The secret value of your API token.
  • PROXMOX_URL : The complete URL to your Proxmox API endpoint (e.g., https://proxmox.example.com:8006/api2/json).
  • PROXMOX_VERIFY_SSL : Set to false if you are using a self-signed certificate on Proxmox (default: false).
  • PVMSS_ENV : “prod” or “dev”, this argument will be used to unlock or freeze some features
  • PVMSS_OFFLINE : When your Proxmox node is not reachable, but you want to access the application without making API calls, set this option to “true”. Thus, you will be able to configure some options of PVMSS
  • PVMSS_SETTINGS_PATH : The default path in the app to store its configuration can be modified, it is not useful for the moment, but the option exists.
  • SESSION_SECRET : Secret key for session encryption (change to a random unique string, for example $ openssl rand -hex 32)
    environment:
      # Proxmox VE settings
      PROXMOX_API_TOKEN_NAME: "nom_user_pvmss@pve!nom_jeton_api"
      PROXMOX_API_TOKEN_VALUE: "aaaaaaaa-0000-44aa-1111-aaaaaaaaaaa"
      PROXMOX_URL: "https://ip-or-name:8006/api2/json"
      PROXMOX_VERIFY_SSL: false
      # PVMSS settings
      ADMIN_PASSWORD_HASH: "$2y$10$Ppg7Wl3sNYrmxZmWgcq4reOyznt7AeqMrQucaH4HY.dBrzavhPP1e"
      LOG_LEVEL: "INFO"
      SESSION_SECRET: "changeMeWithSomethingElseUnique"
      PVMSS_ENV: "prod" # Environment: production/prod or development/dev/developpement
      PVMSS_OFFLINE: "false"
      PVMSS_SETTINGS_PATH: "/app/settings.json"
      TZ: "Europe/Paris"

Launch the container#

Create the settings.json file that will be used by PVMSS to store its configurations:

{
  "tags": ["pvmss"],
  "isos": [],
  "vmbrs": [],
  "max_network_cards": 1,
  "max_disk_per_vm": 1,
  "enabled_storages": [],
  "limits": {
    "nodes": {},
    "vm": {
      "cores": {
        "max": 2,
        "min": 1
      },
      "disk": {
        "max": 12,
        "min": 6
      },
      "ram": {
        "max": 4,
        "min": 1
      },
      "sockets": {
        "max": 1,
        "min": 1
      }
    }
  }
}

Create the docker-compose.yml file and enter this content:

---
services:
  pvmss:
    image: jhmmt/pvmss:0.4.0
    container_name: pvmss
    restart: unless-stopped
    ports:
      - "50000:50000/tcp"
    # Use either the .env file for environment variables
    # or the environment variables in the docker-compose.yml file.
    # env_file:
    #  - .env
    environment:
      # Proxmox VE settings
      PROXMOX_API_TOKEN_NAME: "tokenName@changeMe!value"
      PROXMOX_API_TOKEN_VALUE: "aaaaaaaa-0000-44aa-1111-aaaaaaaaaaa"
      PROXMOX_URL: "https://ip-or-name:8006/api2/json"
      PROXMOX_VERIFY_SSL: "false"
      # PVMSS settings
      ADMIN_PASSWORD_HASH: "$2y$10$Ppg7Wl3sNYrmxZmWgcq4reOyznt7AeqMrQucaH4HY.dBrzavhPP1e"
      LOG_LEVEL: "INFO"
      SESSION_SECRET: "changeMeWithSomethingElseUnique"
      PVMSS_ENV: "prod" # Environment: production/prod or development/dev/developpement
      PVMSS_OFFLINE: "false"
      PVMSS_SETTINGS_PATH: "/app/settings.json"
      TZ: "Europe/Paris"
    volumes:
      - ./settings.json:/app/settings.json
    deploy:
      resources:
        limits:
          cpus: "1"
          memory: 64M

With Docker running, execute the following command from the project root docker compose up -d, or launch the container with docker run :

docker run -d \
  --name pvmss \
  --restart unless-stopped \
  -p 50000:50000 \
  -v $(pwd)/settings.json:/app/settings.json \
  -e ADMIN_PASSWORD_HASH="$2y$10$Ppg7Wl3sNYrmxZmWgcq4reOyznt7AeqMrQucaH4HY.dBrzavhPP1e" \
  -e LOG_LEVEL=INFO \
  -e PROXMOX_API_TOKEN_NAME="tokenName@changeMe!value" \
  -e PROXMOX_API_TOKEN_VALUE="aaaaaaaa-0000-44aa-1111-aaaaaaaaaaa" \
  -e PROXMOX_URL=https://ip-or-name:8006/api2/json \
  -e PROXMOX_VERIFY_SSL=false \
  -e PVMSS_ENV="prod" \
  -e PVMSS_OFFLINE="false" \
  -e PVMSS_SETTINGS_PATH="/app/settings.json" \
  -e SESSION_SECRET="$(openssl rand -hex 32)" \
  -e TZ=Europe/Paris \
  jhmmt/pvmss:0.4.0

The application will be available at http://localhost:50000.

Consult the logs#

Via the docker command line : docker logs -f pvmss.

Find the images on the docker hub at this address : https://hub.docker.com/r/jhmmt/pvmss/tags

Deployment of the application in Kubernetes#

A manifest containing all the necessary information is available at the root of this repository, named pvmss-deployment.yaml. This manifest contains :

  • A namespace
  • A service account
  • A secret
  • A configmap
  • A persistent volume claim (pvc)
  • A deployment
  • A service
apiVersion: v1
kind: Namespace
metadata:
  name: pvmss
---
apiVersion: v1
kind: ServiceAccount
automountServiceAccountToken: true
metadata:
  name: pvmss-sa
  namespace: pvmss
---
apiVersion: v1
kind: Secret
metadata:
  name: pvmss-secrets
type: Opaque
data:
  admin-password: changemebase64hash
  pve-api-token: changemebase64hash
  session-secret: changemebase64hash
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: pvmss-config
data:
  settings.json: |
    {
        "tags": [
            "pvmss"
        ],
        "isos": [],
        "vmbrs": [],
        "max_network_cards": 1,
        "max_disk_per_vm": 1,
        "enabled_storages": [],
        "limits": {
            "nodes": {},
            "vm": {
                "cores": {
                    "min": 1,
                    "max": 4
                },
                "disk": {
                    "min": 6,
                    "max": 12
                },
                "ram": {
                    "min": 1,
                    "max": 4
                },
                "sockets": {
                    "min": 1,
                    "max": 1
                }
            }
        }
    }
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvmss-settings-pvc
  namespace: pvmss
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: "" # Use default storage class
---
kind: Deployment
metadata:
  name: pvmss
  namespace: pvmss
labels:
  app.kubernetes.io/name: pvmss
  app.kubernetes.io/instance: pvmss
  app.kubernetes.io/version: 0.4.0
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app.kubernetes.io/name: pvmss
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pvmss
    spec:
      automountServiceAccountToken: true
      serviceAccountName: pvmss-sa
      securityContext:
        runAsUser: 65532
        runAsGroup: 65532
        fsGroup: 65532
        fsGroupChangePolicy: OnRootMismatch
      terminationGracePeriodSeconds: 5
      restartPolicy: Always
      containers:
        - name: pvmss
          image: jhmmt/pvmss:0.4.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: backend
              containerPort: 50000
              protocol: TCP
          env:
            - name: ADMIN_PASSWORD_HASH
              valueFrom:
                secretKeyRef:
                  name: pvmss-secrets
                  key: admin-password
            - name: LOG_LEVEL
              value: "INFO"
            - name: PROXMOX_API_TOKEN_NAME
              value: "changeme"
            - name: PROXMOX_API_TOKEN_VALUE
              valueFrom:
                secretKeyRef:
                  name: pvmss-secrets
                  key: pve-api-token
            - name: PROXMOX_VERIFY_SSL
              value: "false"
            - name: PROXMOX_URL
              value: "https://changeme:8006/api2/json"
            - name: SESSION_SECRET
              valueFrom:
                secretKeyRef:
                  name: pvmss-secrets
                  key: session-secret
            - name: PVMSS_ENV
              value: "production" # Can be 'dev', 'developpement', 'prod'
            - name: PVMSS_OFFLINE
              value: "false" # Set to true to disable Proxmox connection
            - name: PVMSS_SETTINGS_PATH
              value: "/data/settings.json"
            - name: TZ
              value: "Europe/Paris"
          volumeMounts:
            - name: pvmss-settings
              mountPath: /data
              readOnly: false
          resources:
            requests:
              memory: "64Mi"
              cpu: "25m"
            limits:
              memory: "128Mi"
              cpu: "50m"
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          volumes:
            - name: pvmss-settings
              persistentVolumeClaim:
                claimName: pvmss-settings-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: pvmss
  namespace: pvmss
spec:
  selector:
    app.kubernetes.io/name: pvmss
    app.kubernetes.io/instance: pvmss
    app.kubernetes.io/version: 0.4.0
  ports:
    - name: backend
      protocol: TCP
      port: 50000
      targetPort: 50000

To deploy the application in Kubernetes, run the following command : kubectl apply -f pvmss-deployment.yaml.

Limitations of PVMSS#

  • No rigorous security tests have been conducted, be careful when deploying.
  • No (yet) OpenID Connect support.
  • Only a local administrator at PVMSS can manage the application, there is no possibility yet to create additional administrators.

The technical stack#

Based on the Go language for the engine (backend) and HTML and CSS for the user interface (frontend), I want to keep the tool as simple as possible technically. The sources are available on GitHub at this address .

Licence#

PVMSS is licensed under “Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International”. For more information, visit https://creativecommons.org/licenses/by-nc-nd/4.0/ .

Divers#

Proxmox VE (PVE) is a suite of tools under Debian 13 that allows you to have a virtualized infrastructure for your needs. Provided for free and with a paid support service, PVE is accessible and is taking up more and more space in different contexts.

To install Proxmox in Debian 13, you can find an article I wrote here https://j.hommet.net/installer-proxmox-sur-debian/ .

#pvmss
10 minutes
2077 words