Your Ubuntu server was installed without encryption, and you need root (and any swap logical volume on the same volume group) on LUKS without reinstalling. This online LVM migration:
- Adds a spare disk or partition
- Lays down LUKS2 on the spare
pvmoveextents from the unencrypted source PV onto the encrypted PV- Drops the old PV
- Wires
crypttaband the initramfs so early boot unlocks LUKS before LVM mounts root
Before migration:
- Logical volumes stay in place — only the physical volume underneath moves from plaintext disk into LUKS
/bootmust remain on a separate, unencrypted partition so GRUB can load the kernel before unlock
The walkthrough below uses one reference layout (single source PV, separate /boot, spare disk for LUKS). Substitute your device names, VG name, and mapper name in every command.
At boot after migration, the stack looks like this:
/boot (unencrypted) → GRUB loads kernel + initramfs
initramfs unlocks LUKS on <spare-partition> → /dev/mapper/<name>
LVM activates <vg-name> on encrypted PV → root LV (/) [+ swap LV if present]Reference example: source PV /dev/sda3, spare LUKS /dev/sdb1, mapper secret, VG ubuntu-vg.
LUKS wraps the physical volume, not individual files on /:
- Your ext4 root filesystem stays inside the same logical volume.
- Only the underlying PV moves from plaintext disk to an encrypted mapper.
| If you need… | Go to… |
|---|---|
| Command reference without the walkthrough | cryptsetup cheat sheet |
| Encrypt a new secondary data disk | Encrypt a disk partition with LUKS |
| Rotate passphrases after migration | Change LUKS passphrases and reencrypt |
The pvmove, cryptsetup, and LVM commands work the same on any distribution that uses LVM root; examples below use Ubuntu package names (apt, update-grub, update-initramfs).
Tested on: Ubuntu 26.04 LTS (Resolute Raccoon); kernel 7.0.0-27-generic; cryptsetup 2.8.4.
What you need on your system
A spare disk or partition is mandatory—you cannot safely luksFormat the PV that still holds your running root. pvmove copies allocated extents to the spare first; only then can you remove the old PV.
Size the spare from LVM, not from df on /:
- At minimum, ≥
pv_usedon the source PV—every extent on that PV (root, swap, and any other LVs there), plus a small margin for the LUKS header. - When the VG fills the source PV (
PFree0), plan for a spare at least as large as the source PV itself—in the reference layout, a 23 GiB source PV needs a ~25 GiB spare, not merely the ~19 GiB root filesystem.
Before luksFormat or pvmove, identify these on your host and write them down. Every command below uses the example names in the last column—replace them with yours.
| You need | How to find it | Example in this guide |
|---|---|---|
| Source PV — unencrypted PV with root extents (and any other LVs on that same PV) | sudo pvs; sudo lvs -o devices |
/dev/sda3 |
| VG containing root — volume group that owns the source PV and root LV | sudo pvs or sudo vgs; VG column on your source PV |
ubuntu-vg |
| Root LV | findmnt /; sudo lvs |
ubuntu-lv → /dev/mapper/ubuntu--vg-ubuntu--lv |
Other LVs on the source PV — everything pvmove will move off that disk |
sudo lvs -o lv_name,vg_name,devices |
swap_1 on /dev/sda3(4864) |
/boot partition — must be outside the root LV |
findmnt /boot |
/dev/sda2 |
| Spare partition (required) — second disk or empty partition for the new LUKS PV | lsblk; compare to pvs pv_used / pv_size on source PV |
/dev/sdb1 (25 G spare for 23 G source PV) |
Mapper name — your choice for cryptsetup open |
you pick once; reuse in crypttab | secret |
Also confirm:
- Swap layout — root + swap LVs on the same source PV need one
pvmove; a swap file on/needs no extra step; a swap partition outside the VG is outside this walkthrough. - Other LVs in the same VG —
pvmovemoves all extents on the source PV, not only root. If/home,var, or data LVs sit on that PV, they move with it. LVs on other PVs in the same VG stay where they are. - Multi-PV root — if
lvs -o deviceslists more than one PV for root, you need onepvmoveper source PV and a spare large enough for the combinedpv_usedfrom every PV you will empty (see multi-PV section).
Inspect your layout
Run these checks on your host before you touch disks. Write down:
- Source PV — partition holding LVM extents (example
sda3) /boot— separate unencrypted partition (examplesda2)- Spare partition — empty space for LUKS (example
sdb1) - LVs on the source PV — everything
pvmovewill move (root, swap, others)
List block devices and mount points:
sudo lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTReference layout (single-PV Ubuntu install—your names and sizes will differ):
NAME SIZE TYPE FSTYPE MOUNTPOINT
sda 25G disk
├─sda2 2G part ext4 /boot
└─sda3 23G part LVM2_member
├─ubuntu--vg-ubuntu--lv 19G lvm ext4 /
└─ubuntu--vg-swap_1 4G lvm swap [SWAP]
sdb 25G disk
└─sdb1 25G partIn the reference layout:
sda3— source PV (LVM2_member); root mounts fromubuntu--vg-ubuntu--lv, not fromsda3directlysda2—/bootsdb1— empty spare for LUKS
df on / only reports filesystem use inside the root LV (~19 GiB here). pvmove copies every allocated extent on the source PV—including swap—so size the spare from pvs:
sudo pvs -o pv_name,vg_name,pv_size,pv_used,pv_freePV VG PSize Used PFree
/dev/sda3 ubuntu-vg <23.00g <23.00g 0On /dev/sda3 in the reference layout:
pv_used~23 GiB — migration size (notdfon/)- Root LV ~19 GiB — the rest is swap LV + LVM metadata
PFree0 — VG fills the PV; plan a spare ≥PSize, not just root filesystem size
See which LVs share the source PV (all of them move in one pvmove):
sudo lvs -o lv_name,vg_name,lv_size,devicesLV VG LSize Devices
ubuntu-lv ubuntu-vg <19.00g /dev/sda3(0)
swap_1 ubuntu-vg <4.00g /dev/sda3(4864)The numbers in parentheses are extent offsets on the same PV—both lines are normal.
Confirm / is on an LV and /boot is a separate partition:
findmnt /
findmnt /boot
swapon --showTARGET SOURCE FSTYPE OPTIONS
/ /dev/mapper/ubuntu--vg-ubuntu--lv ext4 rw,relatime
TARGET SOURCE FSTYPE OPTIONS
/boot /dev/sda2 ext4 rw,relatime
NAME TYPE SIZE USED PRIO
/dev/dm-1 partition 4G 0B -1When root spans more than one physical volume
Some installs spread one root LV across multiple source PVs. In that case:
- Create LUKS on a separate spare partition (not on any disk that still holds source PV extents).
- Open it with your mapper name.
- Run one
pvmoveper source PV, thenvgreduce/pvremoveeach emptied PV.
Example when source PVs are /dev/sda3 and /dev/sdb3 and spare LUKS is /dev/sdc1:
sudo pvmove /dev/sda3 /dev/mapper/secret
sudo pvmove /dev/sdb3 /dev/mapper/secret
sudo vgreduce ubuntu-vg /dev/sda3 && sudo pvremove /dev/sda3
sudo vgreduce ubuntu-vg /dev/sdb3 && sudo pvremove /dev/sdb3lvs -o devices lists every PV that still holds extents:
sudo lvs -o lv_name,vg_name,lv_size,devicesLV VG LSize Devices
ubuntu-lv ubuntu-vg 58.41g /dev/sda3(0)
ubuntu-lv ubuntu-vg 58.41g /dev/sdb3(0)The same LV on two PV lines means two source PVs:
- Run
pvmoveonce per PV you empty - Boot wiring still uses one
crypttabline withluks,initramfsfor the single new LUKS partition (example/dev/sdc1)
Take two backups before luksFormat or pvmove:
- Filesystem-level backup of
/(and other mounted LVs you care about). - A LUKS header backup after you create the new encrypted container (step in Create LUKS2 on the spare partition)—header backup preserves metadata and slots; it does not replace a full root backup.
Prerequisites
You already mapped devices in What you need on your system. Before proceeding, confirm:
| Requirement | Why |
|---|---|
Separate unencrypted /boot |
GRUB loads kernel and initramfs from /boot before LUKS unlock—see check below |
| Spare disk or partition (required) | Second disk/partition ≥ pv_used on source PV—often ≥ full source PV size when the VG is full; not the same as df on / |
| Valid root backup | pvmove and luksFormat are destructive on mistakes |
cryptsetup, lvm2, cryptsetup-initramfs |
Install before the initramfs step—see command below |
| Maintenance window | pvmove duration scales with moved data; plan for a reboot after boot wiring |
| Console or serial access for first reboot | Initramfs prompts for the LUKS passphrase before root mounts |
Install packages:
sudo apt update
sudo apt install -y cryptsetup lvm2 cryptsetup-initramfscryptsetup-initramfs hooks crypttab into the initramfs on Ubuntu and Debian—install it before the boot wiring step.
Every privileged command below assumes sudo command on a root-capable shell.
Confirm /boot is a separate, unencrypted mount—not inside the root LV you are moving:
findmnt /bootTARGET SOURCE FSTYPE OPTIONS
/boot /dev/sda2 ext4 rw,relatimeThe source should be a disk partition, not a path under /dev/mapper/ubuntu--vg-….
/boot is inside the root LV you are moving under LUKS. GRUB must read an unencrypted /boot before the initramfs unlocks LUKS.
Reference layout for the commands below (replace every device and name with yours):
| Role | Example device |
|---|---|
| Source PV (unencrypted root + swap LVs) | /dev/sda3 in VG ubuntu-vg |
/boot (stays unencrypted) |
/dev/sda2 |
| Spare LUKS partition (new encrypted PV) | /dev/sdb1 |
| LUKS mapper name | secret → /dev/mapper/secret |
Create LUKS2 on the spare partition
Partition your spare disk if needed. On the spare partition only:
luksFormatwrites a new LUKS header- Any existing data on that partition is destroyed — back up first
luksFormat only on the spare partition (example /dev/sdb1), never on the source PV that still holds your running root (example /dev/sda3).
Format the spare partition as LUKS2, open the mapper, and back up the header before pvcreate:
sudo cryptsetup luksFormat --type luks2 /dev/sdb1
sudo cryptsetup open /dev/sdb1 secret
sudo cryptsetup luksHeaderBackup \
--header-backup-file /root/sdb1-luks-header.bin \
/dev/sdb1
sudo chmod 600 /root/sdb1-luks-header.binAfter luksFormat, open, and header backup:
luksFormat— warns the spare partition will be overwritten; confirm when promptedcryptsetup open— silent on success;/dev/mapper/secretappears when the passphrase is acceptedluksHeaderBackup— silent on success; confirm withls -lon the backup file
ls -l /root/sdb1-luks-header.bin-rw------- 1 root root 16777216 ... /root/sdb1-luks-header.binStore the header backup safely:
- Copy it offline (not only on the same disk)
- It protects against header damage
- It does not replace a full root filesystem backup
See LUKS header backup and restore for restore steps.
Only add --cipher or --key-size when a policy explicitly requires specific encryption parameters.
Create the encrypted physical volume on the mapper:
sudo pvcreate /dev/mapper/secretPhysical volume "/dev/mapper/secret" successfully created.LVM now treats /dev/mapper/secret as the PV—encryption sits underneath.
Extend the volume group
Add the encrypted PV to your VG (example ubuntu-vg):
sudo vgextend ubuntu-vg /dev/mapper/secretVolume group "ubuntu-vg" successfully extendedBoth PVs should appear in the VG before you move extents:
sudo pvsPV VG Fmt Attr PSize PFree
/dev/mapper/secret ubuntu-vg lvm2 a-- <24.99g <24.99g
/dev/sda3 ubuntu-vg lvm2 a-- <23.00g 0The encrypted PV needs enough PFree to absorb all of pv_used from /dev/sda3.
Move root and swap extents
Move all extents off the unencrypted PV onto the encrypted mapper.
While pvmove runs:
- Logical volumes stay mounted—root keeps serving, but I/O may be slower.
- Large volumes can take tens of minutes to hours.
- Do not reboot or detach disks mid-run.
- If
pvmovestops mid-run, runsudo pvmoveagain without PV arguments to resume from the last checkpoint.
For a single source PV (example /dev/sda3):
sudo pvmove /dev/sda3 /dev/mapper/secretWhen the move finishes:
/dev/sda3: Moved: 100.00%sudo pvsPV VG Fmt Attr PSize PFree
/dev/mapper/secret ubuntu-vg lvm2 a-- <24.99g 1.99g
/dev/sda3 ubuntu-vg lvm2 a-- <23.00g <23.00g/dev/sda3 should show all space as PFree; LVs now list /dev/mapper/secret in lvs -o devices.
Drop the emptied source PV from the VG:
sudo vgreduce ubuntu-vg /dev/sda3
sudo pvremove /dev/sda3Removed "/dev/sda3" from volume group "ubuntu-vg"
Labels on physical volume "/dev/sda3" successfully wiped.Root and swap LVs now live on /dev/mapper/secret backed by the spare LUKS partition. Before reboot:
- Leave the mapper open — the running system still needs it
- Finish crypttab and initramfs wiring first
Configure crypttab and initramfs
Early boot must unlock the spare LUKS partition before LVM activates the VG and mounts /. On Ubuntu and Debian with initramfs-tools:
- Add the LUKS device to
/etc/crypttab - Include the
initramfsoption on that line - Regenerate initramfs and run
update-grub
Do not use rd.luks.uuid= as the primary path here—that belongs to dracut-based distributions (Fedora, RHEL).
Collect the LUKS UUID from your spare partition:
sudo cryptsetup luksUUID /dev/sdb14c9b0973-407f-44e4-a91b-446014832ce6Put that LUKS UUID in crypttab—not the ext4 UUID inside the root LV.
Add a line to /etc/crypttab (use your mapper name and UUID):
secret UUID=4c9b0973-407f-44e4-a91b-446014832ce6 none luks,initramfsField notes:
- Mapper name — must match
cryptsetup openduring migration (examplesecret). - UUID — LUKS UUID of the spare partition, not the ext4 UUID inside the root LV.
initramfsoption — unlocks this device before LVM activates the volume group.
For field-by-field crypttab rules, keyfiles, and nofail options, see auto mount LUKS at boot.
If you use a dracut-based distribution (Fedora, RHEL), use kernel parameters instead of crypttab as the primary path:
rd.luks.uuid=— LUKS UUID of the spare partitionrd.lvm.lv=— root LV path
That is not the Ubuntu/Debian path used in this guide.
Regenerate the initramfs and GRUB menu:
sudo update-initramfs -u -k all
sudo update-grubupdate-initramfs rebuilds each installed kernel initrd with crypttab hooks; update-grub refreshes the boot menu:
- Use
-k allwhen multiple kernels are installed so every initrd picks up crypttab changes
update-initramfs: Generating /boot/initrd.img-6.14.0-37-generic
...
Found linux image: /boot/vmlinuz-6.14.0-37-generic
Found initrd image: /boot/initrd.img-6.14.0-37-genericTrimmed output from a typical run.
Verify before reboot
Before rebooting, confirm:
- LVs list only
/dev/mapper/secretinlvs -o devices - Only the encrypted PV remains in
pvs - crypttab line matches the LUKS UUID and includes
luks,initramfs - initrd contains
cryptroot/crypttabpaths
Keep a rescue image or live USB until the first encrypted boot succeeds.
Crypttab should match the LUKS UUID from the spare partition:
sudo grep '^secret' /etc/crypttabsecret UUID=4c9b0973-407f-44e4-a91b-446014832ce6 none luks,initramfsExpected:
- Options field includes
luks,initramfs - UUID matches
cryptsetup luksUUIDon the spare partition
Root should still mount from the same LV path as before migration:
findmnt -no SOURCE /
grep -v '^#' /etc/fstab/dev/mapper/ubuntu--vg-ubuntu--lv
UUID=9fe05bbb-e530-48ed-a8f7-461febc7329f / ext4 defaults 0 1
UUID=c254a326-948a-4ae2-993b-1659f4ddcf03 /boot ext4 defaults 0 1Expected:
- Root still mounts from
/dev/mapper/ubuntu--vg-ubuntu--lv - fstab root line uses the root LV UUID or mapper path—not the old source PV
Every LV should list only the encrypted mapper:
sudo lvs -o lv_name,vg_name,devices ubuntu-vg
sudo pvsLV VG Devices
ubuntu-lv ubuntu-vg /dev/mapper/secret(0)
swap_1 ubuntu-vg /dev/mapper/secret(4864)
PV VG Fmt Attr PSize PFree
/dev/mapper/secret ubuntu-vg lvm2 a-- <24.99g 1.99gConfirm cryptsetup hooks are in the initrd for your running kernel:
lsinitramfs /boot/initrd.img-$(uname -r) | grep -E 'cryptroot|crypttab|cryptsetup'cryptroot
cryptroot/crypttab
scripts/local-top/cryptroot
usr/bin/cryptsetup
usr/lib/cryptsetupMissing cryptroot or crypttab paths usually means:
update-initramfsdid not run after editing/etc/crypttab- Wrong kernel initrd checked — use
uname -rin the path
Reboot and confirm unlock
Reboot only after you have console or serial access. At boot you should see:
- Initramfs prompts for the LUKS passphrase you set on the spare partition.
- Spare partition unlocks as your mapper (example
/dev/mapper/secret). - Your VG activates and the existing root LV mounts.
After login, root should still be on the root LV, with LVs backed only by the encrypted PV:
findmnt -no SOURCE /
sudo lvs -o lv_name,vg_name,devices ubuntu-vg
sudo pvs/dev/mapper/ubuntu--vg-ubuntu--lv
LV VG Devices
ubuntu-lv ubuntu-vg /dev/mapper/secret(0)
swap_1 ubuntu-vg /dev/mapper/secret(4864)
PV VG Fmt Attr PSize PFree
/dev/mapper/secret ubuntu-vg lvm2 a-- <24.99g 1.99gThe old source PV should no longer appear in pvs.
If your layout includes a swap LV on the same volume group and you use hibernation:
- Verify
/etc/initramfs-tools/conf.d/resume(or the resume configuration for your distribution). - The swap LV UUID usually does not change after
pvmove, but confirm before relying on resume.
Wipe the old plaintext PV after successful boot
pvremove only drops LVM metadata—it does not erase plaintext on the old source PV. After a successful encrypted boot:
- Wipe the old source PV partition (example
/dev/sda3) so root data is not left in plaintext - Leave
/bootand the LUKS partition untouched
Confirm the source PV is gone from LVM and root lives on the LUKS disk before you erase plaintext:
sudo pvs
sudo lvs -o lv_name,vg_name,devices ubuntu-vg
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTPV VG Fmt Attr PSize PFree
/dev/mapper/secret ubuntu-vg lvm2 a-- <24.99g 1.99g
LV VG Devices
ubuntu-lv ubuntu-vg /dev/mapper/secret(0)
swap_1 ubuntu-vg /dev/mapper/secret(4864)
NAME SIZE TYPE FSTYPE MOUNTPOINT
sda 25G disk
├─sda2 2G part ext4 /boot
└─sda3 23G part
sdb 25G disk
└─sdb1 25G part crypto_LUKS
└─secret 25G crypt LVM2_member
├─ubuntu--vg-ubuntu--lv 19G lvm ext4 /
└─ubuntu--vg-swap_1 4G lvm swap [SWAP]Before wiping, confirm:
/dev/sda3absent frompvs- Every LV lists
/dev/mapper/secretonly /bootstill onsda2; root on LUKS disksdb1
Zero-fill (most disks — target only the old source PV partition):
- Re-check the device is the emptied source PV—not
/boot, not the LUKS partition, not the whole disk wipefsclears signatures;ddoverwrites the plaintext area (slow on large partitions)
sudo wipefs -a /dev/sda3
sudo dd if=/dev/zero of=/dev/sda3 bs=16M status=progress conv=fsyncDiscard on SSDs that support TRIM:
- Success is silent (exit code 0)
- Some virtual disks reject discard—use zero-fill instead
- Do not wipe the whole boot disk; leave
/boot(examplesda2) untouched
sudo blkdiscard /dev/sda3After migration: unattended unlock
| Approach | Guide |
|---|---|
| Tang + Clevis NBDE | Network-bound disk encryption |
| TPM2 / FIDO2 / recovery key | systemd-cryptenroll |
Keep at least one unlock path until unattended boot is proven:
- Passphrase or recovery slot stays available
- Test unattended unlock on console and through a full reboot cycle before removing it
Troubleshooting
pvmove fails with insufficient free extents
The encrypted PV is too small for the extents still on the source PV. Work through:
- Confirm demand:
sudo pvs -o pv_name,pv_used,pv_freeandsudo lvs -o lv_name,seg_pe_ranges,devices - Grow the underlying partition if needed
- Keep the LUKS mapper open, resize the mapping, then resize the LVM PV
sudo cryptsetup resize secret
sudo pvresize /dev/mapper/secretcryptsetup resize grows the LUKS payload to the partition edge; pvresize tells LVM the PV is larger. Then:
- Confirm
PFreeon the encrypted PV is enough for remaining extents - Retry
pvmove
Boot drops to emergency shell
Common causes:
- LUKS UUID mismatch in
/etc/crypttab. - Missing
initramfsoption on the crypttab line. update-initramfs -u -k allskipped after editing crypttab.
Fix the crypttab line, then regenerate initramfs and reboot:
- Match UUID with
cryptsetup luksUUIDon the spare partition - Run
sudo update-initramfs -u -k all
From a live environment, substitute your LUKS partition, VG name, root LV path, and /boot device:
sudo cryptsetup open /dev/sdb1 secret
sudo vgchange -ay ubuntu-vg
sudo mount /dev/mapper/ubuntu--vg-ubuntu--lv /mnt
sudo mount /dev/sda2 /mnt/bootFrom a live environment:
cryptsetup openthe spare LUKS partitionvgchange -ayactivates the VG after unlock- Mount root LV, then
/bootfor chroot-style repair
System boots unencrypted old disk
- Firmware may still boot the wrong disk—check BIOS boot order.
- GRUB may point at the old PV—re-run
update-grub.
Endless passphrase prompt at boot
Usually one of:
- LUKS UUID in crypttab does not match
blkidon your spare partition. - Mapper name does not match what initramfs expects.
initramfsmissing from the crypttab options field.
Compare sudo blkid on the spare partition with /etc/crypttab and re-run update-initramfs -u -k all.
References
- pvmove(8)
- vgreduce(8)
- cryptsetup(8)
- crypttab(5) — Ubuntu
- cryptsetup initramfs support — Debian
- update-initramfs(8) — Ubuntu
Summary
- Map your layout (
lsblk,pvs,lvs); confirm a spare disk or partition large enough forpv_usedon the source PV. - Confirm separate
/boot; back up root and the LUKS header. - Lay down LUKS2 on spare space;
pvmoveonto your mapper; remove the source PV. - Add
/etc/crypttabwithluks,initramfs; runupdate-initramfs -u -k all; reboot. - Wipe the old source PV after the first successful encrypted boot.
This migrates an existing LVM root filesystem to LUKS—it is not installer-time full-disk encryption.

