Security

Encrypt a VPS disk with LUKS on Ubuntu 24.04

Why encrypt your VPS disk?

When you provision a VPS, the hypervisor has full physical access to your virtual disk. If the host is compromised or the disk is reallocated, unencrypted data is readable. Disk encryption at rest with LUKS (Linux Unified Key Setup) wraps your entire root partition in AES-256 encryption. The only way to boot is to enter a passphrase at each reboot, the data on disk stays scrambled without it.

This matters most for: sensitive databases, private keys, configuration files with API tokens, or any regulated workload. The performance overhead on modern NVMe VPS (like thueVPS's NVMe infrastructure) is negligible, typically under 5% for sequential I/O. This guide runs on Ubuntu 24.04 LTS and uses the stock kernel with initramfs support. The same steps work on Debian 12 with minor package name changes.

Prerequisites

  • A VPS running Ubuntu 24.04 LTS (fresh install preferred).
  • Root access (sudo -i).
  • The VPS must use UEFI boot (most modern VPS do). Check with [ -d /sys/firmware/efi ] && echo "UEFI" || echo "BIOS".
  • A separate /boot partition (unencrypted). LUKS needs a small plain partition to boot from.
  • Console access to the VPS, after encryption, the boot process is interactive (type passphrase via VNC/console).
  • Backup all data before starting. Encryption repartitions your disk.

What this setup does, and what it does not

This guide encrypts the root partition (/) using LVM on top of LUKS. The /boot partition stays unencrypted because the firmware and bootloader need a readable kernel and initramfs. The swap partition (if present) is also encrypted, if the system hibernates, swap may leak plaintext data.

What it does not protect against: a running system where the passphrase is already entered (the kernel has the decrypted key in memory); cold boot attacks without physical access; or the VPS provider's management layer if they boot with your passphrase in a script (mitigated by entering it manually each time via console).

Step 1, Install cryptsetup and prepare the disk

First, install the tools and identify your root disk.

apt update && apt install -y cryptsetup lvm2
lsblk

Identify the root device, typically /dev/sda or /dev/vda. The output shows something like sda1 for boot, sda2 for root (and possibly sda3 for swap). Write down the partition layout.

We will repartition the disk. This destroys all data, ensure backups are safe.

# Example layout (yours may differ): /dev/vda1 (1G, /boot), /dev/vda2 (rest, LVM)
# We keep /boot as-is and encrypt the remaining space.

# Shrink the existing root if needed (skip if disk is empty):
# e2fsck -f /dev/mapper/ubuntu--vg-ubuntu--lv
# lvreduce -L -100G /dev/mapper/ubuntu--vg-ubuntu--lv

# Reboot into a live environment or use initramfs rescue. For simplicity, assume fresh install:
fdisk /dev/vda
# Delete root partition (number 2), create new partition that starts at same sector.
# Type 8300 for Linux filesystem. Keep /boot (partition 1) untouched.
# Write and exit.
partprobe /dev/vda
lsblk

Verify: lsblk now shows /dev/vda1 (boot, ext4) and /dev/vda2 (empty, about 40-100G).

Step 2, Create the LUKS container

Initialize the partition as a LUKS device with AES-256 encryption.

cryptsetup luksFormat /dev/vda2
# Type YES (uppercase) and enter a strong passphrase (min 12 chars, mixed case + numbers).
cryptsetup open /dev/vda2 cryptroot
# Enter the same passphrase.

Now /dev/mapper/cryptroot is an unencrypted block device backed by LUKS.

Verify:

ls -l /dev/mapper/cryptroot
# Output: lrwxrwxrwx 1 root root 7 ... /dev/mapper/cryptroot -> ../dm-0
cryptsetup status /dev/mapper/cryptroot
# Shows "type: LUKS2", "cipher: aes-xts-plain64", "keysize: 512 bits"

Step 3, Create LVM on top of LUKS

Set up LVM inside the encrypted container. This gives flexibility for later resizing.

pvcreate /dev/mapper/cryptroot
vgcreate vg_crypt /dev/mapper/cryptroot
lvcreate -L 20G -n root vg_crypt
lvcreate -L 4G -n swap vg_crypt   # match server RAM
lvcreate -l rất caoFREE -n home vg_crypt

Format the logical volumes:

mkfs.ext4 /dev/vg_crypt/root
mkfs.ext4 /dev/vg_crypt/home
mkswap /dev/vg_crypt/swap

Step 4, Mount and install the system

Mount the new encrypted volumes and copy the current system.

mount /dev/vg_crypt/root /mnt
mkdir /mnt/{boot,home}
mount /dev/vda1 /mnt/boot
mount /dev/vg_crypt/home /mnt/home
swapon /dev/vg_crypt/swap
apt install -y rsync
rsync -aAXv / --exclude={/dev,/proc,/sys,/tmp,/run,/mnt,/media,/lost+found} /mnt/
# Or, if starting from a fresh minimal install, reinstall packages (faster):
# debootstrap jammy /mnt

Bind the virtual filesystems:

mount --bind /dev /mnt/dev
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
cp /etc/resolv.conf /mnt/etc/resolv.conf

Chroot into the new system:

chroot /mnt /bin/bash
export PATH=/usr/sbin:/usr/bin:/sbin:/bin

Step 5, Configure crypttab and initramfs

The system must know to unlock the LUKS partition at boot. Find the UUID of the encrypted partition.

blkid /dev/vda2
# Output: /dev/vda2: UUID="a1b2c3d4-..." TYPE="crypto_LUKS"

Edit /etc/crypttab:

echo 'cryptroot UUID=a1b2c3d4-... none luks' >> /etc/crypttab
# Replace the UUID with your actual one.

Edit /etc/default/grub to make the initramfs find the LUKS device:

# Change GRUB_CMDLINE_LINUX to include:
GRUB_CMDLINE_LINUX="cryptdevice=UUID=a1b2c3d4-...:cryptroot root=/dev/mapper/vg_crypt-root"

Update the initramfs and grub:

update-initramfs -u -k all
update-grub
grub-install /dev/vda
# For UEFI: grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB

Verify:

cat /etc/crypttab
# Must contain the cryptroot line with UUID.
lsinitramfs /boot/initrd.img-$(uname -r) | grep crypt
# Should show cryptsetup binaries and scripts.

Step 6, Fix fstab for the new volumes

Generate the correct /etc/fstab entries using filesystem UUIDs.

blkid /dev/vg_crypt/root
blkid /dev/vg_crypt/home
blkid /dev/vg_crypt/swap
blkid /dev/vda1

Edit /etc/fstab to look like this (use your UUIDs):

# /etc/fstab
UUID=root-uuid /               ext4    defaults  0 1
UUID=home-uuid /home           ext4    defaults  0 2
UUID=boot-uuid /boot           ext4    defaults  0 2
UUID=swap-uuid none            swap    sw        0 0

Verify:

mount -a
# No error = fstab is correct.
df -h
# Shows /, /boot, /home on the new volumes.

Step 7, Reboot and test

Exit the chroot, unmount, and reboot.

exit
umount -R /mnt
reboot

During boot, the console prompts: Please enter passphrase for disk (cryptroot) on /dev/vda2:, type your passphrase. The system then continues booting normally.

Post-boot verification:

cryptsetup status /dev/mapper/cryptroot
# Shows "active"
lsblk
# /dev/vda2 -> cryptroot -> vg_crypt-root, vg_crypt-home, vg_crypt-swap
dmesg | grep crypt
# Should show successful unlock.

Troubleshooting

Problem: Boot drops to initramfs prompt with "cryptroot not found".
Run blkid inside the initramfs shell to list LUKS UUIDs. The crypttab UUID may be wrong. Reboot, edit kernel parameters (press e in GRUB) to pass cryptdevice=UUID=correct-uuid manually.

Problem: "No key available" or "Passphrase not accepted".
LUKS passphrase is case-sensitive. If you forgot it, you cannot recover data. Always test the passphrase with cryptsetup luksOpen --test-passphrase /dev/vda2 before rebooting.

Problem: System boots but can't mount root.
Check fstab UUIDs against blkid. A typo causes mount failure. Boot from a rescue live ISO, chroot in, and correct fstab.

Does LUKS encryption affect VPS performance?

On modern CPUs with AES-NI instructions and NVMe storage (like thueVPS), the overhead is typically under 5% for sequential reads/writes and under 10% for mixed workloads. Random I/O sees the most impact, but most VPS workloads are not bottlenecked by disk encryption.

Can I encrypt just one partition instead of the whole disk?

Yes. You can keep an unencrypted boot partition and encrypt only data partitions (/home, /var, /opt). This is useful if you want only specific sensitive data at rest.

What happens if I lose the LUKS passphrase?

Data is permanently unrecoverable. LUKS has no backdoor. Maintain a backup of the LUKS header (using cryptsetup luksHeaderBackup) and a separate encrypted USB key as a fallback.

Can I automate the passphrase entry at boot?

Automation defeats the purpose of encryption (the key is stored on disk). For headless servers, consider a TPM-based unlock or a network-based key server (like Tang/Clevis for NBDE). This guide does not cover network unlock, it assumes manual passphrase entry via console.

Does this work on Debian 12 or Ubuntu 22.04?

Yes. The steps are identical. On Debian, the package is cryptsetup (same name). The initramfs scripts are the same. On Ubuntu 22.04, the grub configuration path is the same; the kernel addon name changes slightly but the commands are identical.

Should I use LUKS1 or LUKS2?

Ubuntu 24.04 uses LUKS2 by default. LUKS2 supports Argon2 for key derivation (more secure than PBKDF2) and better performance. LUKS1 is needed only for legacy GRUB without cryptodisk. If your VPS boots UEFI (most today), LUKS2 is fine.

Related articles

Note: This guide is for general reference. Every system and infrastructure has its own specifics, so test each step in a safe environment and consult a qualified engineer before applying it in production.