Skip to main content

Command Palette

Search for a command to run...

Installing Ubuntu Server on M.2 Drives for Pi5 SBCs.

Or: Setting Up Pi5 SBCs for an HA Cluster.

Updated
12 min read
Installing Ubuntu Server on M.2 Drives for Pi5 SBCs.
B

Thank you for reading this post.

My name is Brian and I'm a developer from New Zealand. I've been interested in computers since the early 1990s. My first language was QBASIC. (Things have changed since the days of MS-DOS.)

I am the managing director of a one-man startup called Digital Core (NZ) Limited. I have accepted the "12 Startups in 12 Months" challenge so that DigitalCore will have income-generating products by April 2024.

This blog will follow the "12 Startups" project during its design, development, and deployment, cover the Agile principles and the DevOps philosophy that is used by the "12 Startups" project, and delve into the world of AI, machine learning, deep learning, prompt engineering, and large language models.

I hope you enjoyed this post and, if you did, I encourage you to explore some others I've written. And remember: The best technologies bring people together.

Updated: Tuesday 14th October 2025

TL;DR.

This post is a guide to upgrading Pi5 SBCs (Raspberry Pi 5 Single Board Computers) from using microSD cards to employing M.2 NVMe drives.

Attributions:

None ↗.


An Introduction.

Upgrading from using a microSD card on a Pi5 SBC to using an M.2 NVMe drive on the same device can really open up the storage capability of the Raspberry Pi platform:

The purpose of this post is to demonstrate how to install an OS onto an M.2 NVMe drive for a Pi5 SBC.


The Big Picture.

There is a redundancy requirement when assembling an HA (High Availability) cluster. Many different flavours of Kubernetes (K8s, K3s, MicroK8s, K0s, and even Minikube) support HA clustering and I will use my Homelab hardware, such as it is, to practice the skills of deploying HA solutions. Using Pi5 SBCs as HA Master Nodes (sometimes called Control Planes) is fine due to the low resource requirements. Worker Nodes (sometimes called Data Planes), on the other hand, consumes many resources (CPU cycles, RAM, bandwidth, etc.) due to processing resource requests. Not only do Worker Nodes need to send a LOT of data, but they must also spin up more nodes when the demand increases. More nodes means more resources consumed.

For M.2 NVMe drives, there is a speed difference between the (older) SATA interface and the (newer) NVMe interface. The drives I use in this post are NVMe PCIe Gen3 x4 ↗. The M.2 NVMe enclosures I use also support NVMe Drives. Also, the hats that are installed in the Pi5 SBCs are also NVMe compatible.

For now, my focus is on installing a Linux distro on M.2 NVMe drives that will be used by Pi5 SBCs.


Prerequisites.

  • A Debian-based Linux distro (I use Ubuntu),

  • 3 x Pi5 single board computers,

  • 3 x Pi5 active coolers,

  • 3 x M.2 NVMe drives,

  • 3 x Pi5 NVMe hats,

  • An M.2 NVMe enclosure,

  • 3 x CAT-5 Ethernet cables, and

  • Access to an Internet router, or a LAN switch, that is connected to the Internet router.


Updating my Base System.

  • From the (base) terminal, I update my (base) system:
sudo apt clean && \
sudo apt update && \
sudo apt dist-upgrade -y && \
sudo apt --fix-broken install && \
sudo apt autoclean && \
sudo apt autoremove -y

NOTE: The Ollama LLM manager is already installed on my (base) system.


What is the Raspberry Pi Imager?

Raspberry Pi Imager is a user-friendly application that allows me to easily install Raspberry Pi OS, or any other compatible operating system, onto a microSD card for use with Raspberry Pi devices. It simplifies the process of selecting the OS and writing it to the card, ensuring that the installation is done correctly.

In my case, I will be installing Ubuntu Server LTS 24.04 onto an M.2 NVMe drive using an M.2 NVMe enclosure.


Installing Pi Imager.

  • From the terminal, I install the Raspberry Imager:
sudo apt install -y rpi-imager

Creating an Ubuntu Server M.2 NVMe Drive.

NOTE: For this process, I use the Raspberry Imager software, 3 x M.2 NVMe drives, an M.2 NVMe enclosure, 3 x M.2 NVMe hats for Pi5 SBCs, and 3 x Pi5 SBCs.

  • I install an M.2 NVMe drive into an M.2 NVMe enclosure:

  • I connect the M.2 NVMe enclosure to my PC:

  • I start the Raspberry Pi Imager:

  • I select Raspberry Pi 5 as my Raspberry Pi Device:

  • I select Ubuntu Server 24.04.2 LTS (64-bit) as the Operating System:

  • I select the M.2 NVMe enclosure (Realtek TS512GMTE440S) as the Storage:

NOTE: TS512GMTE440S is the product ID for the M.2 NVMe drive.

  • I click the NEXT button:

  • From the Use OS customisation? dialog, I click the EDIT SETTINGS button to open the OS Customisation dialog:

  • In the GENERAL tab, I use the following settings:

  • In the SERVICES tab, I use the following settings:

