TechEarl

LUKS Disk Encryption With cryptsetup

Set up LUKS disk encryption with cryptsetup: format a block device, open it, put a filesystem on it, and mount it. The four commands, plus the header backup nobody warns you about.

Ishan Karunaratne⏱️ 10 min readUpdated
Share thisCopied
LUKS disk encryption with cryptsetup on Linux: luksFormat to encrypt a block device, luksOpen to unlock it, then mkfs and mount. Includes header backup and keyslot management.

LUKS disk encryption with cryptsetup is four commands. Format the device, open it, put a filesystem on it, mount it:

bash
sudo cryptsetup luksFormat /dev/sdX
sudo cryptsetup open /dev/sdX mydisk
sudo mkfs.ext4 /dev/mapper/mydisk
sudo mount /dev/mapper/mydisk /mnt/secure

That is the whole job for an empty data disk. The hard parts are not the commands; they are the things the commands do not warn you about: luksFormat destroys everything on the target, the LUKS header is a single point of failure you have to back up, and getting /dev/sdX wrong means encrypting the wrong disk. This is field-tested on Debian and Ubuntu; the binary is the same everywhere, so it works identically on Fedora, Arch, and RHEL once cryptsetup is installed.

Pick the right device first (this is where people lose data)

luksFormat is destructive. It writes a new LUKS header and from that point the old contents are gone. So before anything else, confirm which block device you mean:

bash
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,MODEL
code
NAME   SIZE TYPE MOUNTPOINT MODEL
sda    238G disk            Samsung SSD 860
├─sda1   1G part /boot
└─sda2 237G part /
sdb    932G disk            WDC WD10EZEX

Here sdb is the unmounted 1 TB drive I want to encrypt; sda is the running system. Encrypt the partition (/dev/sdb1) if the disk has a partition table, or the whole device (/dev/sdb) if you want one big encrypted blob with no partitioning. Both are valid. I encrypt the whole device for single-purpose data disks and a partition when the disk shares duties.

Throughout the rest of this guide I use /dev/sdb as the target. Substitute your real device, and double-check it against lsblk every single time.

Format the device with luksFormat

bash
sudo cryptsetup luksFormat /dev/sdb

cryptsetup makes you confirm in capitals and then asks for the passphrase twice:

code
WARNING!
========
This will overwrite data on /dev/sdb irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sdb:
Verify passphrase:

You do not need to pass a cipher or key size. On current cryptsetup the default format is LUKS2 (since 2.1.0) with aes-xts-plain64, a 512-bit key (256-bit AES because XTS splits the key in two), and Argon2id as the password-hashing function (the default KDF since cryptsetup 2.4.0; earlier LUKS2 used Argon2i). Those defaults are sound; override them only if you have a specific reason, for example a kernel that lacks AES-NI where you might prefer a cipher like xchacha20,aes-adiantum-plain64 on low-power hardware.

To be explicit about the format, name it:

bash
sudo cryptsetup luksFormat --type luks2 /dev/sdb

LUKS2 has been the default since cryptsetup 2.1.0 (2019). The main reasons to force --type luks1 are GRUB booting an encrypted /boot on older setups, or an old initramfs that cannot open LUKS2. For a plain data disk, take the default.

Open it, format the mapped device, mount it

Opening attaches the decrypted device under /dev/mapper/:

bash
sudo cryptsetup open /dev/sdb secure-data

secure-data is a name you choose; the unlocked device appears at /dev/mapper/secure-data. (cryptsetup luksOpen is the old spelling and still works; open is the current form.) Everything you write through that mapper node is encrypted on the way to the disk and decrypted on the way back, transparently.

Now treat /dev/mapper/secure-data like any block device. Put a filesystem on it and mount it:

bash
sudo mkfs.ext4 /dev/mapper/secure-data
sudo mkdir -p /mnt/secure
sudo mount /dev/mapper/secure-data /mnt/secure

When you are done, unmount and close to lock it again:

bash
sudo umount /mnt/secure
sudo cryptsetup close secure-data

Once closed, the data on /dev/sdb is unreadable ciphertext until someone opens it with a valid passphrase. There is no plaintext copy of the key sitting anywhere on disk; the key is unwrapped from a keyslot in the header using your passphrase and held in kernel memory only while the device is open.

Back up the LUKS header (the step everyone skips)

The LUKS header sits at the start of the device. It holds the keyslots, which hold the encrypted master key. If the header is corrupted or overwritten, the data is gone permanently, even with the correct passphrase, because the master key it protected is unrecoverable. A stray dd, a partition tool that rewrites the first few megabytes, a flaky USB enclosure: any of these can take out the header.

So back it up the moment the device exists, and store the backup somewhere other than the encrypted disk:

bash
sudo cryptsetup luksHeaderBackup /dev/sdb \
  --header-backup-file /root/sdb-luks-header.img

To restore after a header disaster:

bash
sudo cryptsetup luksHeaderRestore /dev/sdb \
  --header-backup-file /root/sdb-luks-header.img

