A safety-first script to migrate a Proxmox LXC container root filesystem from one LVM-thin volume to a new, correctly sized one.
This is intended for situations where:
- a container disk was accidentally resized to an absurd size (e.g. TB instead of GB)
- shrinking is not supported by Proxmox
- rebuilding the container is undesirable
This software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement.
This script performs low-level storage operations and may modify or permanently delete storage volumes.
If used incorrectly, it may result in data loss, system downtime, or an unbootable container.
- Do not run this in a production environment
- Test thoroughly in a non-production / lab environment first
- Ensure you have verified and restorable backups before use
In no event shall the author(s) or copyright holder(s) be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software.
Supported:
- Proxmox VE
- LXC containers
- local-lvm (LVM-thin)
- ext4 root filesystem
Not supported:
- QEMU VMs
- ZFS rootfs
- Ceph / RBD
- directory-backed storage
- bind-mounted rootfs
- Stops the container
- Allocates a new LVM-thin volume
- Temporarily mounts it inside the container
- Rsyncs / into the new volume
- Swaps rootfs in /etc/pve/lxc/.conf
- Boots the container on the new root
- Optionally deletes the old volume
git clone https://github.com/DevRanger/pve-lxc-rootfs-migrate.git
cd pve-lxc-rootfs-migrate
chmod +x pve-lxc-rootfs-migrate.shsudo ./pve-lxc-rootfs-migrate.sh --ctid <CTID> --size <GiB> [options]--ctid LXC container ID (example: 126)
--size New root filesystem size in GiB (example: 128)
--dry-run Print actions without making changes (recommended first run)
--delete-old Delete the old rootfs LV after successful migration (DESTRUCTIVE)
--yes Non-interactive mode (assume yes for prompts)
--mount Temporary mount path inside the container (default: /mnt/newroot)
--mpid Explicit mount point ID (mp0, mp1, etc). Auto-selected if omitted
--keep-mp Keep the temporary mount point in the container config (not recommended)
Dry run (recommended):
sudo ./pve-lxc-rootfs-migrate.sh --ctid 126 --size 128 --dry-runMigrate rootfs (leave old disk orphaned):
sudo ./pve-lxc-rootfs-migrate.sh --ctid 126 --size 128Migrate and delete old disk (destructive):
sudo ./pve-lxc-rootfs-migrate.sh --ctid 126 --size 128 --delete-oldFully non-interactive:
sudo ./pve-lxc-rootfs-migrate.sh --ctid 126 --size 128 --delete-old --yesInside the container:
pct enter <CTID>
df -h /Expected:
- Root filesystem reflects the new size (e.g. ~125G)
On the host:
lvs | grep vm-<CTID>If --delete-old was used, only the new disk should remain.
A backup of the container config is created automatically:
/etc/pve/lxc/.conf.bak.TIMESTAMP
Rollback steps:
- Stop the container
- Restore the backup config
- Start the container
- Rsync exit codes 23 and 24 are normal (runtime sockets / permissions)
- Always verify / is mounted on the new disk before deleting the old one
- This script intentionally avoids shrinking volumes (unsafe for LXC rootfs)
MIT