A Practical Guide to LUKS2 Full-Disk Encryption with a Detached Header on a USB Key
A normal LUKS2 volume keeps its header, the bit that stores the cipher configuration, the salts and the encrypted keyslots, on the first megabyte or so of the encrypted device itself. That's convenient: the disk is self-contained, and any machine with the right passphrase can mount it. It also means that if someone takes the disk, they have everything they need to attack the passphrase offline, at their leisure, with as many GPUs as they can afford. A detached header moves that metadata off the disk entirely, typically onto a small USB key you keep separately. Without it, the disk is just high-entropy noise: there is no header to attack, because there is nothing there that says "this is a LUKS volume" at all.
This is a genuinely useful property for an external backup drive, a removable data volume, or a laptop's secondary disk, and it's a five-minute change to your normal LUKS workflow. It is not, on its own, plausible deniability in the VeraCrypt sense, and it introduces a new single point of failure that you need to plan for from the start. Both of those points matter enough that I'll come back to them.
What a detached header actually buys you
If your disk is seized, imaged, or simply lost or stolen without the USB key, the attacker has ciphertext with no header. There is no keyslot to brute-force, no KDF parameters to attack, nothing. They cannot even confirm it's a LUKS volume rather than, say, a badly wiped disk full of random bytes. That's a meaningfully stronger position than "here is a LUKS2 header with argon2id keyslots, please attack them", even though argon2id is expensive to attack in the first place.
It does not hide the fact that a device holding an unreadable blob of ciphertext exists, and it does not stop an attacker who has both the disk and the USB key at the same time, for example because they were seized together. If your threat model specifically involves someone taking your laptop and its accessory bag in one go, the detached header buys you very little; the value is in physically separating the two, keeping the key on your person, in a different bag, or left at home when the laptop travels.
Before you start: plan the layout
You need two devices: the target you're encrypting (I'll use /dev/sdb, a whole external disk with no partition table you care about) and a USB key with a small filesystem on it to hold the header file, mounted here at /mnt/keyusb. Double-check /dev/sdb with lsblk and blkid before you touch it: with a detached header, the encrypted payload starts at byte zero of the target device, not after a reserved header region, so pointing luksFormat at the wrong device destroys it from the very first sector with no header offset to save you.
Creating the header and formatting the target
cryptsetup will create the header file for you if it doesn't already exist, sized to fit the LUKS2 metadata and keyslot areas (around 16 MiB by default, trivial for any USB key):
cryptsetup luksFormat --type luks2 \
--cipher aes-xts-plain64 \
--key-size 512 \
--hash sha512 \
--pbkdf argon2id \
--iter-time 4000 \
--header /mnt/keyusb/vault-header.img \
/dev/sdb
The explicit cipher, hash and pbkdf flags aren't strictly necessary, cryptsetup's LUKS2 defaults are already sane, but writing them out means you know exactly what you got, and it's one less thing to guess at when you're reading this back in two years. --iter-time 4000 tells argon2id to spend about four seconds calibrating its cost; raise or lower it depending on how fast you want unlocks to be versus how expensive you want an offline attack to become. If you're targeting a machine with limited RAM, also check --pbkdf-memory, since recent cryptsetup defaults can ask for a gigabyte of memory during the KDF, which is fine on a desktop and a problem on something small.
Confirm what actually got written before you rely on it:
cryptsetup luksDump --header /mnt/keyusb/vault-header.img
Check the UUID, cipher and keyslot entries match what you expect. This is also a good moment to note the UUID somewhere, since blkid won't find it on the target disk itself once the header is gone.
Backing up the header, and where not to put the backup
Lose the USB key with no backup and the data is gone, not "hard to recover", genuinely gone, because there is no header anywhere to reconstruct the keyslots from. Back it up immediately:
cryptsetup luksHeaderBackup /mnt/keyusb/vault-header.img \
--header-backup-file ~/secure/vault-header-backup.img
Where you put that backup matters. If you leave a copy sitting on your laptop's own disk, you've reintroduced exactly the exposure the detached header was meant to remove: anyone who takes the laptop now has the header again, just via a different path. Put it somewhere with its own protection, an encrypted cloud backup, a GPG-encrypted copy on a different offline medium, whatever fits the rest of your setup, but treat it as being at least as sensitive as the live header, because it is the live header.
Worth testing before you trust it, using --test-passphrase so you're not actually opening the mapping:
cryptsetup open --header ~/secure/vault-header-backup.img \
--test-passphrase /dev/sdb
Opening, formatting and mounting
cryptsetup open --header /mnt/keyusb/vault-header.img /dev/sdb vault
mkfs.ext4 -L vault /dev/mapper/vault
mount /dev/mapper/vault /mnt/vault
And to close it down again:
umount /mnt/vault
cryptsetup close vault
Making it repeatable
For a data volume you mount on demand, an /etc/crypttab entry works, using the header= option:
vault UUID=<target-uuid> none luks,header=/mnt/keyusb/vault-header.img,noauto
noauto matters here: without it, systemd will try to process this entry at boot and stall waiting for a USB key that probably isn't plugged in yet. Trigger the unlock explicitly, or via a udev rule keyed to the USB key's insertion, once the key's filesystem is actually mounted.
Putting the root filesystem itself behind a detached header on removable media is a different and considerably harder problem: the header has to be readable from the initramfs, before the normal boot-time device ordering and mount logic exists, which means baking USB enumeration and a stable device path into your initramfs hooks (dracut or mkinitcpio, depending on distribution) rather than relying on crypttab alone. It's done, but it's specific enough to your distribution and initramfs generator that I won't hand-wave a generic recipe here; treat it as a separate project from encrypting a data volume.
What this setup doesn't cover
A stray copy of the header file sitting in a shell history, a temp directory, or an old backup snapshot undermines the whole point just as thoroughly as losing the USB key does, except silently. The header file also carries a recognisable magic string at its start, so a stick with a file named vault-header.img on an otherwise empty FAT32 partition is not exactly camouflaged; renaming it buys you nothing against anyone who actually inspects the bytes. And none of this touches the passphrase itself: keylogging, shoulder-surfing, or a cold-boot attack against an already-unlocked machine works exactly as well against a detached-header setup as against a normal one, because by the time the volume is mounted, the master key is sitting in kernel memory regardless of where the header came from.