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
sudoprivileges. 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/sdband/dev/sdc; the operating system is on/dev/sda. - A backup of anything on those two disks. Creating the array erases them.
WarningRAID protects against a disk failing, not against deleting files, ransomware or a corrupted filesystem. Keep separate backups.
Choosing a RAID level
| Level | Minimum disks | Usable capacity | Disks that can fail | Typical use |
|---|---|---|---|---|
| RAID 0 | 2 | All disks | None | Scratch space where speed matters and data is disposable |
| RAID 1 | 2 | One disk | All but one | Boot and data disks on small servers |
| RAID 5 | 3 | All but one | 1 | Read-heavy storage with 3 or 4 disks |
| RAID 6 | 4 | All but two | 2 | Large arrays of big disks, where rebuilds take many hours |
| RAID 10 | 4 | Half | 1 per mirror pair | Databases 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.
