Skip to content

Instantly share code, notes, and snippets.

Last active December 17, 2020 15:40
Show Gist options
  • Save pezz/5310082 to your computer and use it in GitHub Desktop.
Save pezz/5310082 to your computer and use it in GitHub Desktop.
Archlinux ARM encrypted root


Just some FYI, to get started:

  • I'm using a 16 GB Sandisk SD card.
  • I have a model B Pi, 512 MB RAM (not really relevant, thought I'd mention it).
  • Monitor and keyboard connected to the Pi itself, for now.
  • Network working, internet access.


We will run no swap, like the default image, and leave the initial install on the 1.8 GB partition as a potential rescue disk. Trust me, you need to be able to run ARM binaries if you ever need to recover.

Having a rescue partition that you can boot into will be invaluable and would have saved me from my last screw-up.

Step 1

Download and dd the Arch ARM image, as per normal.

At the time of writing this (4 April, 2013) it is:


sudo dd if=archlinux-hf-2013-02-11.img of=/dev/mmcblk0 bs=1M

You know this bit, now put the card into your Pi.

Step 2

Boot, update everything (pacman -Syu). Based on the current image, you'll have to fix a few pacnew files.

  • Install rsync if it isn't already (a must, but I do think it's installed by default with the alarm image).
  • Install vim :)

Reboot and make sure everything is cool.

Your kernel should be (as of updating on 4 April, 2013) from uname -a:


Do any normal tasks now as you would otherwise when setting up a system.

All of this is optional:

  • Set your root password.
  • Set an IP, hostname etc (all the stuff systemd wants, e.g. vconsole etc).
  • Add users, your favourite shell, configure any services, etc.
  • Setup whatever else you don't want to setup later or don't mind having in a rescue environment.

We will be rsyncing this setup to the encrypted partition.

Reboot again, make sure everything is good.

Step 3

Create a new partition of at least 2 GB, I normally just fill the rest of the SD card, it's up to you though.

Use fdisk on /dev/mmcblk0 and create a new primary partition.

I would show you output, but I can't be bothered re-typing stuff I can't copy and paste.

Nevertheless, you should have an mmcblk0p1, p2 and p3.

  • p1 being the vfat boot partition - do not mess with it.
  • p2 being our current 1.8 GB root.
  • p3 being the new partition.

Step 4

dd /dev/zero over the new partition (p3), just to add a minimal amount of safety:

dd if=/dev/zero of=/dev/mmcblk0p3 bs=1M

This will take a long time. You can use if=/dev/urandom if you like, but it will take even longer.

You'll get several kernel IO hung timeout messages while this runs, but it will finish.

Be patient.

When dd finishes, create a LUKS volume on /dev/mmcblk0p3

cryptsetup -c aes-xts-plain -y -s 512 luksFormat /dev/mmcblk0p3

Do what the command says, choose a passphrase etc.

Step 5

Open the LUKS volume and put a filesystem on it:

cryptsetup luksOpen /dev/mmcblk0p3 root

Enter passphrase...

mkfs.ext4 /dev/mapper/root

Step 6

Mount the new filesystem:

mount /dev/mapper/root /mnt

Step 7

Rsync the current system over:

rsync --progress -axv / /mnt/

Don't forget the trailing / on /mnt/

This will take a long time.

Run the rsync again, just to make sure you have everything, this will be much quicker.

Step 8

We're not ready to do our "over SSH" unlock just yet, let's make sure we can at least boot the encrypted root.

Edit /etc/mkinitcpio.conf and make sure this line has:

HOOKS="base udev autodetect modconf block keyboard encrypt filesystems fsck"

Now generate an initrd:

mkinitcpio -k $(uname -r) -g /boot/initrd

Step 9

Edit /boot/config.txt and add to the end:

initramfs initrd 0x00f00000

Step 10

Edit the kernel command line, leave whatever is there alone, add or modify the following (file is /boot/cmdline.txt):

cryptdevice=/dev/mmcblk0p3:root:allow-discards root=/dev/mapper/root initrd=0x00f00000

