β οΈ This guide is only tested on the Raspberry Pi 5 with Raspberry Pi OS 64-bit 2025-09-16.
Other platforms and distributions may work, but there may be unexpected issues or side effects.
This guide will show you how to encrypt your Raspberry Pi's root partition and set up an initramfs that will prompt for the password, decrypt the partition and gracefully resume boot. You will also learn how to enable SSH during this pre-boot stage, allowing you to unlock the partition remotely. There are also optional steps for WiFi setup.
This guide operates directly on an image file and therefore does not require an SD card for the setup. The resulting image can be flashed to an SD card as usual.
-
A Raspberry Pi Linux image (e.g. Raspberry Pi OS Lite 64-bit 2023-12-11)
-
A computer (host) running Linux (e.g. Kali Linux 2023.2)
β οΈ NOTE: Your host's Linux should be as similar as possible to the Raspberry Pi's Linux. If you are preparing Debian 12/kernel 6.1 for the Raspberry Pi, use similar versions on the host, otherwise you may encounter issues inside the chroot.
This guide assumes you are actually following these steps on the Pi you intend to setup for encrypted boot.
Install dependencies:
- You can skip
binfmt-supportandqemu-user-staticif your host Linux's architecture matches that of the Raspberry Pi's Linux image. - If your host Linux doesn't use systemd, such as WSL on Windows, you need to manually run
update-binfmts --enableafter installingbinfmt-support.
apt update
apt install -y parted kpartx cryptsetup-bin rsync binfmt-support qemu-user-staticCreate two copies of the Raspberry Pi's Linux image β one to read from (base), and one to write to (target):
- pi-base.img
For the target image, if you intend to use a larger partition than MS-DOS supports, you'll need to create the partition table from scratch:
# Create blank img
dd if=/dev/zero of=pi-target.img bs=1M count=4096
# Attach images
kpartx -ar "$PWD/pi-base.img"
kpartx -a "$PWD/pi-target.img"
# Create partitions
parted /dev/loop1
> mklabel gpt
> mkpart boot fat32 1MiB 513MiB
> set 1 boot on
> mkpart root ext4 513MiB 100%
> quit
# Reattach image
kpartx -d "$PWD/pi-target.img"
kpartx -a "$PWD/pi-target.img"
# Copy boot partition
dd if=/dev/mapper/loop0p1 of=/dev/mapper/loop1p1
# Format root partition
mkfs.ext4 -L rootfs /dev/mapper/loop1p2If your system automatically mounted any partitions, unmount them:
umount /media/**/*Run lsblk and verify the process was successful β you should see two loopback devices, each with two partitions:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT # COMMENT
loop0 7:0 0 3.3G 0 loop # pi-base.img
ββloop0p1 253:0 0 256M 0 part # ββ boot
ββloop0p2 253:1 0 3G 0 part # ββ root
loop1 7:1 0 3.3G 1 loop # pi-target.img
ββloop1p1 253:2 0 256M 1 part # ββ boot
ββloop1p2 253:3 0 3G 1 part # ββ rootMount the base image's root partition:
mkdir -p /mnt/original/
mount /dev/mapper/loop0p2 /mnt/original/Replace the target image's root partition with a new, encrypted partition:
β οΈ NOTE:The default encryption algorithm is
aes-xts-plain64, which is fast only on the Raspberry Pi 5 due to its hardware AES acceleration. If you have an older generation, then use aes-adiantum instead via-c xchacha20,aes-adiantum-plain64. It is much faster than AES in software.By default cryptsetup will benchmark your host and use a memory-hard PBKDF algorithm that can require up to 4GB of RAM. If these settings exceed your Raspberry Pi's available RAM, it will make it impossible to unlock the partition. To work around this, set the --pbkdf-memory and --pbkdf-parallel arguments so when you multiply them, the result is less than your Pi's total RAM. For example:
--pbkdf-memory 512000 --pbkdf-parallel=1
cryptsetup luksFormat /dev/mapper/loop1p2Open (decrypt) the new partition:
cryptsetup open /dev/mapper/loop1p2 crypted
Then format and mount it:
mkfs.ext4 /dev/mapper/crypted
mkdir -p /mnt/chroot/
mount /dev/mapper/crypted /mnt/chroot/
Copy the base image's root partition files to the target image's new, encrypted root partition. You can use dd, but rsync is faster:
rsync --archive --hard-links --acls --xattrs --one-file-system --numeric-ids --info="progress2" /mnt/original/* /mnt/chroot/Set up a chroot by mounting the target image's boot partition and required virtual filesystems from the host:
mkdir -p /mnt/chroot/boot/firmware
mount /dev/mapper/loop1p1 /mnt/chroot/boot/firmware
mount -t proc none /mnt/chroot/proc/
mount -t sysfs none /mnt/chroot/sys/
mount -o bind /dev /mnt/chroot/dev/
mount -o bind /dev/pts /mnt/chroot/dev/pts/Enter the chroot:
LANG=C chroot /mnt/chroot/ /bin/bashInstall the dependencies:
apt update
apt install -y busybox cryptsetup dropbear-initramfsEdit /etc/fstab and replace the root entry with your decrypted (virtual) partition's device name:
# Original:
PARTUUID=e8af6eb2-02 / ext4 defaults,noatime 0 1
# Replace with:
/dev/mapper/crypted / ext4 defaults,noatime 0 1IMPORTANT: Make sure to also update the boot partition PARTUUID if you built the image from scratch with a completely new partition table
Run blkid and note the details of your encrypted partition:
blkid | grep crypto_LUKS
/dev/mapper/loop1p2: UUID="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" TYPE="crypto_LUKS" PARTUUID="cccccccc-cc"Edit /etc/crypttab and add an entry with your encrypted (raw) partition's UUID:
crypted UUID=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa none luks,initramfsEdit /boot/firmware/cmdline.txt and update the root entry:
# Original:
root=PARTUUID=21e60f8c-02
# Replace with:
root=/dev/mapper/crypted cryptdevice=UUID=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:cryptedUpdate /etc/initramfs-tools/modules with the following list to ensure that the required modules are included:
#
# You must run update-initramfs(8) to effect this change.
#
# Examples:
#
# raid1
# sd_mod
# Crypto - Critical for LUKS aes-xts-plain64
aes_ce_blk
aes_ce_cipher
ghash_ce
gf128mul
libaes
sha2_ce
sha256_arm64
sha1_ce
sha1_generic
cbc
ctr
ccm
gcm
cryptd
crypto_null
# WiFi - Critical for dropbear SSH
cfg80211
brcmfmac
brcmfmac_wcc
brcmutil
rfkill
# Network
ipv6
# Raspberry Pi 5 specific (likely needed for hardware)
rp1_fw
rp1_mailbox
rp1_pio
i2c_brcmstb
spi_bcm2835
# Other
gpio_keys
nvmem_rmem
Update /etc/initramfs-tools/initramfs.conf and replace the MODULES=* line with MODULES=list
Edit the cryptsetup initramfs hook to ensure cryptsetup ends up in the initramfs:
echo "CRYPTSETUP=y" >> /etc/cryptsetup-initramfs/conf-hookThe initramfs-tools cryptroot hook will resolve any UUIDs to device names during initramfs generation. This is a problem because the device names will likely differ between the host and the Raspberry Pi, resulting in failure to boot. To work around this, apply the following patch:
patch --no-backup-if-mismatch /usr/share/initramfs-tools/hooks/cryptroot << 'EOF'
--- cryptroot
+++ cryptroot
@@ -33,7 +33,7 @@
printf '%s\0' "$target" >>"$DESTDIR/cryptroot/targets"
crypttab_find_entry "$target" || return 1
crypttab_parse_options --missing-path=warn || return 1
- crypttab_print_entry
+ printf '%s %s %s %s\n' "$_CRYPTTAB_NAME" "$_CRYPTTAB_SOURCE" "$_CRYPTTAB_KEY" "$_CRYPTTAB_OPTIONS" >&3
fi
}
EOFThe default timeout when waiting for decryption (10 seconds) may be too short and result in a timeout error. To work around this, bump the value:
sed -i 's/^TIMEOUT=.*/TIMEOUT=100/g' /usr/share/cryptsetup/initramfs/bin/cryptroot-unlockWrite your SSH public key inside dropbear's and your decrypted OS's authorized_keys and fix permissions:
mkdir -p /root/.ssh && chmod 0700 /root/.ssh
echo "/REDACTED/" | tee /etc/dropbear/initramfs/authorized_keys /root/.ssh/authorized_keys
chmod 0600 /etc/dropbear/initramfs/authorized_keys /root/.ssh/authorized_keysReduce the dropbear shutdown timeout in /usr/share/initramfs-tools/scripts/init-bottom/dropbear (see #22):
# Original
DROPBEAR_SHUTDOWN_TIMEOUT=60
# Replace with:
DROPBEAR_SHUTDOWN_TIMEOUT=3
Set the dhcp configuration for dropbear:
echo -e "IP=::::$(hostname)::dhcp:::" | sudo tee /etc/initramfs-tools/conf.d/dropbear
If your pi boot gets stuck for some reason or the networking stack does not come up as expected, having local access to the initramfs console for debugging is rather helpful. If you want to use a keyboard in a local initramfs shell, this will make sure the layout is properly configured.
Modify /etc/default/keyboard to match the keyboard layout you intend to use:
# KEYBOARD CONFIGURATION FILE
# Consult the keyboard(5) manual page.
XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS=""
BACKSPACE="guess"
If you are booting from an NVME attached to the PCIe slot and want to enable PCIe Gen 3, add the following to /boot/firmware/config.txt
[all]
dtparam=pciex1
dtparam=pciex1_gen=3
Note this can also be added later and does not necessarily need to be present for first boot unless your NVME does not support PCIe gen 2.
Follow the instructions in Wireless-Builtin2.md to setup WiFi networking on boot for remote decryption. Note that if you do not choose to do this, some of the modules listed above may not be required.
Build the new initramdisk:
update-initramfs -uCustomize first run/init in /boot/firmware/cmdline.txt as it will break the encrypted setup and prevent booting:
Remove the following flags:
quiet splash plymount.ignore-serial-consoles
Note: Not sure whether it's necessary to actually remove any of these
And add the following:
systemd.run=/boot/firmware/firstrun.sh systemd.run_success_action=reboot systemd.unit=kernel-command-line.target
Tip: For more verbose initramfs output during bootup, add the
debugflag. And if you need to drop into a shell, addbreak=premount(or whatever other stage you want to pause at).
Create /boot/firmware/firstrun.sh and customize it for your needs. Most of these scripts allow additional configuration, so feel free to check their source:
#!/bin/bash
set +e
HOSTNAME=""
WIFI_SSID=""
WIFI_PSK=""
WIFI_COUNTRY=""
PI_USER=""
/usr/lib/raspberrypi-sys-mods/imager_custom set_hostname "$HOSTNAME"
/usr/lib/raspberrypi-sys-mods/imager_custom enable_ssh --key-only
/usr/lib/raspberrypi-sys-mods/imager_custom set_wlan "$WIFI_SSID" "$WIFI_PSK" "$WIFI_COUNTRY"
# Regenerate host ssh keys
rm /etc/ssh/ssh_host_* && ssh-keygen -A
# Setup default user
/usr/lib/userconf-pi/userconf $PI_USER
mkdir -p /home/$PI_USER/.ssh
cp /root/.ssh/authorized_keys /home/$PI_USER/.ssh/authorized_keys
chown -R $PI_USER:$PI_USER /home/$PI_USER/.ssh
# Cleanup script after first run
rm -f /boot/firmware/firstrun.sh
sed -i 's| systemd.run.*||g' /boot/firmware/cmdline.txt
exit 0Make sure the newly created file is executable:
chmod +x /boot/firmware/firstrun.shSync and exit the chroot:
set +o history
rm /root/.bash_history
sync
exitUnmount everything and clean up any remaining artifacts:
umount /mnt/chroot/boot/firmware
umount /mnt/chroot/sys
umount /mnt/chroot/proc
umount /mnt/chroot/dev/pts
umount /mnt/chroot/dev
umount /mnt/chroot
cryptsetup close crypted
umount /mnt/original
rm -d /mnt/chroot
rm -d /mnt/original
kpartx -d "$PWD/pi-base.img"
kpartx -d "$PWD/pi-target.img"You are now ready to flash pi-target.img to an SD card.
Boot the Raspberry Pi with the new SD card. It will obtain an IP address from the DHCP server and start listening for SSH connections. To decrypt the root partition and continue boot, from any shell, simply run cryptroot-unlock.
The first time only:
- Once decrypted, the system may power off. The reason for this is currently unknown. Restart the device and decrypt again.
- The decrypted system will run the init script from before and reboot back into the initramfs. Proceed to decrypt one last time.
Install any pending updates:
sudo apt-get update && sudo apt-get upgrade -yUpdate your user's password:
sudo passwd piEnforce password for sudo access:
sudo visudo /etc/sudoers.d/010_pi-nopasswd
# change NOPASSWD to PASSWDDisable auto-login:
raspi-config > System Options > Auto Login
Finally, reboot the system one last time for good measure:
rebootTo avoid host key collisions you can configure a separate trusted hosts store in the ~/.ssh/config of your client:
Host box
Hostname 192.168.0.30
User root
Host box-initramfs
Hostname 192.168.0.30
User root
UserKnownHostsFile ~/.ssh/known_hosts.initramfs
- https://www.kali.org/docs/arm/raspberry-pi-with-luks-disk-encryption/
- https://wiki.archlinux.org/index.php/Dm-crypt/Specialties
- https://wiki.gentoo.org/wiki/Custom_Initramfs
- https://www.raspberrypi.org/forums/viewtopic.php?t=252980
- https://thej6s.com/articles/2019-03-05__decrypting-boot-drives-remotely/
- https://www.pbworks.net/ubuntu-guide-dropbear-ssh-server-to-unlock-luks-encrypted-pc/
- https://raspberrypi.stackexchange.com/questions/92557/how-can-i-use-an-init-ramdisk-initramfs-on-boot-up-raspberry-pi/
- https://www.raspberrypi.com/documentation/computers/configuration.html#setting-up-a-headless-raspberry-pi