NOTE: Setting the public key encryption for SSH will be described in a later post.

  • In the OPTIONS tab, I use the following settings:

  • I click the SAVE button to return to the previous dialog.

  • Back in the Use OS customisation? dialog, I click the YES button.

  • I read the Warning dialog, then click the YES button:

  • The Raspberry Pi Imager installs Ubuntu Server 24.4.2 LTS (64-bit) onto the M.2 NVMe drive.

  • After the image is written to the M.2 NVMe drive, the M.2 NVMe enclosure is automatically ejected from my PC:

NOTE: The M.2 NVMe enclosure is automatically ejected from my PC due to this setting that was enabled earlier:

  • I unplug the M.2 NVMe enclosure from my PC.

  • I remove the M.2 NVMe drive from the M.2 NVMe enclosure.

  • I install the M.2 NVMe drive into the M.2 NVMe hat that I previously added to my Pi5 SBC.

  • I repeat this process 2 more times (along with making appropriate changes to the settings):

NOTE: Now that the M.2 NVMe drives have been imaged and installed, I now need to provide the Pi5 SBCs with a new boot order.


Creating a MicroSD Card Bootloader.

NOTE: For this process, I use the Raspberry Imager software, a microSD card and a USB card reader.

  • I insert a microSD card into the USB card reader.

  • I insert the USB card reader into my PC.

  • I start the Raspberry Pi Imager:

  • I set the Raspberry Pi Device to Raspberry Pi 5:

  • I set the Operating System to Misc utility images > Bootloader (Pi 5 family) > SD Card Boot:

  • I set the Storage to the SD Card Reader - 31.3 GB:

NOTE: 31.3 GB is the usable capacity of the microSD card inserted in the SD Card Reader.

  • I click the NEXT button:

  • I read the Warning dialog and then click the YES button:

  • It takes less than 20-seconds for the Raspberry Pi Imager to finish:

  • I remove the USB reader from my PC.

  • I remove the microSD card from the USB card reader.


Changing the Pi5 Boot Order.

  • I insert the microSD card into the Pi5 microSD card slot.

  • I power on the Pi5.

  • I wait for the microSD card to rewrite the bootloader in the EEPROM of the Pi5.

NOTE: Rewriting the settings for the bootloader only takes a few seconds.

  • A successful rewrite is shown by a blinking, green LED and a green screen displayed on the monitor. (A failed process is denoted by a blinking, red LED and a red screen displayed on the monitor.)

  • I repeat this process for the remaining Pi5 SBCs.

NOTE: If there is no bootable microSD card in the Pi5, then it will try to boot from an M.2 NVMe drive. If there is no bootable M.2 NVMe drive, the it will try to boot from a USB drive.


What is a Raspberry Pi?

A Raspberry Pi is a single-board computer, or SBC, that is a little larger than a credit card, specifically 85mm x 56mm in size. It looks like a miniature motherboard but all the components, like the CPU, memory, wireless module, USB ports, and the network port are already (and permanently) installed. Hardware upgrades are enabled through the use of ‘hats’. A hat is a circuit board that is installed on top of, or below, the Raspberry Pi. Hats have pins that electrically connect to the header of the Pi, and may also include a ribbon cable that also provides a connection to the SBC.


Assembling a Pi5 that Supports an M.2 NVMe Drive.

  • If installed, I remove the passive heat sink from the Pi5 CPU.

  • I install the active cooler and attach the fan cable to the fan header of the Pi5.

  • I remove a specific screw from the active cooler fan.

  • I connect the NVMe hat to the Pi5 header and use the included long screw to attach it to the active cooler fan.

  • I use the NVMe ribbon cable to connect the NVMe hat to the Pi5.

  • I install the M.2 NVMe drive, the drive with Ubuntu Server 24.4 LTS installed, into the NVMe hat and use the included short screw to secure the drive.

  • On the case, I pop out the case fan because it will get in the way of the NVMe hat.

  • I install the assembled Pi5 into the Pi case.

  • I repeat this process 2 more times:


Setting Up the Local Terminal.

The following describes setting up the remote PiLab servers, two of which will become the control plane nodes of the MicroK8s cluster. These settings must also be applied to the eight NucLab containers that will become the worker nodes of the MicroK8s cluster.


Creating an RSA Key Pair on the Local PC.

  • From my local, PC terminal (CTRL + ALT + T), I start the ssh-agent:
eval "$(ssh-agent -s)"
  • I generate a pair of RSA keys called "/home/brian/.ssh/key-name" (where I replace "key-name" with the name of the remote server):
ssh-keygen -b 4096

NOTE: It is my convention to name RSA keys after the remote server on which they will be used.

  • I add the SSH key to my workstation account (where I replace "key-name" with the actual name of the ssh key):
ssh-add /home/brian/.ssh/key-name

Uploading the Public Key to the Remote Server.

  • From the workstation terminal (CTRL + ALT + T), I use "ssh-copy-id" to upload the locally-generated public key to the remote container (where I replace "container-name" with the actual name of the container):
