PVE Privilege Converter
Convert an LXC container between unprivileged and privileged by backing it up and restoring it under a new ID.
Proxmox cannot flip the unprivileged flag of an existing container. pve-privilege-converter.sh automates the supported way: back the container up with vzdump and restore the backup as a new container with the opposite setting. The original container is kept.
Website entry: pve-privilege-converter. Source: tools/pve/pve-privilege-converter.sh.
Run
In the Proxmox VE host shell, as root:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/pve/pve-privilege-converter.sh)"The script installs curl if it is missing and exits with 104 if you are not root.
Prompts
All prompts are plain text in the terminal.
| Step | Prompt | Input |
|---|---|---|
| 1 | Enter number of container to convert: | Number from the list of containers (pct list). Exit code 234 if there are none. |
| 2 | Enter number of backup storage: | Number from the storages that allow content type backup. |
| 3 | (backup runs) | |
| 4 | Enter number of target storage: | Number from the storages that allow content type rootdir. |
| 5 | Suggested next free container ID: <id>. Enter new container ID [default: <id>]: | Enter for the suggestion from pvesh get /cluster/nextid, or another ID. |
| 6 | (restore runs) | |
| 7 | Shutdown source and start new container? [Y/n]: | Enter or y: shut down the original, start the new one. n: leave both as they are. |
| 8 | Timeout reached. Force shutdown? [Y/n]: (only if the original is still running after 36 checks, 5 seconds apart) | Enter or y: kills the container's lxc-start process. |
| 9 | Delete backup archive? [<path>] [Y/n]: | Enter or y: deletes the vzdump archive. n: keeps it. |
The direction is not asked. An unprivileged container becomes privileged and a privileged one becomes unprivileged.
Commands it runs
vzdump <id> --compress zstd --storage <backup storage> --mode snapshot
pct restore <new id> <archive> --storage <target storage> --unprivileged -ignore-unpack-errors 1For the direction unprivileged to privileged the restore uses --unprivileged false instead. The script exits with 235 if the backup did not finish successfully or the restore failed.
At the end a summary lists the original container, both storages, the backup path, the new ID and the direction.
Undo
The original container is never modified or deleted. To go back, stop and remove the new container and start the original again. Delete the original yourself once the new container works.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
COMMUNITY_SCRIPTS_CORE_URL | https://raw.githubusercontent.com/community-scripts/core/main | Base URL for core/core.func and api/api.func. |
Limits
- You need free space for the backup archive and for a second copy of the container's disk.
- The new container has a new ID. Backup jobs, firewall rules or scripts that refer to the old ID must be adjusted.
- Both containers have the same network configuration, including a static IP. Do not run them at the same time; answering yes at step 7 takes care of that.
- Bind mounts, device passthrough and file ownership on mounted host paths behave differently in unprivileged containers because of UID/GID mapping. Check them after converting to unprivileged.
- The restore ignores unpack errors (
-ignore-unpack-errors 1), so files that cannot be recreated in the target mode are skipped without stopping the restore. - The backup storage must produce a
tar.zstarchive path in thevzdumpoutput; otherwise the script reports "Backup failed".