mdadm is the standard Linux tool for software RAID: it combines several disks into one block device (/dev/md0) that survives the failure of a disk or runs faster than a single one, without a hardware RAID controller. In this tutorial you will build a RAID 1 (mirror) array from two data disks on Ubuntu 24.04, format and mount it, make it assemble at boot, set up monitoring and practice replacing a failed disk. The last section shows the commands for RAID 5, 6 and 10.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS with a non-root user that has sudo privileges. Software RAID is most useful on dedicated servers, such as a CubePath bare metal server, with several physical disks.
  • Two empty disks of the same size for the array. This guide uses /dev/sdb and /dev/sdc; the operating system is on /dev/sda.
  • A backup of anything on those two disks. Creating the array erases them.

Choosing a RAID level

LevelMinimum disksUsable capacityDisks that can failTypical use
RAID 02All disksNoneScratch space where speed matters and data is disposable
RAID 12One diskAll but oneBoot and data disks on small servers
RAID 53All but one1Read-heavy storage with 3 or 4 disks
RAID 64All but two2Large arrays of big disks, where rebuilds take many hours
RAID 104Half1 per mirror pairDatabases and virtual machines: speed and redundancy

With two disks, RAID 1 is the only level that gives redundancy, so it is what this guide builds.

Step 1 - Installing mdadm and identifying the disks

mdadm is usually preinstalled on Ubuntu Server. Make sure it is present:

sudo apt update
sudo apt install mdadm

List the disks with their size, type and mount point:

lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS
NAME     SIZE TYPE FSTYPE MOUNTPOINTS
sda      480G disk
├─sda1     1G part vfat   /boot/efi
└─sda2   479G part ext4   /
sdb      1.8T disk
sdc      1.8T disk

sdb and sdc have no partitions and no filesystem. If lsblk -f shows an old linux_raid_member or filesystem signature on them, wipe it first with sudo wipefs -a /dev/sdb /dev/sdc, after making sure these are the right disks.

Step 2 - Partitioning the disks

You can build an array from whole disks, but a partition of type "Linux RAID" makes the disk's purpose obvious to other tools and to anyone who looks at it later. Create a GPT table with one partition that fills each disk, using sgdisk from the gdisk package:

sudo apt install gdisk
sudo sgdisk -o -n 1:0:0 -t 1:FD00 /dev/sdb
sudo sgdisk -o -n 1:0:0 -t 1:FD00 /dev/sdc

-o creates a new GPT table, -n 1:0:0 creates partition 1 from the first to the last usable sector, and FD00 is the Linux RAID type code. Check the result:

lsblk /dev/sdb /dev/sdc
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sdb      8:16   0  1.8T  0 disk
└─sdb1   8:17   0  1.8T  0 part
sdc      8:32   0  1.8T  0 disk
└─sdc1   8:33   0  1.8T  0 part

Step 3 - Creating the RAID 1 array

Create /dev/md0 as a RAID 1 array with two members:

sudo mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdb1 /dev/sdc1

mdadm warns that this metadata format is not ideal for a boot device. That does not matter for a data array. Answer y:

mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90
Continue creating array? y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.

The array is usable right away, while the kernel copies one disk onto the other in the background. Follow the initial sync in /proc/mdstat:

cat /proc/mdstat
Personalities : [raid1] [linear] [multipath] [raid0] [raid6] [raid5] [raid4] [raid10]
md0 : active raid1 sdc1[1] sdb1[0]
      1953381376 blocks super 1.2 [2/2] [UU]
      [>....................]  resync =  2.4% (46880768/1953381376) finish=158.2min speed=200862K/sec
      bitmap: 15/15 pages [60KB], 65536KB chunk

unused devices: <none>

[2/2] [UU] means both members are up. An underscore, as in [U_], marks a missing or failed disk. The bitmap line shows the write-intent bitmap that mdadm adds automatically on large arrays: after an unclean shutdown only the regions that changed are resynced, not the whole disk.