One caveat worth stating plainly: the header backup contains your keyslots. Anyone who has both the header backup and a passphrase that unlocks one of its slots can decrypt the disk. Treat the backup file as sensitive as the disk itself. If you later change the passphrase, an old header backup still opens with the old passphrase, so rotate or destroy stale backups.

Manage keyslots: add, change, and remove passphrases

A LUKS device has multiple keyslots (8 in LUKS1, up to 32 in LUKS2). Each slot holds the same master key wrapped under a different passphrase. That is how you give two people independent passphrases to the same disk, or rotate a passphrase without re-encrypting.

Add a second passphrase:

bash
sudo cryptsetup luksAddKey /dev/sdb

It prompts for any existing passphrase first (to prove you are allowed), then the new one. Remove a passphrase you no longer want:

bash
sudo cryptsetup luksRemoveKey /dev/sdb

Change one in place (remove old, add new, atomically):

bash
sudo cryptsetup luksChangeKey /dev/sdb

Inspect what is in the header without unlocking anything:

bash
sudo cryptsetup luksDump /dev/sdb

luksDump shows the LUKS version, cipher, KDF, and which keyslots are populated. It does not reveal any key material, so it is safe to run and paste when asking for help.

Mount it automatically at boot (crypttab and fstab)

Running open then mount by hand every reboot gets old fast. To unlock and mount a data disk automatically at boot, wire it through /etc/crypttab (unlock) and /etc/fstab (mount). Reference the device by UUID, not /dev/sdb: kernel device names are not stable across reboots and a renamed disk in crypttab is how you end up unlocking the wrong device.

Get the UUID of the encrypted block device (the raw /dev/sdb, not the mapper node):

bash
sudo blkid /dev/sdb

Add the unlock line to /etc/crypttab. The fields are: mapper name, source device, key source, options.

code
secure-data  UUID=<uuid-of-/dev/sdb>  none  luks

none for the key source means cryptsetup prompts for the passphrase at boot. That is fine for a desktop or a machine with a console. To unlock without a prompt, point the third field at a keyfile instead (/root/secure-data.key), add that keyfile to a keyslot with cryptsetup luksAddKey /dev/sdb /root/secure-data.key, and chmod 0400 it. A keyfile on the same machine only protects against a stolen drive, not a stolen running box, the same caveat as below.

Then add the mapper device to /etc/fstab so the unlocked volume mounts:

code
/dev/mapper/secure-data  /mnt/secure  ext4  defaults  0  2

Test the wiring before you trust a reboot to it:

bash
sudo systemctl daemon-reload
sudo cryptsetup luksClose secure-data 2>/dev/null
sudo systemctl start "systemd-cryptsetup@secure\x2ddata.service"
sudo mount -a

If mount -a mounts /mnt/secure cleanly, the next boot will too. Get this wrong on a root disk and the machine can fail to boot into a usable state, so always test on a data disk first.

When LUKS is the wrong tool

LUKS encrypts a block device at rest. It does not help with:

  • Per-file encryption inside a shared filesystem. If different users need different keys on the same mounted volume, you want fscrypt (ext4/f2fs native encryption) or gocryptfs, not one LUKS volume everyone shares.
  • Data in transit. LUKS protects the disk, not the wire. Use TLS or SSH for that.
  • An always-on server with no one to type the passphrase. A LUKS volume that auto-unlocks from a keyfile on the same machine protects against a stolen drive but not a stolen running machine. For headless boxes you usually want to unlock remotely at boot. I covered that in unlocking LUKS remotely over SSH with Dropbear.
  • Protection while the disk is mounted. Once opened, the filesystem is plaintext to anything running as root on that machine. Encryption-at-rest is exactly that: at rest.

LUKS1 vs LUKS2 at a glance

AspectLUKS1LUKS2
Default sincecryptsetup before 2.1.0cryptsetup 2.1.0+ (2019)
Default KDFPBKDF2Argon2id (memory-hard, GPU-resistant)
Keyslots8up to 32
Header redundancysingle headerprimary + secondary header copy
Metadatafixed binaryJSON, extensible (tokens, integrity)
GRUB /boot supportyesGRUB 2.06+ only; older setups need LUKS1

For a fresh data disk, take the LUKS2 default. The only common reason to choose LUKS1 in 2026 is booting an encrypted root or /boot through an old GRUB.

See also

Sources

Authoritative references this article was fact-checked against.

TagsLUKScryptsetupDisk EncryptionLinuxdm-cryptSecurityData Encryption

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

Useful Things You Can Do with acf/save_post

acf/save_post is the hook that fires after ACF saves a post's custom fields. Useful patterns: derived field computation, taxonomy sync, search-index refresh, ACF-to-meta mirroring, validation, audit logging. Plus the gotchas.

How to List Only Filenames with grep -l

grep -l prints the name of each file that contains a match and stops reading at the first hit, which makes it the fast answer to 'which files contain this string'. The lowercase -l, the inverted -L for files missing a pattern, the grep -rl one-liner, the NUL-safe xargs pipeline for find-and-replace, and the BSD vs GNU notes.