When you attach a new disk to a Linux server, it arrives empty: no partition table, no filesystem and no mount point. In this tutorial you will identify the disk, create a GPT partition table and a partition with your choice of fdisk, parted or gdisk, format it with ext4, mount it permanently through /etc/fstab and, finally, grow the partition when the disk gets bigger. The commands are for Ubuntu 24.04 and work the same on Debian 12.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS or dedicated server, with a non-root user that has
sudoprivileges. - An extra, empty disk attached to the server. This guide calls it
/dev/vdb; on your system it may be/dev/sdbor/dev/nvme1n1. - A backup of any data on that disk. Writing a partition table destroys what was there.
WarningEvery command in this guide that writes to a disk acts immediately on the device you name. Double check the device name with
lsblkbefore each write, and never run these commands against the disk your system boots from.
Step 1 - Identifying the disk
List the block devices with their size, type and mount point:
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vda 253:0 0 40G 0 disk
├─vda1 253:1 0 39.9G 0 part /
├─vda14 253:14 0 4M 0 part
└─vda15 253:15 0 106M 0 part /boot/efi
vdb 253:16 0 20G 0 disk
vda holds the operating system. vdb is the new 20 GB disk: it has no partitions and nothing is mounted from it. Confirm it has no filesystem or partition table signatures:
lsblk -f /dev/vdb
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
vdb
An empty FSTYPE column means the disk is blank. If it shows ext4, xfs or a partition table, stop and make sure you have the right disk.
Device names follow the driver: vdX for virtio disks on virtual machines, sdX for SATA/SAS and some virtual disks, and nvmeXnY for NVMe drives, whose partitions add a p (for example /dev/nvme1n1p1).
Step 2 - Choosing a partition table and a tool
Use GPT for any new disk. MBR (also called DOS) is limited to 2 TiB and four primary partitions, and there is no reason to choose it for a data disk today.
All three tools can create GPT partitions. Pick one and follow the matching option in Step 3:
| Tool | Package | Best for |
|---|---|---|
fdisk | fdisk (installed by default) | Interactive work, MBR and GPT |
parted | parted | Scripts and one-line commands, resizing partitions |
gdisk / sgdisk | gdisk | GPT-only work, backing up and copying partition tables, MBR to GPT conversion |
Install parted and gdisk if you want to use them:
sudo apt update
sudo apt install parted gdisk
Step 3 - Creating the partition
Follow one of the three options below. Each creates a GPT table and a single partition that uses the whole disk, aligned to 1 MiB, which is optimal for SSDs and virtual disks.
Option A: fdisk
Start fdisk on the disk:
sudo fdisk /dev/vdb
At the Command (m for help): prompt, type g to create a GPT table, then n for a new partition and press Enter three times to accept the default number, first sector and last sector. Finally, type w to write the changes and exit:
Command (m for help): g
Created a new GPT disklabel (GUID: 6F1B0B4E-3C1A-4B8E-9C66-0E3F7A6A5C11).
Command (m for help): n
Partition number (1-128, default 1):
First sector (2048-41943006, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-41943006, default 41940991):
Created a new partition 1 of type 'Linux filesystem' and of size 20 GiB.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
Nothing is written until you type w. If you make a mistake, type q to quit without saving. To create a smaller partition, answer the last sector prompt with a size such as +10G.
Option B: parted
parted can do the same in one non-interactive command. --script stops it from asking questions, and 0%/100% let it choose aligned boundaries:
sudo parted --script /dev/vdb mklabel gpt mkpart data ext4 0% 100%
On GPT, data is the partition name and ext4 is only a type hint: parted does not create the filesystem. Check that the partition is aligned:
sudo parted /dev/vdb align-check optimal 1
1 aligned
WarningUnlike
fdisk,partedapplies every command immediately. There is no "write" step to cancel.
Option C: sgdisk (gdisk)
sgdisk is the scriptable version of gdisk. Create a new GPT table (-o) and a partition 1 that starts and ends at the defaults, which means the whole disk, with type 8300 (Linux filesystem):
sudo sgdisk -o -n 1:0:0 -t 1:8300 -c 1:data /dev/vdb
Creating new GPT entries in memory.
The operation has completed successfully.
Use sudo gdisk /dev/vdb if you prefer an interactive session. Its commands are similar to fdisk (o, n, w), and it shows GPT type codes such as 8300 (Linux filesystem), 8e00 (Linux LVM), fd00 (Linux RAID) and 8200 (Linux swap).
Verifying the partition
Whichever tool you used, confirm the kernel sees the new partition:
lsblk /dev/vdb
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vdb 253:16 0 20G 0 disk
└─vdb1 253:17 0 20G 0 part
If vdb1 does not appear, ask the kernel to reread the partition table:
sudo partprobe /dev/vdb
Step 4 - Creating an ext4 filesystem
A partition is only a reserved range of the disk. Create a filesystem on it so it can hold files. The -L option sets a label you will recognize later:
sudo mkfs.ext4 -L data /dev/vdb1
mke2fs 1.47.0 (5-Feb-2023)
Discarding device blocks: done
Creating filesystem with 5242368 4k blocks and 1310720 inodes
Filesystem UUID: 2b7c1d52-8f0e-4b1f-a6f3-3a7c9d2e0f41
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
ext4 is a safe default. If you need XFS or Btrfs, use mkfs.xfs or mkfs.btrfs instead; the guide on choosing between ext4, XFS and Btrfs explains the differences.
Step 5 - Mounting the partition permanently
Create a mount point and mount the filesystem to test it:
sudo mkdir -p /mnt/data
sudo mount /dev/vdb1 /mnt/data
df -h /mnt/data
Filesystem Size Used Avail Use% Mounted on
/dev/vdb1 20G 24K 19G 1% /mnt/data
To mount it at every boot, add it to /etc/fstab. Use the filesystem UUID rather than /dev/vdb1, because device names can change when disks are added or removed. Get the UUID:
sudo blkid /dev/vdb1
/dev/vdb1: LABEL="data" UUID="2b7c1d52-8f0e-4b1f-a6f3-3a7c9d2e0f41" BLOCK_SIZE="4096" TYPE="ext4" PARTLABEL="data" PARTUUID="a1d4c3b2-7e55-4c1e-9b0a-5d2f6e8c7b90"
Open the file:
sudo nano /etc/fstab
Add this line at the end, with your UUID:
UUID=2b7c1d52-8f0e-4b1f-a6f3-3a7c9d2e0f41 /mnt/data ext4 defaults,nofail 0 2
nofail lets the server finish booting even if this disk is missing, instead of dropping to emergency mode. The last field, 2, makes fsck check it after the root filesystem.
Check the file for errors, then remount everything from fstab to prove the entry works:
sudo findmnt --verify
sudo umount /mnt/data
sudo systemctl daemon-reload
sudo mount -a
findmnt /mnt/data
TARGET SOURCE FSTYPE OPTIONS
/mnt/data /dev/vdb1 ext4 rw,relatime
The filesystem is owned by root. To let your user write to it, change the owner of the mount point:
sudo chown your_user:your_user /mnt/data
Step 6 - Growing the partition after enlarging the disk
If the disk later grows (for example from 20 GB to 40 GB), the partition and the filesystem keep their old size until you extend them. First confirm the kernel sees the new disk size:
lsblk /dev/vdb
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vdb 253:16 0 40G 0 disk
└─vdb1 253:17 0 20G 0 part /mnt/data
On GPT disks, the backup partition table is stored at the end of the disk, so after growing it you must move it to the new end. growpart, from the cloud-guest-utils package, does that and extends the partition in one step, even while it is mounted:
sudo apt install cloud-guest-utils
sudo growpart /dev/vdb 1
CHANGED: partition=1 start=2048 old: size=41938944 end=41940991 new: size=83883999 end=83886046
Note the space between the disk and the partition number. Now grow the ext4 filesystem to fill the partition:
sudo resize2fs /dev/vdb1
df -h /mnt/data
Filesystem Size Used Avail Use% Mounted on
/dev/vdb1 40G 24K 38G 1% /mnt/data
For XFS, use sudo xfs_growfs /mnt/data instead of resize2fs. With parted you can extend the partition manually with sudo parted /dev/vdb resizepart 1 100%, and parted will offer to fix the GPT backup header first.
Troubleshooting
GPT PMBR size mismatch warning in fdisk. The disk grew but the GPT backup header is still at the old end. Move it with sudo sgdisk -e /dev/vdb, or let growpart fix it as in Step 6.
Re-reading the partition table failed: Device or resource busy. A partition on that disk is mounted or in use. Unmount it (sudo umount /mnt/data), then run sudo partprobe /dev/vdb. If something still holds it, sudo lsof /mnt/data shows which process.
umount: target is busy. A shell or process is using the directory. Leave it (cd ~) and check with sudo fuser -vm /mnt/data.
The server boots into emergency mode after editing fstab. An fstab line is wrong and does not use nofail. From the console, run sudo nano /etc/fstab, fix or comment out the line, then reboot. Always run sudo findmnt --verify and sudo mount -a after editing the file.
Conclusion
You identified a new disk, partitioned it with GPT using fdisk, parted or sgdisk, formatted it with ext4, mounted it permanently by UUID and learned how to grow it later. From here, you can use the partition as an LVM physical volume (GPT type 8e00) for flexible resizing, combine several disks with software RAID using mdadm, or compare ext4 with XFS and Btrfs before formatting your next disk.