ssh-copy-id -i /home/brian/.ssh/container-name.pub yt@192.168.?.?

NOTE: I replace the "?" with the actual IP address for the remote server.


Logging In to the Remote Server.

  • From the terminal (CTRL + ALT + T), I login to the account of the remote server:
ssh 'yt@192.168.?.?'

NOTE: I replace the "?" with the actual IP address for the remote server.


Updating the Remote Server.

  • From the terminal, I update the remote server:
sudo apt clean && \
sudo apt update && \
sudo apt dist-upgrade -y && \
sudo apt --fix-broken install && \
sudo apt autoclean && \
sudo apt autoremove -y

Hardening the Remote Server.

  • From the terminal (CTRL + ALT + T) that is connected to the remote server, I open the "sshd_config" file:
sudo nano /etc/ssh/sshd_config
  • I add (CTRL + V) the following to the bottom of the "sshd_config" page, save (CTRL + S) the changes, and exit (CTRL + X) the Nano text editor:
PasswordAuthentication no
PermitRootLogin no
Protocol 2
  • I restart the "ssh" service:
sudo systemctl restart ssh.service

Enabling, and Setting Up, UFW on the Remote Server.

  • From the PC terminal (CTRL + ALT + T) that is connected to the remote server, I check the UFW status:
sudo ufw status
  • I enable the UFW:
sudo ufw enable
  • I install a UFW rule:
sudo ufw allow from 192.168.?.?

NOTE: I can use ip a or ip addr in my local PC terminal to find my IP address. I replace the IP address above with the actual address for the workstation, e.g. 192.168.188.41.

  • I check the status of the UFW and list the rules by number:
sudo ufw status numbered

NOTE 1: UFW will, by default, block all incoming traffic, including SSH and HTTP.

NOTE 2: I will update the UFW rules as I deploy other services to the remote server.

  • I can delete a UFW rule by number if needed:
sudo ufw delete 1
  • I can also disable UFW if needed:
sudo ufw disable

Installing, and Setting Up, Fail2Ban on the Remote Server.

  • From the terminal (CTRL + ALT + T) that is connected to the remote server, I install Fail2Ban:
sudo apt install -y fail2ban
  • I copy the jail.conf file as jail.local:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
  • I open the jail.local file in Nano:
sudo nano /etc/fail2ban/jail.local
  • I make the following changes to a few (SSH-centric) settings in the jail.local file, then I save (CTRL + S) those changes, and exit (CTRL + X) the Nano text editor:
[DEFAULT]
⋮
bantime = 1d
maxretry = 3
⋮
[sshd]
enabled = true
port = ssh,22
  • I restart Fail2Ban:
sudo systemctl restart fail2ban
  • I check the status of Fail2Ban:
sudo systemctl status fail2ban
  • I enable Fail2Ban to auto-start on boot:
sudo systemctl enable fail2ban
  • I reboot the remote server:
sudo reboot

My Use Case.

My plan is to use PiLab51 as the primary control plane, PiLab52 as the secondary control plane, and PiLab53 as a general server for hosting GitLab CE, PiHole, and other services. The NucLab systems will host ProxMox VE which, themselves, will host four containers each. These eight containers (total) will act as the worker nodes which, themselves, will host the pods. Although a pod is the smallest deployable unit that can contain one or more containers, the three PiLab SBCs, along with the eight ProxMox containers, collectively make up my local cluster.


The Results.

Transitioning from microSD cards to M.2 NVMe drives for my Pi5 SBCs significantly enhanced the storage capabilities and performance of my Raspberry Pi setup. By following the steps outlined in this post, I successfully installed Ubuntu Server 24.04 LTS on multiple M.2 NVMe drives, paving the way for more robust and efficient use of the Pi5 platform in various applications, including HA (high availability) clustering. This upgrade not only improved data handling and processing speed but also provided a more reliable and scalable solution for my projects. As I continue to explore and implement these technologies, I will adapt and customize my setup to meet my specific needs and objectives.


In Conclusion.

I learned how to enhance the storage capabilities my Raspberry Pi 5 SBCs by replacing microSD cards with M.2 NVMe drives. This post covered my prerequisites, the installation steps, and suggested a practical application where Pi5 SBCs can be used in an HA cluster. The Pi5 platform is a potentially strong and flexible, though expensive, resource for Homelab enthusiasts.

Until next time: Be safe, be kind, be awesome.


Hash Tags.

#RaspberryPi #Pi5 #SingleBoardComputer #M2Drive #UbuntuServer #ServerInstallation

#Kubernetes #HighAvailability #Homelab #StorageSolutions #OpenSource #DIYTech

#TechTutorial #TechUpgrade #TechEnthusiast

The Ops Series

Part 4 of 46

In the Ops series, I describe the server "operations" I use for app development and technology evaluations.

Up next

Local System Toolkit for Ubuntu.

Or: Installing the Apps that Meet My Needs.