Use watch -n 5 cat /proc/mdstat to follow the progress. You can continue with the next steps while it runs.

Step 4 - Creating a filesystem and mounting it

Format the array with ext4 and create a mount point:

sudo mkfs.ext4 -L raid1 /dev/md0
sudo mkdir -p /mnt/raid1

Get the filesystem UUID, which is what you will use in /etc/fstab:

sudo blkid /dev/md0
/dev/md0: LABEL="raid1" UUID="5c0e9a7d-2f41-4d6b-9e1a-8b3c7f2d4a60" BLOCK_SIZE="4096" TYPE="ext4"

Open the file:

sudo nano /etc/fstab

Add this line at the end, with your UUID:

UUID=5c0e9a7d-2f41-4d6b-9e1a-8b3c7f2d4a60  /mnt/raid1  ext4  defaults,nofail  0  2

nofail lets the server boot even if the array cannot be assembled, instead of stopping in emergency mode. Validate the file and mount it:

sudo findmnt --verify
sudo systemctl daemon-reload
sudo mount -a
df -h /mnt/raid1
Filesystem      Size  Used Avail Use% Mounted on
/dev/md0        1.8T   28K  1.7T   1% /mnt/raid1

Step 5 - Making the array assemble at boot

Record the array in /etc/mdadm/mdadm.conf so it is assembled with the same name at every boot. Without this, it often comes back as /dev/md127:

sudo mdadm --detail --scan | sudo tee -a /etc/mdadm/mdadm.conf
ARRAY /dev/md0 metadata=1.2 UUID=3f8e2a1b:7c4d9e05:a2b6f1c3:8d0e4f72

Ubuntu assembles arrays early in the boot process from the initramfs, so rebuild it to include the new configuration:

sudo update-initramfs -u

Reboot, then confirm the array is md0, active and mounted:

cat /proc/mdstat
findmnt /mnt/raid1

Step 6 - Monitoring the array

Check the full state of an array at any time:

sudo mdadm --detail /dev/md0
/dev/md0:
           Version : 1.2
        Raid Level : raid1
        Array Size : 1953381376 (1862.89 GiB 2000.26 GB)
      Raid Devices : 2
     Total Devices : 2
             State : clean
    Active Devices : 2
   Working Devices : 2
    Failed Devices : 0
     Spare Devices : 0

    Number   Major   Minor   RaidDevice State
       0       8       17        0      active sync   /dev/sdb1
       1       8       33        1      active sync   /dev/sdc1

State : clean and Failed Devices : 0 are what you want to see.

mdadm also runs as a monitoring daemon and sends an email when a disk fails. It uses the MAILADDR line in /etc/mdadm/mdadm.conf, which is root by default. Open the file:

sudo nano /etc/mdadm/mdadm.conf

Set the address that should receive alerts:

MAILADDR admin@your_domain

Mail delivery requires a working mail transfer agent on the server (for example Postfix configured to relay through your mail provider). Send a test alert for every array to check the whole chain:

sudo mdadm --monitor --scan --oneshot --test

The Ubuntu mdadm package also schedules a periodic consistency check of all arrays. To run one by hand, which reads both disks and compares them:

echo check | sudo tee /sys/block/md0/md/sync_action

When it finishes (cat /proc/mdstat no longer shows check), the number of mismatched blocks should be 0:

cat /sys/block/md0/md/mismatch_cnt
0

Combine this with SMART monitoring (sudo apt install smartmontools, then sudo smartctl -H /dev/sdb) to catch disks that are about to fail.

Step 7 - Replacing a failed disk

Practice the replacement procedure now, while the data is not critical, so you know it works. First, mark sdc1 as failed to simulate a broken disk:

sudo mdadm --manage /dev/md0 --fail /dev/sdc1
cat /proc/mdstat
md0 : active raid1 sdc1[1](F) sdb1[0]
      1953381376 blocks super 1.2 [2/1] [U_]