Up to you if you want allow-discards or not, your choice.

Be sure to leave the "ro" option there.

Now add the following to fstab, edit /mnt/etc/fstab and ensure:

/dev/mmcblk0p1      /boot       vfat    defaults                    0      0
/dev/mapper/root    /           ext4    defaults,discard,commit=120 0      1

Change options to what you want.

Reboot and hope it works!

Step 11

From the console, you should now be able to enter your passphrase and boot off the encrypted root.

Your root filesystem is now the LUKS encrypted mmcblk0p3 and not p2.

Make sure the HOOKS line in /etc/mkinitcpio.conf on p3 matches what you edited before on p2.

Make sure /etc/fstab on this partition is correct (you did it right if it booted and you can do touch foo and write a file).

If you make any changes, reboot and ensure you can boot without any problems (if you are going to reboot, rebuild the initrd before you do -- just to be on the safe side).

Step 12

Install base-devel (hit enter to select all).

pacman -S base-devel

For thoroughness run:

pacman-key --init

Install an AUR helper.

pacman -S yaourt

Handy tip, add the following to /etc/yaourtrc to disable architecture checks.


Step 13

Install dropbear_initrd_encrypt

yaourt -S dropbear_initrd_encrypt

Change the /etc/mkinitcpio.conf HOOKS line to say:

HOOKS="base udev autodetect modconf block keyboard dropbear encryptssh filesystems fsck"

Remove anything you feel you don't need, but this is what I use. Also, order is important so make sure dropbear is before encryptssh which is before filesystems.

Step 14

By default, sshd is enabled and started, so you should have host keys generated without doing anything.

Generate dropbear keys based off your OpenSSH host keys:

[root@pi ~]# cd /etc/dropbear
[root@pi ~]# dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key dropbear_rsa_host_key
Key is a RSA key
Wrote key to '/etc/dropbear/dropbear_rsa_host_key'
[root@pi ~]# dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
Key is a DSS key
Wrote key to '/etc/dropbear/dropbear_dss_host_key'


Put your own public ssh key into /etc/dropbear/root_key (i.e. the public key you normally put onto hosts so you can ssh in without a password).

Step 15

Edit /boot/cmdline.txt and add:


Edit this to suit your setup. Replace the IP address with the address of your Pi, its gateway and its node name (pi in my case).

Now rebuild the initrd.

mkinitcpio -k $(uname -r) -g /boot/initrd

Reboot, and ssh in from another box:


Enter the passphrase and...


Any errors or omissions are due to the fact that I've been drinkin'...


  • You must rebuild the initrd after every kernel update. Archlinux ARM kernel packages do not run mkinitcpio automatically after kernel update like regular x86_64 Arch does.

  • When rebuilding the initrd after an update, you must provide the correct string appropriate to the new kernel.


The easiest way to recover, in my opinion, would be to:

  • Leave the p2 partition in tact.

  • When something goes wrong, put the SD card into another system and edit cmdline.txt to boot off p2.

  • Use the system on p2 to unlock the LUKS volume etc, and chroot into it, whatever you need to do to fix the system.

Copy link

Gerhman commented Feb 8, 2014

Thanks a lot for this, it's exactly what I needed. Could you please just elaborate on the whole process of providing dropbear with our public key because I have tried but it tells me that the server refused my key and then asks for root's password but won't accept it. Maybe an example of how this file should look would help.

Just a thought, does this work for you? The reason I'm asking is because as far as I can determine the public key is stored in /etc/dropbear which as I understand it will be encrypted at boot time? Is this not the case or is there some work around?

Copy link

BusyJay commented Mar 1, 2014

I think step 4 will have security issue. You should write random data rather than a bunch of zero to the device you want to wipe out.

Copy link

mercora commented Mar 12, 2014

Step 14 also has security implications, because the private key of the sshd inside the encrypted root can be recovered from the initrd, which of course is not encrypted.

Copy link

exchgr commented Apr 21, 2014

You can replace the kernel version in the arguments for mkinitcpio with $(uname -r) for added foolproofness

Copy link

