Official support from Canonical for the Raspberry Pi has come a long way. We can now install officially supported Ubuntu on the Pi! In my previous guide for Ubuntu 18.04 on the Pi the Raspberry Pi was not officially supported yet and to be honest the experience was pretty janky.
The previous LTS “unofficial” release had so many problems I actually rolled my own image with dozens of fixes to common ailments before I quickly realized that maintaining a Linux distro, even in such a limited capacity as patching in and distributing fixed binaries, was a monumental undertaking.
Fortunately the current Ubuntu 20.04 LTS release is officially certified for the Raspberry Pi. This combined with Ubuntu’s full 64 bit userland/system environment allows you to take full advantage of the 8 GB Pi’s memory without per-process 3GB memory limits (very useful if you are doing something like running a Minecraft server and want to allocate almost all of the 8 GB to it) means there has never been a better time to give Ubuntu a try on the Pi.
This guide takes it a step further and shows you how to get Ubuntu 20.04 / 20.10 / 21.04 / etc. working with a SSD. Let’s get started!
Equipment Used
The Kingston A400 has been a great drive to use with the Pi for years. It’s reliable, widely available around the world, has low power requirements and performs very well. It’s also very affordable. This drive has been benchmarked over 1000 times at pibenchmarks.com and is the #1 most popular SSD among the Pi community!
Links: AliExpress*, Amazon.com*, Amazon.ca*, Amazon.com.au*, Amazon.co.jp*, Amazon.co.uk*, Amazon.de*, Amazon.es*, Amazon.fr*, Amazon.it*, Amazon.nl*, Amazon.pl*, Amazon.se*, Amazon.sg*
The USB 3.1 variant of the StarTech 2.5″ SATA adapter works well with the Pi 4. The USB 3.0 variant doesn’t have firmware updates available and is not recommended.
Links: Amazon.com*, Amazon.ca*, Amazon.com.au*, Amazon.co.jp*, Amazon.co.uk*, Amazon.de*, Amazon.es*, Amazon.fr*, Amazon.it*, Amazon.nl*, Amazon.pl*, Amazon.se*, Amazon.sg*
NVME Option (powered USB hub required, see “Power Requirements” section in my more generalized Raspberry Pi 4 USB booting guide):
The Samsung 970 EVO Plus is a fantastic drive and has fallen in price substantially. It’s widely available around the world. The smaller capacities (such as the 250GB version) of this drive are perfect for the Pi! This is the top performance option without going into the “Pro” series of the lineup which are much more expensive.
Links: AliExpress*, Amazon.com*, Amazon.ca*, Amazon.com.au*, Amazon.co.jp*, Amazon.co.uk*, Amazon.de*, Amazon.es*, Amazon.fr*, Amazon.it*, Amazon.nl*, Amazon.pl*, Amazon.se*, Amazon.sg*
If you really want to take things over the top the ASUS Rog Strix M.2 NVMe enclosure uses the latest USB 3.2 Gen2 specification, is RGB capable and works with the Pi! Unsurprisingly, adding the extra lighting does take extra power! A powered USB hub is also required for this enclosure. More widely available than the ICY BOX but tends to be on the expensive side.
Links: AliExpress*, Amazon.com*, Amazon.ca*, Amazon.com.au*, *Amazon.co.jp*, Amazon.co.uk*, Amazon.de*, Amazon.es*, Amazon.fr*, Amazon.it*, Amazon.nl*, Amazon.pl*, Amazon.se*, Amazon.sg*
Prerequisites
Verify Power Supply Size (3.5A strongly recommended)
Check your Raspberry Pi’s power supply size and make sure it is delivering at least 3.5A. There are a lot of USB C adapters for the Raspberry Pi that are only 3.0A. These will typically work fine, until you plug in something like a SSD which draws power from the Pi and there is nothing left to give.
Most SSDs are quite power efficient but HDDs draw significantly more. Older generations of SSDs used quite a bit more power than newer ones as well. If you are using an older drive or a drive that you know is power hungry you need to pay extra attention to having a quality power source with plenty of capacity.
A good alternative option to relying on the Pi to power the drive is using a powered USB hub* so your drive doesn’t need to draw power from the Pi’s limited power budget. Make sure you get one that is compatible with the Pi as some powered USB hubs won’t work properly with it so check the reviews and do your research to make sure people are using it successfully with the Pi.
Using a 3.5A power supply* or powered USB hub* will ensure your drive is getting enough power without impacting the Pi’s stability.
Recommended Power Solutions
The Sabrent powered USB hub delivers a whopping 2.5A of dedicated power for your USB attached devices. This is almost as much as the Pi adapter itself is rated for (3.0A). It will easily power the most thirsty of setups such as NVMe enclosures.
Links: Amazon.com*, Amazon.ca*, Amazon.com.au*, Amazon.co.uk*, Amazon.es*, Amazon.it*, Amazon.nl*, Amazon.pl*, Amazon.se*
Note: Make sure Amazon doesn’t try to take you to the non-powered version and that it’s the one with the AC adapter that plugs in to provide extra power
The CanaKit 3.5A adapter has an extra half an amp (500 mA) of capacity to give some breathing room to your accessories. This is bigger than the official Pi power supply which provides 3.0A.
Links: Amazon.com*, Amazon.ca*, Amazon.com.au*, Amazon.sg*
Verify Storage Adapter Compatibility
You will need a USB 3.0 storage adapter. See my other article on USB booting not specific to Ubuntu for a lot more details on the storage adapters!
Get Latest Raspbian & Updates
To update your bootloader / firmware you should use Raspbian on a SD card. Right now support in third party operating systems to do anything with the new Raspberry Pi 4’s firmware or bootloader is very limited / nonexistent. You can use a third party operating system later once you set the boot mode, but to actually make these changes we will use official Raspbian.
First make sure that you have the absolute latest updates and firmware for the Pi. To upgrade all your packages and firmware to the latest version use the following command:
sudo apt update && sudo apt full-upgrade -y
Once the update has completed restart your Pi with a sudo reboot command to apply the latest firmware / kernel updates.
Verify EEPROM Bootloader is up to date
We can check if your Pi’s bootloader firmware is up to date with the following command:
sudo rpi-eeprom-update
If your Raspbian is *very* out of date you may not have this utility and can install it using:
sudo apt install rpi-eeprom
The output from rpi-eeprom-update will look like this if you are not up to date:
BCM2711 detected VL805 firmware in bootloader EEPROM *** UPDATE AVAILABLE *** BOOTLOADER: update available CURRENT: Thu 3 Sep 12:11:43 UTC 2020 (1599135103) LATEST: Tue 24 Nov 15:08:04 UTC 2020 (1606230484) FW DIR: /lib/firmware/raspberrypi/bootloader/beta VL805: up-to-date CURRENT: 000138a1 LATEST: 000138a1
If it says any updates are available they be installed manually by adding ‘-a’ to the end of our previous command like this:
sudo rpi-eeprom-update -a
After the updates finish installing restart your Pi as firmware updates will not be applied until after a reboot. Now if you run rpi-eeprom-update to check for updates again it should say you are on the latest and up to date!
Changing rpi-eeprom’s Release Channel
Note: As of February 16th the firmware available in the “critical” branch is new enough to USB boot so I no longer recommend changing this. One reader even let me know in the comments that on the “stable” channel his storage was getting corrupted prompting a full reinstall!
By default you will only receive updates from Raspbian’s “critical” channel. This is a very conservative firmware update channel that will only give you very well tested firmware updates that are considered critical fixes for the device. Another channel that is available is “stable”.
Carlos and other commenters have reported that the current “critical” firmware didn’t work for them and they had to upgrade to the “stable” channel.
To switch to the stable channel we are going to edit the file /etc/default/rpi-eeprom-update:
sudo nano /etc/default/rpi-eeprom-update
Change the line FIRMWARE_RELEASE_STATUS=”critical” to:
FIRMWARE_RELEASE_STATUS="stable"
Now you can run sudo rpi-eeprom-update and you should see a new update available.
Install Ubuntu on USB Storage Device
The new official Raspberry Pi imaging tool is really good. It’s available on Windows, Linux and MacOS and is a small and fast download. It also works fine on most USB mass storage devices like SSDs. Since Ubuntu is now officially supported the image itself is also available in this tool which saves you the trouble of having to find and download the right image files.
64 bit images are recommended for the Pi 4 for better performance but the 32 bit images work as well.
If you want to do things the traditional way you can download the image from the main Ubuntu site and write it yourself using Etcher / dd / Win32diskimager / your preferred tool and skip to the next section. It’s recommended to create the media with the Raspberry Pi Imager unless you are having problems with that utility or are using this as a troubleshooting step.
Once you’ve downloaded the tool run it as administrator/sudo to avoid permission errors. To run the utility from the command line is usually sudo rpi-imager. You’ll be greeted with this screen:
Next click the “Choose OS” button:
Ahh, the benefits of being officially supported! Ubuntu is right there on the list waiting for us. Select the Ubuntu option and you will get the different choices of flavors/architectures. There’s Ubuntu Desktop, Ubuntu Server, and Ubuntu Core in various forms of 64-bit (arm64) and 32-bit (armhf).
If you want to use the out-of-the-box Ubuntu Desktop edition you need to use the 64 bit Ubuntu 20.10 image as they never made a 20.04 desktop version for some reason. This really isn’t usually a big deal though because you can always choose the “Server” version and install Ubuntu’s desktop environment later with:
sudo apt install ubuntu-desktop
Once you’ve selected the edition you want go ahead and pick the “Choose SD Card” option and write the image. Despite not being a SD card my USB mass storage devices showed up anyway (writing the guide I used a StarTech adapter and a Kingston A400 SSD).
I’m sure some of you will manage to find unusual devices and configurations that may not show up in this tool. It doesn’t appear to show “fixed drives” that are physically installed in your machine. Regardless if it is causing a headache you may need to do it the old fashioned way and download the image from the main Ubuntu site and write the image using your favorite imaging tool instead.
Modifying Ubuntu for USB Booting
We need to make some changes to the Ubuntu drive we just created before we boot from it. Make sure your Pi is powered on and booted into Raspbian then plug in your newly imaged Ubuntu drive. We are going to make the changes using the Pi.
Find and Mount Storage Device
First let’s find your storage device using the command:
lsblk
This will show you all the storage devices attached to your system:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 119.2G 0 disk ├─sda1 8:1 0 256M 0 part └─sda2 8:2 0 2.8G 0 part mmcblk0 179:0 0 59.5G 0 disk ├─mmcblk0p1 179:1 0 256M 0 part /boot └─mmcblk0p2 179:2 0 59.2G 0 part /
Your SD card will always start with mmcblk so you can rule that one out. That leaves sda as the only other disk device on the system. This will be the same for most of you but depending on what type of drive and storage adapter you use this can vary. You can substitute whatever yours is in place of /dev/sda in these instructions going forward. If yours is sdb use /dev/sdb. If it’s nvme0 use /dev/nvme0, etc.
In my output under the “MOUNTPOINT” column you can see it is blank. This means the drive isn’t mounted on my system. My mmcblk0p1 mountpoint though is not blank and is “/boot” as an example of a non-blank mountpoint. If you are using the full “Desktop” version of Raspbian it may have automatically mounted your drive and created 2 shortcuts on your desktop that will take you to the files. If your mountpoint is not blank and has something like /media/pi/writable go ahead and unmount them now using the following commands substituting the mountpoint listed for your drive:
sudo umount /media/pi/writable sudo umount /media/pi/system-boot
Now we are going to create two mountpoints and mount the Ubuntu drive. Use these commands substituting your own drive it is not /dev/sda:
sudo mkdir /mnt/boot sudo mkdir /mnt/writable sudo mount /dev/sda1 /mnt/boot sudo mount /dev/sda2 /mnt/writable
Once you have mounted everything correctly your lsblk command’s output should look like this with the mountpoint field now populated:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 119.2G 0 disk ├─sda1 8:1 0 256M 0 part /mnt/boot └─sda2 8:2 0 2.8G 0 part /mnt/writable mmcblk0 179:0 0 59.5G 0 disk ├─mmcblk0p1 179:1 0 256M 0 part /boot └─mmcblk0p2 179:2 0 59.2G 0 part /
Modify Mounted Partitions – Option A – Automated Script
If you just want to get your Ubuntu partition bootable I have made an automated script to do this. As long as you have mounted the partitions as /mnt/boot and /mnt/writable the script will make the necessary changes for Ubuntu 20.04 / 20.10 to boot! The source code for the script is available at https://github.com/TheRemote/Ubuntu-Server-raspi4-unofficial/blob/master/BootFix.sh
Here is a one liner to run the script:
sudo curl https://raw.githubusercontent.com/TheRemote/Ubuntu-Server-raspi4-unofficial/master/BootFix.sh | sudo bash
You may also download it for inspection (such as nano BootFix.sh or opening it in the Text Editor if you are using Desktop Raspbian) with:
curl https://raw.githubusercontent.com/TheRemote/Ubuntu-Server-raspi4-unofficial/master/BootFix.sh -O BootFix.sh chmod +x BootFix.sh nano BootFix.sh
To execute the script use:
sudo ./BootFix.sh
As long as you mounted your partitions correctly it will modify the partition and tell you that it was successful. Now unmount your partitions with the following commands:
sudo umount /mnt/boot sudo umount /mnt/writable
You may now shut down your Pi and remove the SD card from the Pi leaving just the USB mass storage device plugged in. Reconnect the power.
Modify Mounted Partitions – Option B – Manual Instructions
See bottom of the article for the manual instructions section
First Boot
If all went well the system should boot up into Ubuntu’s logon screen! The default credentials are:
Username: ubuntu Password: ubuntu
Before logging in for the first time you will be forced to select a new password. Once you have done that you will be fully logged in!
Important Note: Upon logging in for the first time if the Pi is connected to the internet Ubuntu will immediately/soon start a lengthy update process via snapd and apt. This can be annoying since you'll be ready to start configuring the system and if you do an apt install it will halt and wait for the updates to finish. It may seem like they're stuck, but if you use the 'top' command you will see all sorts of apt/package/update/extraction related activity happening. Even on my 8 GB Pi and a gigabit fiber connection these took a good 20 minutes or so before my CPU activity went back to 0 and the apt lock released. I highly recommend letting these finish and not yanking the power on the Pi / forcing a reboot / trying to kill the processes. It will often cause a ton of very nasty apt and dpkg problems to the point where it's easier to start over from a fresh image than try to fsck and apt install --fix-broken your way out of it Try to do other necessary configuration that doesn't involve apt in the mean time and let these finish in the background.
Once the patching is finished your shiny new Ubuntu 20.04 system is fully ready to use!
Manual Instructions
These are the manual instructions to recreate what the automated script does. If you used the automated script you don’t need to do anything further in this section unless you want to understand more about how it works or you want to do the process manually.
Decompress the kernel
We need to decompress the kernel as we will be changing the way the Pi is booting. Ubuntu uses u-boot by default and we will be switching away from that. We can do this with the following command:
zcat -qf "/mnt/boot/vmlinuz" > "/mnt/boot/vmlinux"
Update config.txt with correct parameters
Now let’s update /mnt/boot/config.txt with the parameters we need to load the decompressed kernel. Open up config.txt with nano with:
sudo nano /mnt/boot/config.txt
Change the [pi4] section to the following contents:
[pi4] max_framebuffers=2 dtoverlay=vc4-fkms-v3d boot_delay kernel=vmlinux initramfs initrd.img followkernel
Create script to automatically decompress kernel
We are going to create a script to automatically decompress the kernel. If we don’t do this we have to decompress it every time Ubuntu updates. This particular part of the script was not written by me and was found at the post on the Raspberry Pi forums by egrechko.
First let’s create the decompression script. Open up a new file with nano using:
sudo nano /mnt/boot/auto_decompress_kernel
Paste the following contents:
#!/bin/bash -e # auto_decompress_kernel script BTPATH=/boot/firmware CKPATH=$BTPATH/vmlinuz DKPATH=$BTPATH/vmlinux # Check if compression needs to be done. if [ -e $BTPATH/check.md5 ]; then if md5sum --status --ignore-missing -c $BTPATH/check.md5; then echo -e "\e[32mFiles have not changed, Decompression not needed\e[0m" exit 0 else echo -e "\e[31mHash failed, kernel will be compressed\e[0m" fi fi # Backup the old decompressed kernel mv $DKPATH $DKPATH.bak if [ ! $? == 0 ]; then echo -e "\e[31mDECOMPRESSED KERNEL BACKUP FAILED!\e[0m" exit 1 else echo -e "\e[32mDecompressed kernel backup was successful\e[0m" fi # Decompress the new kernel echo "Decompressing kernel: "$CKPATH".............." zcat -qf $CKPATH > $DKPATH if [ ! $? == 0 ]; then echo -e "\e[31mKERNEL FAILED TO DECOMPRESS!\e[0m" exit 1 else echo -e "\e[32mKernel Decompressed Succesfully\e[0m" fi # Hash the new kernel for checking md5sum $CKPATH $DKPATH > $BTPATH/check.md5 if [ ! $? == 0 ]; then echo -e "\e[31mMD5 GENERATION FAILED!\e[0m" else echo -e "\e[32mMD5 generated Succesfully\e[0m" fi exit 0
Create apt script to call kernel decompression script automatically
This is a one liner to create a script to call the auto_decompress_kernel script:
echo 'DPkg::Post-Invoke {"/bin/bash /boot/firmware/auto_decompress_kernel"; };' | sudo tee /mnt/writable/etc/apt/apt.conf.d/999_decompress_rpi_kernel
Verify Drive Performance
You can make sure everything is running correctly (and as fast as it should be) by running my quick storage benchmark. You can run the benchmark with the following one-liner:
sudo curl https://raw.githubusercontent.com/TheRemote/PiBenchmarks/master/Storage.sh | sudo bash
This will give you a score you can compare to the other Raspberry Pi Storage Benchmark results and make sure that you are getting an equivalent speed to your peers with the same device!
Fix (some) USB Adapter Problems Using Quirks
Some storage adapters don’t work very well with the Raspberry Pi 4. There is an option that can get a lot of them working using quirks. If your Ubuntu is booting to emergency mode but not in normal mode it’s worth giving quirks a try. This lowers performance, but it’s still much faster than a SD card and your adapter won’t go to waste.
To find out the quirks mode string to use we need to find the device ID string for your adapter and then add an entry to cmdline.txt telling the kernel to apply them on boot.
Find Your Adapter
To apply the quirks we first need to get the adapter id. We will use the sudo lsusb command:
$ sudo lsusb Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 002: ID 174c:55aa ASMedia Technology Inc. Name: ASM1051E SATA 6Gb/s bridge, ASM1053E SATA 6Gb/s bridge, ASM1153 SATA 3Gb/s bridge, ASM1153E SATA 6Gb/s bridge Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
On line 2 we can see my ASM1051E SATA 6Gb/s bridge adapter (it’s the known working StarTech.com 2.5″ SATA to USB 3.1* adapter). You will see something very similar to mine when you run the command and it shouldn’t be too hard to figure out which device it is. If you need more information add a -v switch to make the command sudo lsusb -v. This can sometimes add some additional details to make it easier to figure out which one is your adapter.
If you’re still not sure, we have another command that between the two that can narrow things down. Type / paste the following:
sudo dmesg | grep usb [0.828535] usb usb3: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 4.19 [0.828568] usb usb3: New USB device strings: Mfr=3, Product=2, SerialNumber=1 [0.828597] usb usb3: Product: DWC OTG Controller [0.828620] usb usb3: Manufacturer: Linux 4.19.75-v7l+ dwc_otg_hcd [0.828644] usb usb3: SerialNumber: fe980000.usb [0.830051] usbcore: registered new interface driver uas [0.830182] usbcore: registered new interface driver usb-storage [0.836488] usbcore: registered new interface driver usbhid [0.836511] usbhid: USB HID core driver [0.971598] usb 1-1: new high-speed USB device number 2 using xhci_hcd [1.154217] usb 1-1: New USB device found, idVendor=2109, idProduct=3431, bcdDevice= 4.20 [1.154254] usb 1-1: New USB device strings: Mfr=0, Product=1, SerialNumber=0 [1.154281] usb 1-1: Product: USB2.0 Hub [1.301989] usb 2-1: new SuperSpeed Gen 1 USB device number 2 using xhci_hcd [1.332965] usb 2-1: New USB device found, idVendor=174c, idProduct=55aa, bcdDevice= 1.00 [1.332999] usb 2-1: New USB device strings: Mfr=2, Product=3, SerialNumber=1 [1.333026] usb 2-1: Product: ASM105x [1.333048] usb 2-1: Manufacturer: ASMT [1.333071] usb 2-1: SerialNumber: 123456789B79F
This is the dmesg log showing the hardware detection as hardware is activated on the Pi. If your log is really long you can generate fresh entries by just unplugging a device and plugging it back in and running the command again. Here we can clearly see that the ASM105x is what our StarTech adapter is being detected as.
Now we can go back to our first lsusb command and we want the 8 characters from the ID field that comes right after the Device:
Bus 002 Device 002: ID 174c:55aa ASMedia Technology Inc. Name: ASM1051E SATA 6Gb/s bridge
Our adapter’s ID is: 174c:55aa
Applying Quirks
To apply the quirks to our USB adapter we are going to edit /boot/firmware/cmdline.txt. Type:
sudo nano /boot/firmware/cmdline.txt
We are going to add the following entry into the very front of cmdline.txt:
usb-storage.quirks=XXXX:XXXX:u
In place of the X’s above you will put in your adapter’s ID that we got before. With the example commands I gave above mine would look like this: usb-storage.quirks=174c:55aa:u. After this my cmdline.txt looks like this (everything should be one continuous line, no line breaks!):
usb-storage.quirks=174c:55aa:u dwg_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=LABEL=writable rootfstype=ext4 elevator=deadline rootwait fixrtc
Now reboot the Pi. If the Pi fails to boot you can plug the SD card into the computer and go to /boot/cmdline.txt and undo the change we did so you can boot back in with your SD card.
Verifying Quirks
Once you have rebooted after changing cmdline.txt we can verify the quirks have been applied by doing another dmesg | grep usb command:
sudo dmesg | grep usb [1.332924] usb 2-1: New USB device found, idVendor=174c, idProduct=55aa, bcdDevice= 1.00 [1.332957] usb 2-1: New USB device strings: Mfr=2, Product=3, SerialNumber=1 [1.332983] usb 2-1: Product: ASM105x [1.333006] usb 2-1: Manufacturer: ASMT [1.333028] usb 2-1: SerialNumber: 123456789B79F [1.335967] usb 2-1: UAS is blacklisted for this device, using usb-storage instead [1.336071] usb 2-1: UAS is blacklisted for this device, using usb-storage instead [1.336103] usb-storage 2-1:1.0: USB Mass Storage device detected [1.336479] usb-storage 2-1:1.0: Quirks match for vid 174c pid 55aa: c00000 [1.336611] scsi host0: usb-storage 2-1:1.0
This time we can see in dmesg that UAS was blacklisted for the device and it has loaded with the usb-storage driver instead. This driver tends to be more compatible with the “problematic adapters” but the performance is usually significantly lower. It’s definitely worth a try though as some adapters do better with the quirks performance-wise. The only way to know for sure is to run a benchmark (see “Verify Drive Performance” section).
Other Resources
I compiled the 2022 Raspberry Pi Storage benchmarks which shows the fastest storage devices for the Pi
For easy headless imaging (does support Ubuntu) check out my Headless Raspberry Pi configuration guide
To find out where to get the 64 bit version of Raspberry Pi OS: where to get the 64 bit Raspberry Pi OS image
To find out how to add a UPS backup battery to your Pi check out my UPS for Raspberry Pi guide
Hi, thanks for guide. Unfortunately, I’m unable to get Ubuntu Server to boot after using your automatic script, it just shows a black screen, which doesn’t seem to load anything. I have used RpiOS desktop on an sdcard, and a flashed Ubuntu Server on the SSD, but it still requires the microsd to be started.
Any ideas would be appreciated, thanks
Hey Joe,
Which adapter are you using? Have you used it before to USB boot with another OS other than Ubuntu or is this the first time you’ve tried to USB boot with it? I’m just wondering if it’s one of the ones that has trouble.
Thanks for your reply, I’m using the Sabrent EC-UK30 enclosure, I have tested it with Windows as an external device, but first time using it with the Rpi4 with Ubuntu as USB boot. I was thinking the same thing as you, with the adaptor being troublesome, as it seems to boot into ssd on boot fine, but just hangs on a black screen unfortunately. It seems to load fine with the microsd card in however via ssh.
Just an update, I’ve managed to boot in Ubuntu, however every time I start, it boots into ‘Emergency mode’, I can’t find the root cause unfortunatly.
Hey Joe,
That’s a really interesting result here. I have a crazy idea, which is that if you’re able to get into emergency mode can you edit the /boot/firmware/cmdline.txt file and enable quirks mode? There’s a “Fix (some) USB Adapter Problems Using Quirks” section in my New Raspberry Pi 4 USB Guide that runs through how to enable it. I’ll also add those sections to this post as they may help people with this in the future.
I have a feeling it is a chipset incompatibility that quirks mode may correct and let you boot into regular Ubuntu. I think it’s able to boot into “emergency mode” using some sort of fallback compatibility mode. It’s worth a try at least!
Bro, I’m not sure how I missed your Quirks fix, but I applied the fix and I’m happy to say everything is booting correctly now!
Thank you so much, you made my day! Happy Holidays 🙂
Very glad to hear it Joe! Don’t sweat it about missing anything, I actually added some more information in this article after your comment when I realized it could be of assistance. Happy Holidays to you as well!
Hey,
First off, great tutorial and script c: much appreciated.
I’m having some trouble with this on a fresh RaspiOS minimal image to setup ubuntu server 20.10.
I flashed a wd green 128gb with the ubuntu-20.10-preinstalled-server-arm64+raspi.img image from ubuntu, and an old noob sd with 2020-08-20-raspios-buster-arm64-lite.img
I have the same problem as Lucien with vmlinuz “not being in gzip format”
./bootprep.sh
makes mount points
mkdir: cannot create directory '/mnt/boot': File exists
mkdir: cannot create directory '/mnt/writable': File exists
Mount which device? enter /dev/sdX# and partitions #s
(first one will be interpreted as boot, second one system)
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 111.8G 0 disk
|-sda1 8:1 0 256M 0 part
`-sda2 8:2 0 2.9G 0 part
mmcblk0 179:0 0 7.3G 0 disk
|-mmcblk0p1 179:1 0 256M 0 part /boot
`-mmcblk0p2 179:2 0 7G 0 part /
device X?
a
# corresponding to boot
1
# corresponding to system
2
confirm that the partitions have been mounted correct
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 111.8G 0 disk
|-sda1 8:1 0 256M 0 part /mnt/boot
`-sda2 8:2 0 2.9G 0 part /mnt/writable
mmcblk0 179:0 0 7.3G 0 disk
|-mmcblk0p1 179:1 0 256M 0 part /boot
`-mmcblk0p2 179:2 0 7G 0 part /
now run BootFix.sh!
pi@raspberrypi:~ $ sudo ./BootFix.sh
Found writable partition at /mnt/writable
Found boot partition at /mnt/boot
Decompressing kernel from vmlinuz to vmlinux...
gzip: /mnt/boot/vmlinuz: not in gzip format
Kernel decompressed
Updating config.txt with correct parameters...
Creating script to automatically decompress kernel...
Creating apt script to automatically decompress kernel...
Updating Ubuntu partition was successful! Shut down your Pi, remove the SD card then reconnect the power.
I manged to get it booting once:
pi@raspberrypi:/mnt/boot $ od -A d -t x1 vmlinuz | grep '1f 8b 08 00'
pi@raspberrypi:/mnt/boot $ od -A d -t x1 vmlinuz | grep 'fd 37 7a 58 5a 00'
16826032 78 7a 5f 64 65 63 00 00 fd 37 7a 58 5a 00 00 00
pi@raspberrypi:/mnt/boot $ od -A d -t x1 vmlinuz | grep '42 5a 68 39'
pi@raspberrypi:/mnt/boot $ su
root@raspberrypi:/mnt/boot/extr# sudo dd if=vmlinuz bs=1 skip=16826040 | unxz > vmlinux
unxz: (stdin): Compressed data is corrupt
But now I run into this problem… would be weird that different mirrors have different compression types, so probably something else spooky.
Why I tried from scratch again was because the standard ubuntu login wouldn’t work despite internet connection and letting it sit overnight to finish background updates. I also chrooted into it and made a new user which didn’t work either.. something seems weird with these ubuntu images :’C
I also found some info about using extract-vmlinux from git.kernel.org
or from /usr/src/linux-headers on ubuntu but keep running into problems with this as well.. I’ll keep trying I guess but if you have any clues that would be greatly appreciated, at least I get to learn about all these different tools in the process ^^)
Hey Ada,
I think I’ve found the problem. Were you using a 32 bit image? It looks like the script was leaving in arm_64bit=1 in the config.txt on 32 bit images. This has been fixed.
Can you give it another try?
ubuntu-20.10-preinstalled-server-arm64+raspi.img image from ubuntu is already able to boot from usb storage without any changes as long as you have the updated bootloader.
Your decompress kernel script (as copy/pasted to this page) contains escaped characters that, if directly copied to a local script, will fail.
echo -e "\e[31mMD5 GENERATION FAILED!\e[0m"
else
echo -e "\e[32mMD5 generated Succesfully\e[0m"
Note that each open- and close-quote contains escape sequences.
Regarding at least one person above having a problem with the file system going bad/becoming locked. I tried migrating my SD card to a Samsung 256G (MZ – 5PA256A) SSD connected via some no-name USB3SATA JMicron (JMS579) adapter (quirks mode enabled). I used a Mac with ddrescue to completely copy the SD to the SSD (I copied at the block device level, not at the partition level):
ddrescue --force /dev/disk7 /dev/disk8
The Pi4 booted with this drive with no problem, but after about 1 minute of running would start to throw inode write errors (I seem to have lost them in my scrollback). After a short period of this Raspian would complain that I was using a read-only drive, and then would refuse to execute any executables (“ls not found” etc). Multiple fdisk-at-startup runs, etc made no difference. I then replaced the Samsung SSD with an old “OCZ 60Gb” I happen to have lying around. Using the exact same steps as above (ddrescue, fdisk at startup, raspi-config to resize the primary partition), this drive has been working flawlessly.
I’ve connected the Samsung back to the Mac to do more testing against it. So far a DiskUtil secure erase (7 writes over the entirety of the storage area), plus multiple abuse-runs with dd:
dd if=/dev/zero of=/Volumes/Untitled/foo bs=1m count=256k
and
dd of=/dev/zero if=/Volumes/Untitled/foo bs=1m count=256k
have not produced any errors or warnings, so my best conclusion is that Raspbian (or the JMicron chip) somehow chokes on this SSD. I’d extrapolate from this that it may have problems with other SSDs and that in certain situations the symptoms of this choking will be “read only” or worse.
I guess that’s a whole bunch of words for “some drives won’t work; buy from the ‘known working’ list.” 🙂
Ugh, my web site formatting must be mangling that. Let me see what I can do. Thanks for the heads up!
Those are pretty interesting results for the Samsung. I’m pulling that up as a 470 series which is not one that I’ve encountered before. I do see it’s a SATA II drive instead of a SATA III drive. I wonder if that has something to do with it possibly? Most adapters I’ve seen are meant for SATA III and the standards themselves are backwards compatible but that assumes the adapter (mostly) and probably to some extent the Pi can work with it.
Theoretically it would max out at 3 GB / sec instead of 6 GB / sec but you’ll hit other bottlenecks on the Pi before reaching anywhere near either of those speeds.
Hi,
I used your automatic script and now every apt-command ends with the follwing error:
flash-kernel: installing version 5.4.0-1025-raspi
Taking backup of vmlinuz.
mv: cannot move '/boot/firmware/vmlinuz' to '/boot/firmware/vmlinuz.bak': Read-only file system
run-parts: /etc/initramfs/post-update.d//flash-kernel exited with return code 1
dpkg: error processing package initramfs-tools (--configure):
installed initramfs-tools package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:
initramfs-tools
Files have not changed, Decompression not needed
E: Sub-process /usr/bin/dpkg returned an error code (1)
Everything seems to work, but I’m afraid this will bite me in the future..
Uh oh! Your boot partition is read-only. Usually this is due to a corrupt partition. It needs an fsck on /dev/sda1. It probably needs an fsck on /dev/sda2 as well.
Did you happen to run your imager tool to create the Ubuntu media on Mint Linux? I was able to find someone else who had this issue here.
run-parts: /etc/initramfs/post-update.d//flash-kernel exited with return code 1
– I see a double forward slash here that I bolded too. The path to this file is not something the script would have any effect on and your OS seems to be getting it wrong here.Failing storage device / missing damaged /etc/fstab are also a possibility but it’s probably a bad/corrupt image. I doubt there’s anything wrong with the drive itself but it’s possible.
You’re right to be concerned. This needs to be corrected. You could try remounting your boot partition as rw but honestly if a fsck on /dev/sda1 doesn’t fix it I would try reimaging it! The Mint Linux guy from my first link ended up writing the image the old school way using dd. This might be worth a try for you too!
One more thing to check. When you are creating the image and you plug in your SSD drive before you run the script if your operating system has a GUI it will usually try to automount the image and create 2 shortcuts on your desktop. If you don’t remove these automounts and then you mount them again they will be double mounted. This was the Mint Linux guy’s issue most likely, and if you aren’t absolutely positive you didn’t unmount the automounts it could have something to do with this as well!
Thank you for the tutorial! But I have a problem. The default 20.04.1 LTS installation comes with kernel version 5.4.0-1023. At first boot the unattended upgrade procedure updates the kernel with version 1025 and after rebooting the kernel version is still 1023. I tried manually running the script but it says nothing has changed. I believe something fails inside the unattended upgrade but the hashes are still preserved so running the script manually doesn’t help. I deleted the hash file but still no change, after reboot the version still stands as 1023. I know it’s hard to debug on someone else’s machine but I can help with all the info needed. Thank you again!
Hey lucian,
Thanks for letting me know! It definitely is hard to debug other people’s machines but you gave me enough to investigate.
I wonder if this is just with the unattended upgrade. What happens if you do a:
sudo apt update && sudo apt dist-upgrade -y
I used the desktop 20.10 version to test and here’s what you should see (just with the 5.4.x kernel instead of 5.8.0). Here was my starting kernel:
rpi@rpi:/boot/firmware$ uname -a
Linux rpi 5.8.0-1008-raspi #11-Ubuntu SMP PREEMPT Thu Nov 12 15:49:32 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux
Now let’s do the dist-upgrade:
Setting up linux-image-5.8.0-1010-raspi (5.8.0-1010.13) ...
I: /boot/vmlinuz.old is now a symlink to vmlinuz-5.8.0-1008-raspi
I: /boot/initrd.img.old is now a symlink to initrd.img-5.8.0-1008-raspi
I: /boot/vmlinuz is now a symlink to vmlinuz-5.8.0-1010-raspi
I: /boot/initrd.img is now a symlink to initrd.img-5.8.0-1010-raspi
Setting up linux-image-raspi (5.8.0.1010.13) ...
This is where the links to the kernel are actually updated so you should see this in here. After a few more steps the system will update the ramdisk which will look like this:
update-initramfs: Generating /boot/initrd.img-5.8.0-1008-raspi
Using DTB: bcm2711-rpi-4-b.dtb
Installing /lib/firmware/5.8.0-1008-raspi/device-tree/broadcom/bcm2711-rpi-4-b.dtb into /boot/dtbs/5.8.0-1008-raspi/./bcm2711-rpi-4-b.dtb
Taking backup of bcm2711-rpi-4-b.dtb.
Installing new bcm2711-rpi-4-b.dtb.
Ignoring old or unknown version 5.8.0-1008-raspi (latest is 5.8.0-1010-raspi)
Here you can see it ignore the old kernel. After a reboot I ended up with:
Linux rpi 5.8.0-1010-raspi #13-Ubuntu SMP PREEMPT Wed Dec 9 17:14:07 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux
Can you follow my steps and see what you get and how it compares to these? My initial suspicion is that unattended-upgrade might not be triggering the apt script.
One more command we can have you try that just updates the ramdisk (the last step):
sudo update-initramfs -u
Hello,
I didn’t try the steps above yet but I’m able to see an error inside the logs and I have some proper steps to reproduce.
1. So after booting from the SSD the unattended upgrade installs the new kernel (1025), I could see that in htop when it was generating the initramfs. I let it run for about 30mins to finish everything.
2. Rebooted as ubuntu asks, and the kernel is still 1023. The contents of the boot partition:
lrwxrwxrwx 1 root root 43 Dec 13 09:53 dtb -> dtbs/5.4.0-1025-raspi/./bcm2711-rpi-4-b.dtb
lrwxrwxrwx 1 root root 43 Dec 13 09:51 dtb-5.4.0-1015-raspi -> dtbs/5.4.0-1015-raspi/./bcm2711-rpi-4-b.dtb
lrwxrwxrwx 1 root root 43 Dec 13 09:53 dtb-5.4.0-1025-raspi -> dtbs/5.4.0-1025-raspi/./bcm2711-rpi-4-b.dtb
drwxr-xr-x 4 root root 4096 Dec 13 09:51 dtbs
drwxr-xr-x 5 root root 4608 Jan 1 1970 firmware
lrwxrwxrwx 1 root root 27 Dec 13 09:10 initrd.img -> initrd.img-5.4.0-1025-raspi
-rw-r--r-- 1 root root 13818442 Dec 13 09:51 initrd.img-5.4.0-1015-raspi
-rw-r--r-- 1 root root 13818499 Dec 13 09:53 initrd.img-5.4.0-1025-raspi
lrwxrwxrwx 1 root root 27 Jul 31 16:44 initrd.img.old -> initrd.img-5.4.0-1015-raspi
lrwxrwxrwx 1 root root 24 Dec 13 09:10 vmlinuz -> vmlinuz-5.4.0-1025-raspi
-rw------- 1 root root 8390521 Jul 10 05:18 vmlinuz-5.4.0-1015-raspi
-rw------- 1 root root 8340400 Dec 9 11:55 vmlinuz-5.4.0-1025-raspi
lrwxrwxrwx 1 root root 24 Jul 31 16:44 vmlinuz.old -> vmlinuz-5.4.0-1015-raspi
3. uname -r outputs 5.4.0-1023-raspi
4. sudo apt update
5. sudo apt upgrade to install the remaining updates and some errors show up:
update-initramfs: Generating /boot/initrd.img-5.4.0-1015-raspi
W: missing /lib/modules/5.4.0-1015-raspi
W: Ensure all necessary drivers are built into the linux image!
depmod: ERROR: could not open directory /lib/modules/5.4.0-1015-raspi: No such file or directory
depmod: FATAL: could not search modules: No such file or directory
cat: /var/tmp/mkinitramfs_wMsnnn/lib/modules/5.4.0-1015-raspi/modules.builtin: No
update-initramfs: Generating /boot/initrd.img-5.4.0-1025-raspi
W: missing /lib/modules/5.4.0-1025-raspi
W: Ensure all necessary drivers are built into the linux image!
depmod: ERROR: could not open directory /lib/modules/5.4.0-1025-raspi: No such file or directory
depmod: FATAL: could not search modules: No such file or directory
cat: /var/tmp/mkinitramfs_mPYMrl/lib/modules/5.4.0-1025-raspi/modules.builtin: No such file or directory
find: ‘/var/tmp/mkinitramfs_mPYMrl/lib/modules/5.4.0-1025-raspi/kernel’: No such file or directory
5. The auto update script says nothing has changed when the package installation ends
So it still doesn’t boot the newly installed kernel. I could try a dist-upgrade to upgrade to 20.10 but I would like to use 20.04 for a while now 🙂
The contents of the firmware folder is:
-rwxr-xr-x 1 root root 23824896 Dec 13 09:11 vmlinux
-rwxr-xr-x 1 root root 25907712 Dec 13 09:02 vmlinux.bak
-rwxr-xr-x 1 root root 8340400 Dec 13 10:13 vmlinuz
-rwxr-xr-x 1 root root 8340400 Dec 13 09:53 vmlinuz.bak
and the check.md5 file is there. So I think the script runs when the unattended upgrade updates the kernel to 1025
Then I manually ran:
ubuntu@ubuntu:/boot/firmware$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-5.4.0-1025-raspi
W: missing /lib/modules/5.4.0-1025-raspi
W: Ensure all necessary drivers are built into the linux image!
depmod: ERROR: could not open directory /lib/modules/5.4.0-1025-raspi: No such file or directory
depmod: FATAL: could not search modules: No such file or directory
cat: /var/tmp/mkinitramfs_Jz538Z/lib/modules/5.4.0-1025-raspi/modules.builtin: No such file or directory
find: ‘/var/tmp/mkinitramfs_Jz538Z/lib/modules/5.4.0-1025-raspi/kernel’: No such file or directory
Hey Lucian,
It looks like you’re missing the entire kernel modules directory. I take it /lib/modules/5.4.0-1025-raspi doesn’t actually exist?
The script doesn’t do anything with the kernel modules. I’m really perplexed what you are seeing. I guess I need to fire up the old one again and make sure I don’t see this at all on there.
This is a separate package called linux-modules-5.x. You can see all the ones you have with:
sudo apt search linux | grep modules
The script is pretty simple. There’s basically nothing to it except decompressing the kernel. If the kernel isn’t decompressed, your Pi literally can’t boot and won’t get past a black screen. Without a kernel there is nothing to boot to, so I think something else is going on here.
Did you use the Raspberry Pi imaging tool to create these or are you downloading images off Ubuntu’s web site? I have only done it using the images that the Raspberry Pi imaging tool creates.
I’m trying with Ubuntu 20.10 now and I get a weird error:
ound writable partition at /mnt/writable
Found boot partition at /mnt/boot
Decompressing kernel from vmlinuz to vmlinux...
gzip: /mnt/boot/vmlinuz: not in gzip format
Kernel decompressed
Updating config.txt with correct parameters...
Creating script to automatically decompress kernel...
Creating apt script to automatically decompress kernel...
Updating Ubuntu partition was successful! Shut down your Pi, remove the SD card then reconnect the power.
And vmlinux has 0 bytes
This looks right. The kernel isn’t in gzip format which is normal. Did it boot?
Edit: It did, at least when the initial script was ran on Raspbian, I saw your other reply, awesome!
It worked, finally. It was my mistake. I switched to using Raspian to do the initial setup scripts and I actually removed the microSD card when booting, although it looked like it worked normally and USB has higher boot priority. Thank you for taking the time to help!
Oh wow, that is a great find Lucian, I’m glad you followed up because I should have asked those questions right off the bat!
Thanks for following through and posting the results. It’s going to help a lot of people. I’m also going to update the guide a little bit to help others avoid going down this path.
There’s some things I can do to help with this too. I can add some better safety checks in the script to make sure it’s running on a compatible version of Raspbian that it has all the files it needs.
Basically Raspbian is used as the “source” for the script, or Raspbian’s /boot folder specifically. This is used to update the .elf and .bat firmware files on the Ubuntu device as the ones it ships with won’t boot. If exactly the right things aren’t in there you’re going to see some very perplexing behavior like you have. I’ll get that added in there.
Cheers!
My script that was installed using the automated script is missing some parameters, I think that is the reason:
#!/bin/bash -e
# auto_decompress_kernel script
BTPATH=/boot/firmware
CKPATH=/vmlinuz
DKPATH=/vmlinux
# Check if compression needs to be done.
if [ -e /check.md5 ]; then
if md5sum --status --ignore-missing -c /check.md5; then
echo -e "\e[32mFiles have not changed, Decompression not needed\e[0m"
exit 0
else
echo -e "\e[31mHash failed, kernel will be compressed\e[0m"
fi
fi
# Backup the old decompressed kernel
mv .bak
if [ ! 0 == 0 ]; then
echo -e "\e[31mDECOMPRESSED KERNEL BACKUP FAILED!\e[0m"
exit 1
else
echo -e "\e[32mDecompressed kernel backup was successful\e[0m"
fi
# Decompress the new kernel
echo "Decompressing kernel: "".............."
zcat >
if [ ! 0 == 0 ]; then
echo -e "\e[31mKERNEL FAILED TO DECOMPRESS!\e[0m"
exit 1
else
echo -e "\e[32mKernel Decompressed Succesfully\e[0m"
fi
# Hash the new kernel for checking
md5sum > /check.md5
if [ ! 0 == 0 ]; then
echo -e "\e[31mMD5 GENERATION FAILED!\e[0m"
else
echo -e "\e[32mMD5 generated Succesfully\e[0m"
fi
exit 0
Thank you for the information, it helps a lot, however when I do:
sudo apt-get install --reinstall linux-image-5.4.0-1023-raspi
It stops with:
mv: missing destination file operand after '.bak'
Try 'mv --help' for more information.
Decompressed kernel backup was successful
Decompressing kernel: ..............
/boot/firmware/auto_decompress_kernel: line 25: syntax error near unexpected token `newline'
/boot/firmware/auto_decompress_kernel: line 25: `zcat > '
E: Problem executing scripts DPkg::Post-Invoke '/bin/bash /boot/firmware/auto_decompress_kernel'
E: Sub-process returned an error code
If I reboot it no longer boots.
Hey Bastian,
You’re right. It looks like the way I am creating the automated script has a mistake. The EOF in the script probably needs a backslash in front of it to escape it. After the “zcat” in what you posted there are no variables because they were not escaped properly. I did test it, and the scripts work in the non-automated form, but I did not test reinstalling the kernel with the automated version so I missed it, whoops!
I’ll get a fix up shortly, thanks for letting me know!
This fix is up. The problem was:
echo "Creating script to automatically decompress kernel..."
cat << EOF | sudo tee "$mntBoot/auto_decompress_kernel">/dev/null
needed to be
echo "Creating script to automatically decompress kernel..."
cat << \EOF | sudo tee "$mntBoot/auto_decompress_kernel">/dev/null
I’ve committed this fix to GitHub. Can you give it another go here? I just tested and was able to dist-upgrade an entire 20.10 desktop installation and successfully patch my kernel as well as reboot with this fix added.
Hopefully you were the first one who tried it but if anyone else out there had this problem and didn’t comment go ahead and run the new automated script here with this fix!