The array keeps working on one disk ([U_]), and the mount point stays available. Remove the failed member from the array:

sudo mdadm --manage /dev/md0 --remove /dev/sdc1
mdadm: hot removed /dev/sdc1 from /dev/md0

With a real failure, you would now replace the physical disk. Before pulling a disk, note its serial number with sudo smartctl -i /dev/sdc so you remove the right one. When the new disk is installed, copy the partition table from the healthy disk to it, then give it new unique GUIDs. The first command copies from sdb to sdc, so double check the order:

sudo sgdisk /dev/sdb -R /dev/sdc
sudo sgdisk -G /dev/sdc

Add the new partition to the array:

sudo mdadm --manage /dev/md0 --add /dev/sdc1

The array starts rebuilding onto the new disk:

cat /proc/mdstat
md0 : active raid1 sdc1[2] sdb1[0]
      1953381376 blocks super 1.2 [2/1] [U_]
      [=>...................]  recovery =  6.3% (123057152/1953381376) finish=151.9min speed=200774K/sec

When the recovery reaches 100%, the status returns to [2/2] [UU]. In this simulation, the rebuild of the same disk finishes much faster thanks to the write-intent bitmap.

Rebuild speed is limited so it does not starve normal I/O. If the server is idle and you want it to finish sooner, raise the minimum speed (in KB/s) temporarily:

sudo sysctl -w dev.raid.speed_limit_min=100000

Other RAID levels

The rest of the workflow (filesystem, fstab, mdadm.conf, update-initramfs) is identical for every level. Only the create command changes. Partition each disk as in Step 2 first.

RAID 5 with three disks:

sudo mdadm --create /dev/md0 --level=5 --raid-devices=3 /dev/sdb1 /dev/sdc1 /dev/sdd1

RAID 6 with four disks:

sudo mdadm --create /dev/md0 --level=6 --raid-devices=4 /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1

RAID 10 with four disks:

sudo mdadm --create /dev/md0 --level=10 --raid-devices=4 /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1

To add a hot spare that takes over automatically when a member fails, add an extra partition to an array that is already complete:

sudo mdadm --manage /dev/md0 --add /dev/sdf1

It appears with an (S) next to it in /proc/mdstat.

Removing an array

If you need to dismantle the array, unmount it and remove its /etc/fstab line first, then stop it and erase the RAID metadata from its members:

sudo umount /mnt/raid1
sudo mdadm --stop /dev/md0
sudo mdadm --zero-superblock /dev/sdb1 /dev/sdc1

Delete the ARRAY /dev/md0 line from /etc/mdadm/mdadm.conf and run sudo update-initramfs -u again.

Troubleshooting

The array appears as /dev/md127 after a reboot. It is not listed in /etc/mdadm/mdadm.conf or the initramfs was not updated. Repeat Step 5. Because fstab uses the filesystem UUID, the mount keeps working even with the wrong name.

The array is inactive in /proc/mdstat. It was only partly assembled at boot. Stop it and assemble it again from the configuration:

sudo mdadm --stop /dev/md127
sudo mdadm --assemble --scan

mdadm: Cannot open /dev/sdX1: Device or resource busy when creating the array. The partition is mounted or already part of an array that the kernel auto-assembled from old metadata. Check cat /proc/mdstat, stop that array, and wipe the old signatures with sudo wipefs -a on the partition.

A disk is marked faulty but SMART shows no errors. A cable or controller glitch can cause this. Remove it and add it back with --remove and --add as in Step 7, then watch sudo smartctl -a and the kernel log (sudo journalctl -k) closely. If it fails again, replace it.

Conclusion

You built a RAID 1 array with mdadm, mounted it by UUID, made it assemble at boot, set up alerts and consistency checks, and rehearsed replacing a failed disk. As next steps, put LVM on top of /dev/md0 for flexible volumes, schedule SMART self-tests with smartd, and set up off-server backups, since RAID keeps the server running but does not protect your data from deletion or corruption.