pezz commented May 28, 2014

Hey guys, I've just noticed these comments, thanks for the feedback!

I've suggested using /dev/urandom and $(uname -r) is a great suggestion for the mkinitcpio.

I've never considered the fact that the private keys are put into the initrd, need to have a think about that. I'm not sure there's any decent way around it?

Using different keys is one idea, I suppose. However, if a malicious hosting company wanted to fake the ssh server on a reboot and trick you into providing the unlock passphrase, they could do it with whatever keys are in the initrd.

Copy link

It looks like something broke after the recent Archlinux kernel upgrades. The preboot network comes up, however dropbear is not listening. Attaching to the serial console I see the following:
[ 57.042346] IP-Config: Complete:
[ 57.083296] device=eth0, hwaddr=b8:27:eb:07:27:a3, ipaddr=, mask=, gw=
[ 57.211198] host=pie, domain=, nis-domain=(none)
[ 57.273785] bootserver=, rootserver=, rootpath=
[ 57.368803] md: Waiting for all devices to be available before autodetect
[ 57.452338] md: If you don't use raid, use raid=noautodetect
[ 57.522872] md: Autodetecting RAID arrays.
[ 57.573271] md: Scanned 0 and added 0 devices.
[ 57.627728] md: autorun ...
[ 57.662342] md: ... autorun DONE.
[ 57.703415] RAMDISK: Couldn't find valid RAM disk image starting at 0.
[ 57.783096] Waiting for root device /dev/mapper/root...

Any idea what might be the issue?

Copy link

To answer my own question, here's the solution:

It looks like the initrd values must be altered for the newer releases of Arch.

Copy link

galets commented Apr 10, 2015

New versions of the kernel don't work with this write-up. initrd must go to 0x01f00000 . See

Copy link

Has anyone of you by any chance succeeded to get a similar setup running on BeagleBone Black? Any tips & tricks are welcome. :)

Copy link

Seeing as I can't open a pull request for a Gist, I'll put this in the comments and hope @pezz picks it up.

I was having some trouble with "couldn't find valid ram disk image starting at 0" at boot, and infinite waiting for /dev/mapper/root to become available. I found this thread:

After changing the end of /boot/config.txt to be just initramfs initrd (no hex address) my issue was resolved.

Could you update your Step 9 to reflect this? Thanks

Copy link

justinsteven commented Jun 12, 2016

+1 on the initramfs initrd 0x00f00000 causing issues.

When config.txt reads initramfs initrd 0x00f00000 and cmdline.txt reads initrd=0x00f00000 I get the following during boot:

[    2.466036] Trying to unpack rootfs image as initramfs...
[    2.471906] rootfs image is not initramfs (junk in compressed archive); looks like an initrd
[    2.507794] Freeing initrd memory: 3936K (c0f00000 - c12d8000)
<-- SNIP -->
[    4.489928] RAMDISK: Couldn't find valid RAM disk image starting at 0.
[    4.504999] Waiting for root device /dev/mapper/root...
[    4.602585] usb 1-1.1: new high-speed USB device number 3 using dwc_otg
[    4.712978] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00
[    4.725602] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[    4.741952] smsc95xx v1.0.4
[    4.817193] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-20980000.usb-1.1, smsc95x
x USB 2.0 Ethernet, <REDACTED>

And then it hangs.

When I have config.txt read just initramfs initrd and I omit initrd=0x00f00000 from config.txt I get:

[    2.464528] Trying to unpack rootfs image as initramfs...
[    3.001867] Freeing initrd memory: 3936K (dbc18000 - dbff0000)
<-- SNIP -->
[    5.100966] usb 1-1.1: new high-speed USB device number 3 using dwc_otg
[    5.121092] random: systemd-tmpfile urandom read with 40 bits of entropy available
starting version 230
:: running hook [udev]
:: Triggering uevents...
[    5.231425] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00
[    5.243753] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[    5.288667] smsc95xx v1.0.4
[    5.401484] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-20980000.usb-1.1, smsc95xx USB 2.0 Ethernet, <REDACTED>
:: running hook [encrypt]
Waiting 10 seconds for device /dev/disk/by-uuid/796F-002C ...
Keyfile could not be opened. Reverting to passphrase.

