Partitioning
Different partioning schemes and their setup
- Understanding Linux file systems
- Singular file system
- Singular file system (LUKS, encrypted)
- Encrypt non-root devices (LUKS)
- LVM + dm-cache (unencrypted)
- LVM on LUKS (encrypted, Laptop)
- LUKS on LVM (encrypted, cached, Desktop)
Understanding Linux file systems
Linux supports a number of different file systems with different sets of features and intended use-cases.
Ext4: The All-rounder
Ext4 is the latest iteration of the "Extended file system" and is the default choice for most major Linux distributions. As the direct descendant of Ext2 and Ext3, it represents decades of battle-tested development, making it one of the most mature, reliable, and stable file systems for Linux.
Ext4 keeps a dedicated log (or journal) of files that are about to be written to the disk. Once the data is safely committed, it is removed from the journal. This improves file system integrity and prevents data corruption in the event of an unexpected power loss or system crash.
Instead of writing data to the drive immediately, Ext4 buffers the data in system memory and allocates the physical disk blocks just before writing them to storage. This feature improves overall write performance and helps maximize the lifespan of flash-based storage devices, like SSDs.
Ext4 actively optimizes how files are scattered across the drive to prevent file fragmentation, which benefits slower storage devices like HDDs by minimizing seek times of the drive head.
Since Ext4 is mature and battle-tested, tooling around it is as reliable as it gets. There exist a myriad of data recovery tools in the case something does go wrong. The file system is also very flexible in that it can be expanded or shrunk as needed.
When you want it: You just need a reliable, "set-it-and-forget-it" file system that works well without any manual tuning. Even with its old heritage, it's still a good choice for everyday desktop users, gamers, older computers, and external backup drives. Choose Ext4 if you need low system overhead and want the flexibility to safely shrink your partition later if your storage needs change.
When you don't want it: You need advanced, modern storage features. If you want to create instant system-wide snapshots before updating your software, pool multiple different-sized hard drives together, or use transparent data compression to save space on an SSD.
Btrfs: The new kid on the block
Btrfs is a new type of Linux file system that is designed differently from Ext4 in some respects. Where Ext4 is built around simplicity, btrfs shines with modern storage features.
Btrfs is a copy-on-write (CoW for short) file system, which means that copies of files are only "virtual" and do not occupy any additional storage space, and a copy only becomes "real" once it has been changed. Writes do not overwrite data in place; instead, a modified copy of the block is written to a new location, and metadata is updated to point at the new location.
Btrfs organizes its data in subvolumes, which can be mounted like partitions. Unlike partitions, subvolumes do not have a fixed size. Instead, subvolumes are merely an organizational unit on the same Btrfs partition, the size of which depends on the contents stored in them. Any number of subvolumes can be created for different mount points, e.g. / and /home. This allows, amongst other things, for multiple operating systems to be installed to the same disk on the same computer without interfering with each other.
Another feature of Btrfs is its ability to create snapshots of the file system. The state of a subvolume can be recorded in a snapshot, e.g. before a critical system update, in order to revert to a previous state of the file system if necessary. Thanks to CoW, snapshots require very little storage space compared to full-fledged backups (although they are no replacement for them!) and can be mounted and booted from like regular subvolumes. This makes it possible to "rewind" the state of the file system with comparatively little effort. Tools such as snapper or timeshift can simplify and automate the process of creating snapshots during system updates and restoring from snapshots from the commandline.
Btrfs also implements transparent compression of data blocks. Written data is automatically stored in compressed form if the appropriate mount options are set. There are a number of different compression algorithms to choose from, including lz4, gzip and Zstandard. This can also increase the life span of flash based storage devices, as less data is written to the disk and not as much wear-leveling is taking place.
Btrfs comes with RAID management for RAID 0, 1 and 10 built into the file system itself and makes an additional software or firmware RAID superfluous for these configurations. In addition, the integrated RAID functionality offers the advantage that it is aware of used and free data blocks in mirrored setups, which can considerably speed up the reconstruction of a RAID, as only the used blocks are reconstructed. Using the built-in RAID functionality in Btrfs also allows for more storage devices to be added to the RAID later on.
When you want it: You love to tinker with your system, run rolling-release Linux distributions (like Arch or openSUSE Tumbleweed), or want bulletproof peace of mind. Its instant snapshotting turns a system-breaking update into a ten-second rollback. It is also ideal if you want to squeeze more space out of your SSD via built-in compression or don't want to agonize over the correct partition sizes for your / and /home partitions and instead share storage dynamically between them.
When you don't want it: Your daily workflow involves heavy database management (like MySQL or PostgreSQL) or hosting several virtual machine images. Because of its Copy-on-Write mechanics, frequently modified files inside VMs and databases will heavily fragment the drive, dragging down performance. You should also avoid it if you plan on using RAID 5 or RAID 6 storage arrays, as the Btrfs implementation for those specific modes remains notoriously unstable.
XFS: The Enterprise Heavyweight
Originally developed by Silicon Graphics (SGI) in 1993 for their high-end IRIX operating system, XFS is a mature, 64-bit, high-performance file system. It was specifically engineered to handle massive media workstations and massive datasets long before modern storage sizes became common. Today, it is highly revered for its industrial-grade reliability and serves as the default file system for enterprise distributions like Red Hat Enterprise Linux (RHEL) and Fedora Server.
The most notable feature of XFS is its Allocation Group architecture. It divides the storage volume into discrete, independent regions. Each allocation group manages its own free space and inodes, allowing multiple CPU cores and application processes to perform read and write operations simultaneously without locking each other out. This results in exceptional parallel I/O performance.
Like Ext4, XFS protects data integrity using a metadata journal, ensuring rapid recovery after a sudden power loss. Its on-disk structure (advanced B+ trees) allows it to track block of free space to write files efficiently into contiguous blocks, preventing file fragmentation and keeping throughput high.
When you want it: You are building an enterprise-grade server, a database host, or a media production workstation. XFS shines brightest when handling massive files—like multi-gigabyte raw video footage, massive machine learning datasets, or monolithic backups. It is the go-to choice if you have a powerful multi-core CPU and multiple applications demanding high-speed, parallel access to the disk at the exact same time.
When you don't want it: You are setting up a standard consumer laptop or desktop where partition flexibility matters. Because XFS cannot be shrunk under any circumstances, it is a terrible choice if you ever plan to resize your partitions later or dual-boot with another operating system. It is also less efficient than Ext4 on smaller drives that are filled with millions of tiny text or code files rather than giant media blocks.
Swap: When RAM just isn't enough
A special type of file system on Linux is the Swap file system. As the name implies, it is used for "swapping" out data in RAM onto a storage device, like an SSD or HDD, to make room for actively used data the system needs to work with. It prevents the system from running out of RAM when lots of things are going on at the same time which your physical RAM can't hold.
Swap can either be its own partition or a file. Which one you choose comes down to what your use-case is and the administrative effort you're willing to put up with.
A Swap partition carves out a rigid portion of your drive just for swapped out memory pages. If you want to use hibernation on a laptop, a swap partition typically saves you a couple headaches in setting it up correctly—just point the system at the swap partition and you're done (resume="PARTLABEL=swap"). If you upgrade your RAM, however, you will also have to resize your swap partition to be at least as big as the amount of RAM in your system to continue using hibernation. This can entail its own set of administrative headaches, because resizing the swap partition usually means other partitions have to be shrunk (something that's impossible if you went with XFS for example).
A Swap file on the other hand is very flexible and can be created in seconds while the system is running. In case you need more swap space, you can simply create another swap file, turn it on, and delete it again after you're done. The downside with this approach with regards to hibernation is that you will have to tell the system the exact physical file offset of the swap file on disk (resume="PARTLABEL=root" resume_offset=38912) and need to update this value in case you re-create the swap file. You also won't be able to span multiple swap files for hibernation, as all contents in RAM must fit into a single file. There's also special considerations to take into account when using a swap file in conjunction with btrfs, since its CoW capabilities can cause considerable performance hits and file system fragmentation, unless CoW is specifically disabled for the swap file (chattr +C).
If you don't need hibernation and want the flexibility of easily expanding swap space, a swap file offers exactly what you need.
If you have a more complex storage setup (e.g. ZFS or btrfs RAID), or you're not bothered by its inflexibility, a swap partition is the more sensible choice.
Singular file system
The simplest, most basic partitioning scheme in any Linux operating system consists of 3 partitions:
| Type | File System | Description |
|---|---|---|
| EFI System Partition | vfat | Stores boot loaders and bootable OS images in .efi format |
| Root File System | ext4, btrfs, XFS, or other | Stores the Linux OS files (kernel, system libraries, applications, user data) |
| Swap | Swap partition or file | Stores swapped memory pages from RAM during high memory pressure |
This guide assumes the following:
- There is only 1 disk that needs partitioning
/dev/nvme0n1is the primary disk
Preparing the disk
Determine the disks that are installed on your system. This can easily be done with fdisk:
fdisk -l
It outputs a list of disk devices with one or more entries similar to this:
Disk /dev/nvme0n1: 232.89 GiB, 250059350016 bytes, 488397168 sectors
Disk model: Samsung SSD 840
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
The line starting the device file with /dev/ is the relevant one. Start partitioning the disk with cfdisk:
WARNING: Make sure you are modifying the correct device, else you will lose data!
cfdisk /dev/nvme0n1
If the disk has no partition table yet, cfdisk will ask you to specify one. The default partition table format for UEFI systems is gpt. Create a layout with at least 3 partitions:
| Size | FS Type |
|---|---|
| 1G | EFI System |
| (RAM size) | Linux Swap |
| (remaining) | Linux root (x86-64) |
NOTE: Specifying the correct file system type allows some software to automatically detect and assign appropriate mount points to partitions. See Discoverable Partitions Specification for more details.
You can verfiy that the partitions have been created by running fdisk -l again:
Disk /dev/nvme0n1: 232.89 GiB, 250059350016 bytes, 488397168 sectors
Disk model: Samsung SSD 840
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
Device Start End Sectors Size Type
/dev/nvme0n1p1 2048 2099199 2097152 1G EFI System
/dev/nvme0n1p2 2099200 35653631 33554432 16G Linux swap
/dev/nvme0n1p3 35653632 488396799 452743168 215.9G Linux root (x86-64)
This time fdisk will also list the partitions present on the disk.
NOTE: You might notice a pattern with how Linux structures its block devices. Partitions also count as "devices" which you can interact with. Each partition has an incrementing counter attached to its name to specify its order in the partition layout.
Formatting partitions
Format the partition with the appropriate mkfs subcommand for the file system you want to use, e.g. ext4:
mkfs.ext4 /dev/nvme0n1p3 # ext4 root file system
mkfs.fat -F 32 /dev/nvme0n1p1 # EFI System Partition
mkswap /dev/nvme0n1p2 # Swap space
Next mount the file systems:
ATTENTION: Depending on which file system you chose earlier for your root file system, additional mount parameters might be beneficial or necessary, e.g. btrfs requires specifying the subvolume you want to mount using the option subvol=NAME. Refer to the file system's manual to determine relevant mount parameters.
mount /dev/nvme0n1p3 -o noatime /mnt
mount /dev/nvme0n1p1 --mkdir /mnt/efi
swapon /dev/nvme0n1p2
Singular file system (LUKS, encrypted)
LUKS (Linux Unified Key Setup) is the standard for Linux hard disk encryption. By providing a standard on-disk-format, it does not only facilitate compatibility among distributions, but also provides secure management of multiple user passwords. LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
Management of LUKS encrypted devices is done via the cryptsetup utility.
NOTE: Why should you encrypt your data? Encryption ensures that no one but the rightful owner has access to the data. Encryption is therefore not only used to hide sensitive data from prying eyes, it also serves to protect your privacy. Encryption should be considered especially for portable devices such as laptops. In the event of loss or theft, encryption ensures that personal data and secrets (passwords, key files, etc.) do not fall into the wrong hands and are less likely and not as easily be abused.
The simplest, most basic encrypted partitioning scheme in a Linux operating system consists of 3 partitions:
| Type | File System | Description |
|---|---|---|
| EFI System Partition | vfat | Stores boot loaders and bootable OS images in .efi format |
| Swap | LUKS2 | Stores swapped memory pages from RAM during high memory pressure |
| Root File System | LUKS2 | Stores the Linux OS files (kernel, system libraries, applications, user data) |
This guide assumes the following:
- There is only 1 disk that needs partitioning
/dev/nvme0n1is the primary disk
Preparing the disk
Determine the disks that are installed on your system. This can easily be done with fdisk:
fdisk -l
It outputs a list of disk devices with one or more entries similar to this:
Disk /dev/nvme0n1: 232.89 GiB, 250059350016 bytes, 488397168 sectors
Disk model: Samsung SSD 840
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
The line starting the device file with /dev/ is the relevant one. Start partitioning the disk with cfdisk:
WARNING: Make sure you are modifying the correct device, else you will lose data!
cfdisk /dev/nvme0n1
If the disk has no partition table yet, cfdisk will ask you to specify one. The default partition table format for UEFI systems is gpt. Create a layout with at least 3 partitions:
| Size | FS Type |
|---|---|
| 1G | EFI System |
| (RAM size) | Linux Swap |
| (remaining) | Linux root (x86-64) |
NOTE: Specifying the correct file system type allows some software to automatically detect and assign appropriate mount points to partitions. See Discoverable Partitions Specification for more details.
You can verfiy that the partitions have been created by running fdisk -l again:
Disk /dev/nvme0n1: 232.89 GiB, 250059350016 bytes, 488397168 sectors
Disk model: Samsung SSD 840
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
Device Start End Sectors Size Type
/dev/nvme0n1p1 2048 2099199 2097152 1G EFI System
/dev/nvme0n1p2 2099200 35653631 33554432 16G Linux swap
/dev/nvme0n1p3 35653632 488396799 452743168 215.9G Linux root (x86-64)
This time fdisk will also list the partitions present on the disk.
NOTE: You might notice a pattern with how Linux structures its block devices. Partitions also count as "devices" which you can interact with. Each partition has an incrementing counter attached to its name to specify its order in the partition layout.
Encrypting partitions
Before writing a file system to the disk a LUKS container needs to be created with the cryptsetup utility:
WARNING: Do NOT forget your passphrase! In case of loss you won't be able to access the data inside the container anymore!
NOTE: Assigning labels to partitions creates unique nodes in /dev/disk/by-label/, thereby making them uniquely addressable and easy to discern.
cryptsetup luksFormat --label cryptswap /dev/nvme0n1p2
cryptsetup luksFormat --label cryptroot /dev/nvme0n1p3
Open the newly created LUKS container and supply the passphrase you just set:
NOTE: root is used as an example here. It is the "mapper name" under which the opened LUKS container will be available at for the runtime of the system, in this example: /dev/mapper/root. You may use whatever name you like.
cryptsetup open /dev/disk/by-label/cryptswap swap
cryptsetup open /dev/disk/by-label/cryptroot root
You can also pass additional parameters, e.g. for allowing TRIM on LUKS partitions (often referred to as "discards" in the general context of Linux filesystems):
WARNING: Allowing TRIM on encrypted partitions has security implications. By allowing TRIM, it becomes possible to derive information about the disk's utilization from freed areas. If you need absolute confidentiality, do not enable TRIM!
cryptsetup open /dev/disk/by-label/cryptswap swap --allow-discards
cryptsetup open /dev/disk/by-label/cryptroot root --allow-discards
To save the flags permanently, use the --persistent option. This eliminates the need to specify options manually or in configuration files, since they are stored in the header section of the LUKS container and applied automatically.
You can always update already opened LUKS containers' flags with cryptsetup refresh:
cryptsetup refresh swap --allow-discards --persistent
cryptsetup refresh root --allow-discards --persistent
Formatting and mounting partitions
Create file systems for the ESP and the root file system:
mkfs.fat -F32 -n ESP /dev/nvme0n1p1
mkfs.btrfs --label root /dev/mapper/root
mkswap --label swap /dev/mapper/swap
Create btrfs subvolumes:
mount /dev/mapper/root /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
Mark the root subvolume @ as the default. This eliminates having to set it later as a kernel rootflags option.
Query the subvolumes, to get the subvolid:
btrfs subvolume list /mnt/
This lists all subvolumes on the partition with their IDs:
ID 256 gen 4839 top level 5 path @
ID 257 gen 4839 top level 5 path @home
The root subvolume @ in this scenario has ID 256:
btrfs subvolume set-default 256 /mnt/
umount -R /mnt
Mount the file systems:
mount /dev/mapper/root -o noatime,compress=zstd,subvol=@ /mnt
mount --mkdir /dev/mapper/root -o noatime,compress=zstd,subvol=@home /mnt/home
mount --mkdir /dev/disk/by-label/ESP /mnt/efi
swapon /dev/mapper/swap
Encrypt non-root devices (LUKS)
If you have more than one hard disk that you need to encrypt (e.g. SSD as main disk, HDD as data disk) there are a few things to keep in mind to ensure continued smooth operation without any loss of convenience.
The layout is as follows:
| Type | File System | Description |
|---|---|---|
| Home File System | LUKS2 | Stores user home directories and personal files |
Preparing the disk
Determine the disks that are installed on your system. This can easily be done with fdisk:
fdisk -l
Start partitioning the disk with cfdisk:
WARNING: Make sure you are modifying the correct device, else you will lose data!
cfdisk /dev/sda
If the disk has no partition table yet, cfdisk will ask you to specify one. The default partition table format for UEFI systems is gpt. Create a layout to your liking, e.g.:
| Size | FS Type |
|---|---|
| (disk size) | Linux home |
Formatting partitions
Before writing a file system to the disk a LUKS container needs to be created with the cryptsetup utility:
WARNING: Do NOT forget your passphrase! In case of loss you won't be able to access the data inside the container anymore!
NOTE: Using /dev/sda as an example of a SATA HDD that is intended to be mounted at /home.
cryptsetup luksFormat --label crypthome /dev/sda1
Open the newly created LUKS container and supply the passphrase you just set:
NOTE: If you want to enable TRIM support you can use cryptsetup open --allow-discards <device> <mappername>; this comes at a slight security/confidentiality penalty, as it allows insights into file system structures by monitoring which parts were deleted. Additionally passing --persistent will add it to the flags section of the LUKS metadata and apply the flag automatically on every cryptsetup operation.
cryptsetup open /dev/disk/by-label/crypthome home
Create a file system for the home file system:
mkfs.ext4 -L home /dev/mapper/home
Mount the file systems:
mount --mkdir /dev/mapper/home -o noatime /mnt/home
LVM + dm-cache (unencrypted)
LVM dm-cache is a feature of the Linux device mapper, which uses a fast storage device to boost data read/write speeds of a slower one. It achieves this by transparently copying blocks of frequently accessed data to the faster storage device in the background. On subsequent reads/writes the faster storage device is queried first. If the requested data blocks are not on there, it automatically falls back on the slower source storage device.
This makes it possible to combine the benefits of SSD speeds with the low cost and high storage capacity of HDDs, when comparable pure SSD-based storage with the same capacity is too expensive or otherwise unavailable.
NOTE: This partition scheme is tailored towards a desktop computer setup with enough RAM and no SWAP (and therefore no hibernate/suspend-to-disk support).
CAUTION: This setup does NOT utilize LUKS disk encryption.
This guide assumes the following:
-
/dev/nvme0n1is the primary disk (cache device) -
/dev/sdais the secondary disk (origin device)
Nomenclature
| Term | Description |
|---|---|
| Physical Volume (PV) | On-disk partitioning format to be combined in a VG to a common storage pool |
| Volume Group (VG) | Grouping of one or more PVs to provide a combined storage pool from which storage can be requested in the form of LVs. |
| Logical Volume (LV) | Logical partition format which can be accessed like a block device to hold file systems and data. |
Preparing the cache device
First the available disks need to be determined. This can easily be achieved with fdisk:
fdisk -l
To start the actual partitioning process start cfdisk and point it to the disk you wish to partition:
WARNING: Make sure to select your actually desired device!
cfdisk /dev/nvme0n1
Partition the disk in the following way:
| FS Type | Size | Mount Point | Comment |
|---|---|---|---|
| vfat | 1G | /boot | EFI System |
| LVM | (remaining) | Linux LVM |
Preparing the origin device
Partition the disk by starting cfdisk and pointing it to the disk for the origin device:
WARNING: Make sure to select your actually desired device!
cfdisk /dev/sda
Partition the disk in the following way:
| FS Type | Size | Mount Point | Comment |
|---|---|---|---|
| LVM | (all) | Linux LVM |
Creating physical volumes, volume group and logical volumes
To create physical volumes as the basis for the LVM setup, use pvcreate and point it to the partitions you created in the two previous steps:
pvcreate /dev/nvme0n1p2 # SSD
pvcreate /dev/sda1 # HDD
Continue by creating a volume group with vgcreate that spans both physical volumes you just created:
NOTE: vg0 is used as an example here. Use whatever you like.
vgcreate vg0 /dev/nvme0n1p2 /dev/sda1
Next, create logical volumes inside the volume group with lvcreate, using 100% of the available space on the HDD and specifying the cache pool on the SSD:
lvcreate -l 100%FREE -n lv_root vg0 /dev/sda1
lvcreate --type cache-pool -n lv_cache -l 100%FREE vg0 /dev/nvme0n1p2
Finally, link the cache pool to the origin device with lvconvert:
lvconvert --type cache --cachepool vg0/lv_cache vg0/lv_root
Formatting devices
Format the partitions with the appropriate mkfs subcommand:
mkfs.fat -F 32 /dev/nvme0n1p1 # EFI System Partition
mkfs.btrfs /dev/mapper/vg0-lv_root # Btrfs root file system
Mount the root Btrfs file system:
mount /dev/mapper/vg0-lv_root /mnt
Next, create the subvolumes with the btrfs user space tools:
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
Unmount the root file system again:
umount -R /mnt
Mount the @ subvolume at /mnt:
mount /dev/mapper/vg0-lv_root -o noatime,compress-force=zstd,space_cache=v2,subvol=@ /mnt
Create directories for subsequent mount points:
mkdir -p /mnt/{boot,home}
Mount the remaining file systems:
mount /dev/nvme0n1p1 /mnt/boot
mount /dev/mapper/vg0-lv_root -o noatime,compress-force=zstd,space_cache=v2,subvol=@home /mnt/home
LVM on LUKS (encrypted, Laptop)
LUKS (Linux Unified Key Setup) is the standard for Linux hard disk encryption. By providing a standard on-disk-format, it does not only facilitate compatibility among distributions, but also provides secure management of multiple user passwords. LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
Management of LUKS encrypted devices is done via the cryptsetup utility.
Nomenclature
| Term | Description |
|---|---|
| Physical Volume (PV) | On-disk partitioning format to be combined in a VG to a common storage pool |
| Volume Group (VG) | Grouping of one or more PVs to provide a combined storage pool from which storage can be requested in the form of LVs. |
| Logical Volume (LV) | Logical partition format which can be accessed like a block device to hold file systems and data. |
Partitioning Setup
NOTE: This partitioning scheme does NOT include an LVM cache device.
While it is technically possible to add an LVM cache device to this setup, it is not advised to do so, as this will leak plain text contents of the unlocked LUKS container into the cache, which can be read in a hex editor by opening the raw device file directly — entirely defeating the purpose of encrypting the disk!
A LUKS on LVM setup is recommended instead.
LVM on LUKS has the benefit of being able to encrypt an entire drive (useful for laptops with encrypted swap for resume) while only needing to provide a single passphrase to unlock it entirely for simplicity.
However, since the LVM container resides inside the LUKS container it cannot span multiple disks, as it is confined by the boundaries by the parent LUKS container.
This guide assumes the following:
- This is used on a laptop computer with resume capabilities (Swap partition)
- There is only one drive:
/dev/nvme0n1 - The root file system will be btrfs, with subvolumes for
/and/home - To tighten security, this setup assumes a unified kernel image and booting via EFISTUB, with the ESP mounted at
/efi. Extra steps will be necessary to make the machine bootable.
Preparing the drive
-
List available disks
fdisk -l -
Start partitionaing tool for primary disk (
cfdiskis a little easier to use as it has a nice TUI)WARNING: Make sure to select your actually desired device!
cfdisk /dev/nvme0n1 -
Partition with the following scheme
| FS Type | Size | Mount Point | Comment |
|---|---|---|---|
| vfat | 1G | /efi |
EFI System |
| LUKS | (remaining) | Linux file system |
Creating the LUKS container
-
Create the LUKS container and enter a passphrase
WARNING: Do NOT forget your passphrase! In case of loss you won't be able to access the data inside the container anymore!
cryptsetup luksFormat /dev/nvme0n1p2 -
Open the newly created LUKS container
NOTE:
cryptlvmis used as an example here. Use whatever you like.cryptsetup open /dev/nvme0n1p2 cryptlvm
Creating LVM inside the LUKS container
-
Create an LVM physical volume inside LUKS container
pvcreate /dev/mapper/cryptlvm -
Create the volume group:
vgcreate vg0 /dev/mapper/cryptlvm -
Create the logical volumes
NOTE: When using resume, make
lv_swapas large as RAM. In this example the machine has 16 GB of RAM.lvcreate -L 16G -n lv_swap vg0 # Swap as big as RAM (16 GB) lvcreate -l 100%FREE -n lv_root vg0 # Root file system
Formatting devices
- Create partitions
mkfs.fat -F 32 /dev/nvme0n1p1 # EFI System Partition mkfs.btrfs /dev/mapper/vg0-lv_root # Btrfs root volume mkswap /dev/mapper/vg0-lv_swap # Swap space - Create Btrfs subvolumes
# First, mount the root file system mount /dev/mapper/vg0-lv_root /mnt # Create subvolumes btrfs subvolume create /mnt/@ btrfs subvolume create /mnt/@home - Mount partitions
# Unmount the root file system umount -R /mnt # Mount the @ subvolume mount /dev/mapper/vg0-lv_root -o noatime,compress-force=zstd,space_cache=v2,subvol=@ /mnt # Create mountpoints mkdir -p /mnt/{efi,home} # Mount the remaining partitions/subvolumes mount /dev/nvme0n1p1 /mnt/efi mount /dev/mapper/vg0-lv_root -o noatime,compress-force=zstd,space_cache=v2,subvol=@home /mnt/home # Activate swap swapon /dev/mapper/vg0-lv_swap
LUKS on LVM (encrypted, cached, Desktop)
LUKS (Linux Unified Key Setup) is the standard for Linux hard disk encryption. By providing a standard on-disk-format, it does not only facilitate compatibility among distributions, but also provides secure management of multiple user passwords. LUKS stores all necessary setup information in the partition header, enabling to transport or migrate data seamlessly.
Management of LUKS encrypted devices is done via the cryptsetup utility.
Nomenclature
| Term | Description |
|---|---|
| Physical Volume (PV) | On-disk partitioning format to be combined in a VG to a common storage pool |
| Volume Group (VG) | Grouping of one or more PVs to provide a combined storage pool from which storage can be requested in the form of LVs. |
| Logical Volume (LV) | Logical partition format which can be accessed like a block device to hold file systems and data. |
| Cache device | Fast storage used for caching reads/writes to slow storage |
| Origin device | Slow primary storage holding the actual data |
Partitioning Setup
LUKS on LVM has the benefit of a LUKS container being able to span multiple disks, thanks to the machanisms of the underlying LVM. This, however, comes with the downside that if you want to have multiple volumes (e.g. for your root volume and a separate home volume or encrypted SWAP) you will have to take extra steps to unlock these volumes during the boot process.
NOTE: If you want to utilize LVM cache this is the desired partioning scheme to use, as the encrypted LUKS container will reside inside an LVM LV and the LVM caching mechanism will cache the LV instead of the unlocked LUKS container, thus not leaking any secrets into the cache.
This guide assumes the following:
- This is used on a desktop computer without the need to resume (no SWAP partition)
- There are multiple drives:
/dev/nvme0n1(SSD) and/dev/sda(HDD) - The HDD will be cached by the SSD
- The root file system will be btrfs, with subvolumes for
/and/home - To tighten security, this setup assumes a unified kernel image and booting via EFISTUB, with the ESP mounted at
/efi. Extra steps will be necessary to make the machine bootable.
Preparing partition layout
Start by listing available disks:
fdisk -l
Create a partition layout with cfdisk by pointing it to the first disk, e.g. /dev/nvme0n1:
ATTENTION: cfdisk expects a device file, not a partition.
cfdisk /dev/nvme0n1
If cfdisk asks you about the partition table scheme to use, select gpt.
Create the following partition layout:
| FS Type | Size | Mount Point | Comment |
|---|---|---|---|
| vfat | 1G | /efi | EFI System |
| LVM | (remaining) | Linux LVM |
Start cfdisk for the second disk, e.g. /dev/sda:
cfdisk /dev/sda
Create the following partition layout:
| FS Type | Size | Mount Point | Comment |
|---|---|---|---|
| LVM | (all) | Linux LVM |
Setting up LVM
Start by creating LVM PVs on the partitions we just laid out:
pvcreate /dev/nvme0n1p2 # SSD
pvcreate /dev/sda1 # HDD
Next, create a VG spanning both PVs:
NOTE: vg0 is used as an example here. Name your VG whatever you like.
vgcreate vg0 /dev/nvme0n1p2 /dev/sda1
Create an LV inside vg0, using 100% of the available space on the PV at /dev/sda1 and label it lv_root:
lvcreate -l 100%FREE -n lv_root vg0 /dev/sda1
Create an LV inside vg0, using 100% of the available space on the PV at /dev/nvme0n1p2 and label it lv_cache:
lvcreate -l 100%FREE -n lv_cache --type cache-pool vg0 /dev/nvme0n1p2
Finally, link both LVs together so that the LV on the HDD is being cached by the pool on the SSD:
lvconvert --type cache --cachepool vg0/lv_cache vg0/lv_root
Creating the LUKS container
Create the LUKS container inside the LV of the origin device:
WARNING: Do NOT forget your passphrase! In case of loss you won't be able to access the data inside the container anymore!
cryptsetup luksFormat /dev/mapper/vg0-lv_root
Open the newly created LUKS container and supply the passphrase you just set:
NOTE: cryptroot is used as an example here. Use whatever you like.
cryptsetup open /dev/mapper/vg0-lv_root cryptroot
Formatting and mounting partitions
Create file systems for the ESP and the root file system:
mkfs.fat -F 32 /dev/nvme0n1p1
mkfs.btrfs /dev/mapper/cryptroot
Mount the root btrfs file system and create the subvolumes:
mount /dev/mapper/cryptroot /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
Unmount the root btrfs file system:
umount -R /mnt
Mount the @ subvolume:
mount /dev/mapper/cryptroot -o noatime,compress-force=zstd,space_cache=v2,subvol=@ /mnt
Create mount points for /efi and /home:
mkdir -p /mnt/{efi,home}
Mount the remaining partitions and subvolumes:
mount /dev/nvme0n1p1 /mnt/efi
mount /dev/mapper/cryptroot -o noatime,compress-force=zstd,space_cache=v2,subvol=@home /mnt/home