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 sudo privileges.
  • An extra, empty disk attached to the server. This guide calls it /dev/vdb; on your system it may be /dev/sdb or /dev/nvme1n1.
  • A backup of any data on that disk. Writing a partition table destroys what was there.

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:

ToolPackageBest for
fdiskfdisk (installed by default)Interactive work, MBR and GPT
partedpartedScripts and one-line commands, resizing partitions
gdisk / sgdiskgdiskGPT-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

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.