A password is required to access the root volume:
Enter passphrase for /dev/mmcblk0p3:

(NB. I have a keyfile on a USB drive that's unplugged for demonstration, hence the passphrase prompt)

@pezz please update Step 9 and Step 10.

Thanks for the guide! Came in very handy apart from the small snag, which I assume is only an issue these days due to the kernel overlapping with where you're suggesting initrd should be mapped.

Edit: FWIW my testing is based on what I believe to be a Model B Revision 2.0 (512MB), PCB says: "Raspberry Pi (c)2011.12"

Copy link

NicoHood commented Jul 5, 2016

Copy link

NicoHood commented Jul 23, 2016

Some setting have changed for raspi and arch over the time. You do no longer need to hardcode the initramfs file position and after a kernel update the initrd will get updated automatically (which is a huge improvement compared to raspbian). The dropbear AUR package seems outdated and i have not tried that.

For anyone who needs an updated tutorial, here are just the steps i used to create the luks:

sudo pacman -S --needed mkinitcpio rsync

shrink partition with gparted (on another pc), create a new partition on the end

sudo cryptsetup luksFormat -c aes-xts-plain64 -s 512 -h sha512 --use-random -i 30000 /dev/mmcblk0p3

sudo cryptsetup luksOpen /dev/mmcblk0p3 root
sudo mkfs.ext4 /dev/mapper/root

sudo mount /dev/mapper/root /mnt

sudo rsync --progress -axv / /mnt/

sudo nano /etc/mkinitcpio.conf
HOOKS="base udev autodetect modconf block keymap encrypt filesystems keyboard fsck"

sudo mkinitcpio -k $(uname -r) -g /boot/initrd -c /etc/mkinitcpio.conf

sudo nano /boot/config.txt
initramfs initrd followkernel

sudo nano /boot/cmdline.txt
cryptdevice=/dev/mmcblk0p3:root root=/dev/mapper/root

sudo nano /mnt/etc/fstab
/dev/mapper/root  /               ext4    defaults,noatime  0       1

sudo nano /mnt/etc/crypttab
root   /dev/mmcblk0p3   none   luks

Copy link

NicoHood commented Sep 3, 2016

For those of you who follow this gist, I've made a full tutorial on how to install arch with encrypted root. It also uses btrfs which makes use of snapper snapshots. So you never need to reinstall the raspi when you want to revert a change to the root filesystem.

Copy link

Thanks for this instruction. It helped me a lot, although not every step is up to date.
But i have a question about the security:
what are the security implications resulting from step 14? Is there any way to prevent them? Thanks for clarifying.

Copy link

morgner commented Dec 10, 2017

Many thanks for the docu, it helped alot!

A not yet complete revised version.

mkinitcpio -k $(uname -r) -g /boot/initrd is now mkinitcpio -p

This deals always with the correct kernel and creates the correct files. initrd is no more the correct file name and kernelupgrades meanwhile call this function automatically.

The file /boot/cmdline.txt is no more valid, now it's /boot/boot.txt and you need to call /boot/mkscr which generates /boot/boot.scr only boot.scr will be read during boot time.

Now is time to move the construct from p3 to p2 an generate an image ready to be installed.... ;-)

Copy link

gea0 commented Nov 17, 2018

Thanks for the the contributions of everyone here, it greatly helped me.
Although the advice to overwrite with /dev/zero is pretty moot, it is pointless to do so, and gives a false sense on security. Use /dev/urandom instead!

Also, i made a new, complete, up-to-date tutorial!
It installs the newer 64-bit Arch Linux ARM (armv8 architecture), using the AchlinuxARM-rpi-3-latest.tar.gz image.
It also includes the option to unlock the encrypted system over SSH!

If you spot any issues, please contact me!

Arch Linux ARM 64 on Raspberry Pi 3 B+ With Full Disk Encryption And SSH Unlock: 2018 Edition

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment