Configuration file
With Docker and Kubernetes, you can describe the settings of Luvio in a file, luvio-config.yaml,
instead of entering them in the web console: the hypervisors, the administrator account, the
storage defaults, the directory and single sign-on. Luvio applies the file at every start.
Use it to:
- install Luvio without the setup wizard: the server is ready to use when it starts;
- keep the settings in Git, review their changes, and deploy the same settings again;
- give several servers (high availability) the same settings.
The settings the file declares are read-only in the web console. The settings it does not declare stay editable there.
How it works
Section titled “How it works”- Luvio reads the file named by the
LUVIO_CONFIG_FILEvariable when it starts. The Helm chart and the Compose files set this variable for you when you give a file. - At each start, Luvio writes to its database what the file declares, and only what differs. A start that finds everything as declared writes nothing.
- The file holds no secret: it refers to environment variables, with
${NAME}. You give the values where Luvio is deployed (a Kubernetes Secret, aconfig.envfile next to the Compose file). - If the file has an error, Luvio applies nothing of it and does not report ready
(
/readyzanswers 503). With Kubernetes, a rolling update stops at the first pod with a bad file, and the other pods keep serving. - The file is read at start only. After a change, restart Luvio (Docker) or run
helm upgrade(Kubernetes).
Examples
Section titled “Examples”Minimal: the administrator and one Proxmox VE hypervisor
Section titled “Minimal: the administrator and one Proxmox VE hypervisor”version: 1admin: password: ${LUVIO_ADMIN_PASSWORD}hypervisors: - name: pve1 type: proxmox vmStorage: local-lvm settings: PROXMOX_HOST: pve1.example.internal PROXMOX_USER: root@pam PROXMOX_PASSWORD: ${LUVIO_HYPERVISOR_PVE1_PASSWORD} NODE: pve1 SSL_INSECURE: trueWith this file and the two variables set, Luvio creates the admin account and the hypervisor
connection at its first start, and the installation is complete: the web console opens on the
sign-in page, not on the setup wizard. Sign in as admin and go on with
Templates, agent and pools.
version: 1
admin: password: ${LUVIO_ADMIN_PASSWORD}
server: publicHostname: luvio.example.com
storage: templateStorage: ceph-templates maxFillPercent: 85
hypervisors: - name: pve-paris type: proxmox enabled: true universalTemplates: true vmStorage: ceph-vm settings: PROTOCOL: https PROXMOX_HOST: pve1.paris.example.internal PROXMOX_PORT: 8006 PROXMOX_USER: root@pam PROXMOX_PASSWORD: ${LUVIO_HYPERVISOR_PVE_PARIS_PASSWORD} NODE: pve1 SSL_INSECURE: false - name: vsphere-lyon type: vmware vmStorage: datastore1 settings: VMWARE_HOST: vcenter.lyon.example.internal VMWARE_USER: luvio@vsphere.local VMWARE_PASSWORD: ${LUVIO_HYPERVISOR_VSPHERE_LYON_PASSWORD} VMWARE_DATACENTER: Lyon VMWARE_CLUSTER: Desktops VMWARE_VM_FOLDER: Luvio
ldap: enabled: true url: ldaps://dc1.example.internal:636 tlsMode: ldaps bindDn: CN=svc-luvio,OU=Service Accounts,DC=example,DC=internal bindPassword: ${LUVIO_LDAP_BIND_PASSWORD} usersBaseDn: OU=Users,DC=example,DC=internal groupsBaseDn: OU=Groups,DC=example,DC=internal rejectUnauthorized: true syncIntervalMinutes: 60
sso: oidc: - id: entra enabled: true label: Microsoft Entra ID issuer: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0 clientId: 11111111-1111-1111-1111-111111111111 clientSecret: ${LUVIO_OIDC_ENTRA_CLIENT_SECRET} saml: - id: adfs enabled: true label: AD FS idpEntityId: http://adfs.example.internal/adfs/services/trust idpSsoUrl: https://adfs.example.internal/adfs/ls/ idpCert: | -----BEGIN CERTIFICATE----- MIIC... -----END CERTIFICATE----- spPrivateKey: ${LUVIO_SAML_ADFS_SP_PRIVATE_KEY} scim: enabled: true defaultGroup: SSO Users bearerToken: ${LUVIO_SCIM_TOKEN}The easiest way to write a full file is to set Luvio up in the web console first, then export its settings.
Reference
Section titled “Reference”Every section is optional, except version. A section you leave out is not managed by the file:
it stays editable in the web console. A key that Luvio does not know is an error.
| Section | Sets | Where it is in the web console |
|---|---|---|
version |
Always 1 |
— |
admin |
The password of the first admin account |
Setup wizard |
server |
The Server URL | Administration > Server & storage |
storage |
The template storage and the maximum storage fill | Administration > Server & storage |
hypervisors |
The hypervisor connections, or none (hypervisors: []) |
Administration > Hypervisors |
ldap |
The LDAP or Active Directory directory | User Management > Settings > Authentication & Identity |
sso |
OpenID Connect and SAML providers, SCIM provisioning | User Management > Settings > Authentication & Identity |
| Key | Value |
|---|---|
password |
Password of the admin account, 8 characters or more |
Luvio creates the admin account with this password only when no administrator exists. It
never changes the password of an existing account: change it in the web console, as usual.
Without an admin section, the LUVIO_ADMIN_PASSWORD variable does the same, with or without a
file. The Helm value admin.password and the LUVIO_ADMIN_PASSWORD line of the Compose .env
file set this variable.
server
Section titled “server”| Key | Value |
|---|---|
publicHostname |
The Server URL that the agents and the desktop clients connect to: a DNS name or an IP address, without http:// and without a port |
storage
Section titled “storage”| Key | Value |
|---|---|
templateStorage |
The default storage of the templates (Template storage) |
maxFillPercent |
Maximum storage fill: a whole number from 50 to 99. Luvio does not create or copy machines on a storage that would be filled beyond it |
hypervisors
Section titled “hypervisors”A list. Each item is one hypervisor connection.
An empty list, hypervisors: [], declares an installation without a hypervisor: physical
machines only, in pools of existing machines. With an administrator, the installation is then
complete without one; without an administrator, the wizard asks only for its password. You can
still add a hypervisor in the web console later. Without a hypervisors section, the
LUVIO_NO_HYPERVISOR=true variable does the same, with or without a file; a file that lists
hypervisors wins over it.
Each item of the list:
| Key | Required | Value |
|---|---|---|
name |
Yes | The name of the connection. Luvio finds the hypervisor by this name: two items cannot have the same name |
type |
Yes | proxmox or vmware |
vmStorage |
Yes | The storage where Luvio creates the disks of the machines (VM Storage) |
enabled |
No | true (default) or false |
universalTemplates |
No | true or false: Universal Templates on this hypervisor. Left out, Luvio keeps the current setting |
settings |
Yes | The connection fields of the type, below |
Proxmox VE (type: proxmox):
| Setting | Required | Value |
|---|---|---|
PROXMOX_HOST |
Yes | Address of a Proxmox node |
PROXMOX_USER |
Yes | root@pam (see First setup) |
PROXMOX_PASSWORD |
Yes | The password, as a ${NAME} reference |
NODE |
Yes | The name of the Proxmox node (Node name) |
PROTOCOL |
No | https (default) or http |
PROXMOX_PORT |
No | 8006 (default) |
SSL_INSECURE |
No | true if Proxmox still uses the certificate it created at installation; false (default) |
PROXMOX_API_TOKEN_ID, PROXMOX_API_TOKEN_SECRET |
No | An API token, used in place of the password for the API calls. The setup wizard does not show them: leave them out, as some operations need root@pam with its password |
VMware vSphere (type: vmware):
| Setting | Required | Value |
|---|---|---|
VMWARE_HOST |
Yes | Address of the vCenter Server |
VMWARE_USER |
Yes | vCenter Single Sign-On account, for example administrator@vsphere.local |
VMWARE_PASSWORD |
Yes | The password, as a ${NAME} reference |
VMWARE_DATACENTER |
Yes | The datacenter |
VMWARE_PORT |
No | 443 (default) |
VMWARE_CLUSTER |
No | The cluster |
VMWARE_RESOURCE_POOL |
No | The resource pool |
VMWARE_VM_FOLDER |
No | The VM folder, Luvio by default |
SSL_INSECURE |
No | true or false (default) |
The account and the preparation of vCenter are in the VMware vSphere setup guide.
Things to know:
- Luvio does not test the connection before it saves it. It tests it just after, and shows a failure as a warning: the hypervisor is saved anyway, and the server reports ready.
- On Proxmox VE, Luvio discovers the other nodes of the Proxmox cluster, as the web console does.
- A hypervisor has exactly the settings of the file: a setting you remove from the file goes back to its default.
- The SSH account of Universal Templates is not in the file: set it in the web console, in the Universal Templates panel of the hypervisor. Trust the SSH host key of each node there too.
The settings of the directory, with the names of the web console:
| Key | Value |
|---|---|
enabled |
true or false |
url |
ldaps://dc1.example.internal:636, or ldap://… |
tlsMode |
ldaps, starttls or none |
bindDn, bindPassword |
The account Luvio reads the directory with. Give the password as a ${NAME} reference |
usersBaseDn, groupsBaseDn |
Where the users and the groups are |
usernameAttr, groupNameAttr, userFilter, groupFilter |
Attributes and filters |
caCert |
The certificate (PEM) of the authority of the directory |
rejectUnauthorized |
true to check the certificate of the directory |
allowJitLogin |
true or false |
defaultGroup |
A group name |
syncIntervalMinutes |
A whole number of minutes |
deprovision |
disable or none |
nestedGroups |
true or false |
With enabled: true, url, bindDn, usersBaseDn and groupsBaseDn are required. Without
bindPassword, Luvio keeps the password it has already, and shows a warning.
See the authentication guides for the meaning of each setting.
| Key | Value |
|---|---|
oidc |
A list of OpenID Connect providers |
saml |
A list of SAML providers |
scim |
SCIM provisioning: enabled, defaultGroup, bearerToken |
Each provider has an id: lowercase letters, digits, - and _, 48 characters at most, unique in
its list. Set enabled: true: a provider without it is saved, but disabled. The other keys are
the fields of the web console:
- OpenID Connect:
label,issuer,clientId,clientSecret,redirectUri,scopes,usernameClaim,groupsClaim,groupMapping,autoCreateGroups,defaultGroup. - SAML:
label,idpEntityId,idpSsoUrl,idpSloUrl,idpCert,spEntityId,spPrivateKey,callbackUrl,usernameAttr,groupAttr,groupMapping,autoCreateGroups,defaultGroup.
The file declares the whole list: with an oidc section, the OpenID Connect providers are
those of the file, and you cannot add one in the web console. A provider without its
clientSecret (or spPrivateKey), and SCIM without bearerToken, keep the secret Luvio has
already.
Secrets and variables
Section titled “Secrets and variables”Write a secret as a reference to an environment variable of the server:
| In the file | Gives |
|---|---|
${NAME} |
The value of NAME. If NAME is not set, the file is invalid |
${NAME:-default} |
The value of NAME, or default when NAME is not set or empty |
$${ |
A literal ${ |
Luvio replaces the references after it reads the YAML: a value cannot change the structure of the file, whatever characters it has.
The export suggests these names:
| Secret | Variable |
|---|---|
| Password of a hypervisor | LUVIO_HYPERVISOR_<NAME>_PASSWORD (<NAME>: the name of the hypervisor in capitals, - and other signs as _) |
| API token of a Proxmox hypervisor | LUVIO_HYPERVISOR_<NAME>_API_TOKEN_SECRET |
| LDAP bind password | LUVIO_LDAP_BIND_PASSWORD |
| OpenID Connect client secret | LUVIO_OIDC_<ID>_CLIENT_SECRET |
| SAML private key | LUVIO_SAML_<ID>_SP_PRIVATE_KEY |
| SCIM token | LUVIO_SCIM_TOKEN |
Use the file
Section titled “Use the file”Kubernetes
Section titled “Kubernetes”Put the file under config in your values file. The chart stores it in a Secret, mounts it in the
pods at /etc/luvio/config/luvio-config.yaml and sets LUVIO_CONFIG_FILE:
-
Create a Secret with the secrets of the file:
Terminal window kubectl create secret generic luvio-config-secrets -n luvio \--from-literal=pve1-password='<password of root@pam>'kubectl create secret generic luvio-admin -n luvio \--from-literal=password='<password of admin>' -
Add the file and the variables to
luvio-values.yaml:config:hypervisors:- name: pve1type: proxmoxvmStorage: local-lvmsettings:PROXMOX_HOST: pve1.example.internalPROXMOX_USER: root@pamPROXMOX_PASSWORD: ${LUVIO_HYPERVISOR_PVE1_PASSWORD}NODE: pve1configEnv:- name: LUVIO_HYPERVISOR_PVE1_PASSWORDvalueFrom:secretKeyRef:name: luvio-config-secretskey: pve1-passwordadmin:existingSecret: luvio-admin -
Install or upgrade the chart with your values file (Kubernetes).
| Value | Use |
|---|---|
config |
The content of luvio-config.yaml. The chart adds version: 1 when it is missing. Or pass your file: --set-file config=luvio-config.yaml |
configEnv |
The variables the file refers to, as env entries of the container (value, or valueFrom.secretKeyRef) |
admin.password, or admin.existingSecret (key password) |
The password of the first administrator. The chart adds the admin section to config when it has none |
existingConfigSecret |
A Secret of your own with the file under the key luvio-config.yaml, in place of config. Write ${LUVIO_ADMIN_PASSWORD} in it yourself if you use admin.* |
A change of config restarts the pods one at a time, each once the previous one is ready. With
existingConfigSecret, the chart does not see a change of the Secret: restart the pods yourself
with kubectl rollout restart statefulset/luvio -n luvio.
Docker Compose
Section titled “Docker Compose”On the single-server installation of Docker, in /opt/luvio:
-
Write the file in a
configdirectory, readable by the user of the container (uid 1000):Terminal window cd /opt/luviosudo mkdir -p configsudo nano config/luvio-config.yamlsudo chown -R 1000:1000 configsudo chmod 600 config/luvio-config.yaml -
Write the variables the file refers to in
config.env, next todocker-compose.yml, oneNAME=valueper line:Terminal window sudo sh -c 'cat > config.env <<EOFLUVIO_HYPERVISOR_PVE1_PASSWORD=<password of root@pam>EOF'sudo chmod 600 config.env -
In
docker-compose.yml, in thevolumes:of theluvioservice, remove the#in front of the./configline:volumes:- luvio-data:/var/lib/luvio- ./config:/etc/luvio/config:ro,z -
Add to
.envthe path of the file, and the password of the first administrator:Terminal window LUVIO_CONFIG_FILE=/etc/luvio/config/luvio-config.yamlLUVIO_ADMIN_PASSWORD=<password of admin> -
Apply, and read what Luvio did with the file:
Terminal window sudo docker compose up -dsudo docker compose logs luvio | grep DeploymentConfig
After a change of luvio-config.yaml, run sudo docker compose restart luvio. After a change of
config.env or .env, run sudo docker compose up -d.
:z lets the container read the file on a system with SELinux (Fedora, Red Hat Enterprise Linux
and its rebuilds).
Docker application nodes
Section titled “Docker application nodes”The application nodes work the same way: the
same config/luvio-config.yaml and the same config.env on every node, and LUVIO_CONFIG_FILE
in .env. Their compose.yml mounts ./config already.
What a start does with the file
Section titled “What a start does with the file”- Settings (
server,storage,ldap,sso): Luvio writes the values of the file. - Hypervisors: Luvio finds each one by its
name. It creates a hypervisor that does not exist, and changes one that differs from the file. It never deletes a hypervisor: one you remove from the file stays, and you can edit or delete it in the web console again. - Administrator: created only when no administrator exists.
- Installation: once an administrator and an enabled hypervisor with all its settings exist,
the installation is complete, and the setup wizard does not open. With
hypervisors: [](orLUVIO_NO_HYPERVISOR=true), an administrator is enough. - Several servers that start at the same time apply the file one after the other: the first writes, the others find nothing to change.
Settings managed by the file
Section titled “Settings managed by the file”What the file declares is managed by the deployment:
- In the web console, the setting is read-only and shows Managed by the deployment. Its tooltip says where to change it: “Set in /etc/luvio/config/luvio-config.yaml (…): change it there, then restart Luvio.”, or with Kubernetes “Set in the Helm values config.…: change them, then run helm upgrade.”
- The API refuses to change it too.
- A hypervisor of the file cannot be edited, renamed, enabled, disabled or deleted in the web console, and no other hypervisor can take its name. Its Universal Templates SSH account stays editable.
- A part that the file does not declare stays editable in the web console.
- When you remove a section from the file, Luvio keeps its last values, and they become editable in the web console again.
Install without the setup wizard
Section titled “Install without the setup wizard”With Docker Compose and Kubernetes, the installation names the database (PGHOST, PGDATABASE…
or DATABASE_URL). At its first start, Luvio builds this database when it is empty: it creates the
database if it does not exist, then its tables. Give its account the CREATEDB right, or create an
empty database that belongs to it.
The wizard then asks only for what the file does not give:
| The file declares | The first visit to the web console |
|---|---|
| The administrator and a hypervisor | The installation is complete: the sign-in page opens. Sign in as admin |
The administrator and no hypervisor (hypervisors: [] or LUVIO_NO_HYPERVISOR=true) |
The same: physical machines only |
| A hypervisor only, or no hypervisor | The wizard asks for the password of the admin account |
| The administrator only | The wizard asks for a hypervisor (optional), then sends you to the sign-in page |
| Neither | The setup wizard as usual |
Export the settings and find the differences
Section titled “Export the settings and find the differences”The Deployment configuration card is in Administration > Server & storage, with Docker, Kubernetes, or when a file is set. It shows:
- File: the file Luvio reads, or “None: LUVIO_CONFIG_FILE is not set”.
- Status: Applied, Not applied yet, or Invalid: nothing applied, and what the last start wrote.
- Errors and Warnings, each with its place in the file (for example
hypervisors[0].settings.NODE). - Managed by the file: the settings the file declares.
- Set in the console, not in the file: the settings that exist only in the database. A new installation from your file would not have them.
- Export the current settings: luvio-config.yaml, Helm values and Docker Compose.
Each opens the text, with Copy and Download, and the list of the Variables to define.
Docker Compose also gives the lines to write in
config.env.
An export never holds a secret: each secret becomes a ${NAME} reference, with the names of
the table above. It does not hold admin either.
To move an installation to a file:
- Set Luvio up in the web console, as usual.
- Export the settings (luvio-config.yaml, Helm values or Docker Compose).
- Put the file in your Git repository. Put the secrets in your secret store, never in Git.
- Deploy it, as in Use the file, with the variables of the export.
- Check the card: Applied, and Set in the console, not in the file says “Nothing”.
From then on, change the declared settings in Git and deploy them again.
Troubleshooting
Section titled “Troubleshooting”Luvio writes what it does with the file in its log, in lines that start with [DeploymentConfig]:
sudo docker compose logs luvio | grep DeploymentConfig # Dockerkubectl logs -n luvio luvio-0 -c server | grep DeploymentConfig # Kubernetes| Log line | Meaning |
|---|---|
Read <file>; it is applied once the database is ready. |
The file is valid. |
Applied <file>: … |
What the start wrote, or everything was already as declared. |
<file> is invalid: nothing of it is applied, and this server does not report ready. |
The errors follow, one per line, with their place in the file. |
<file> conflicts with the database: … |
Two hypervisors of the database have a name the file declares: rename one of them in Administration > Hypervisors. |
Failed to apply <file>; retrying in 5 s: … |
Writing to the database failed. Luvio tries again by itself. |
Declared hypervisors: and connection failed: … |
A hypervisor of the file does not answer. It is saved anyway: check the address, the account and the network. |
While the file is not applied, /readyz answers 503 and says why:
curl -s http://localhost:3080/readyz"reason":"deployment-config-invalid" comes with the errors of the file;
"reason":"deployment-config-pending" means the database is not ready yet;
"reason":"encryption-key-mismatch" means the node’s CONFIG_ENCRYPTION_KEY is not the one the
database was encrypted with, typically the key from before a rotation
(After a key rotation).
| Error | Cause and fix |
|---|---|
(file): /etc/luvio/config/luvio-config.yaml does not exist (LUVIO_CONFIG_FILE) |
Docker: the ./config volume line is still commented out, or the file is not in config/. Kubernetes: existingConfigSecret has no luvio-config.yaml key. |
(file): cannot read … EACCES |
The container (uid 1000) cannot read the file: sudo chown -R 1000:1000 config. With SELinux, the volume needs :z (./config:/etc/luvio/config:ro,z). |
environment variable NAME is not set |
Add NAME to config.env (Docker) or configEnv (Kubernetes), then docker compose up -d or helm upgrade. |
Unexpected flow-map-start … and other YAML errors |
A ${…} reference without quotes in { … }: see Secrets and variables. |
unknown key (expected one of: …) |
A misspelled key, or a key at the wrong level. The message lists the valid ones. |
version: required (version: 1) |
Add version: 1 at the top of the file. |
admin.password: must be at least 8 characters |
Give a longer password. |
an account named admin exists and is not an administrator (warning) |
An admin account with another role exists: Luvio created no administrator. |
server.publicHostname: the environment variable PUBLIC_HOSTNAME is set and wins over it (warning) |
Remove server from the file: the installation gives the address already. |