VPS Disk Management: Expand Storage, Use LVM, Clean Up Space, and Monitor Disk Health

VPS Disk Management: Expand Storage, Use LVM, Clean Up Space, and Monitor Disk Health

A VPS running out of disk space causes service outages — databases stop writing, Docker containers crash, Nginx can’t write access logs, and applications fail unpredictably. This guide covers proactive disk management: finding what’s consuming space, expanding storage without downtime, setting up LVM for flexible volume management, and configuring alerts before disk fills up.

Step 1: Audit Current Disk Usage

<code"># Disk usage overview
df -hT   # Human-readable, with filesystem type

# Find space hogs in a directory
du -sh /* 2>/dev/null | sort -rh | head -15
du -sh /var/* 2>/dev/null | sort -rh | head -10

# Find large files specifically (over 100 MB)
find / -type f -size +100M -not -path "/proc/*" -not -path "/sys/*" \
    2>/dev/null | sort -k 5 -rn | head -20

# Docker-specific space usage
docker system df   # Shows images, containers, volumes, build cache

# Find log files consuming space
find /var/log -name "*.log" -size +50M | xargs ls -lh

# MySQL/PostgreSQL data directory sizes
du -sh /var/lib/mysql/ /var/lib/postgresql/ 2>/dev/null

Step 2: Clean Up Common Space Hogs

<code"># ── APT package cache ───────────────────────────────
sudo apt autoremove -y              # Remove unused dependencies
sudo apt clean                      # Remove cached .deb packages
sudo apt autoclean                  # Remove outdated cached packages

# ── Docker cleanup ──────────────────────────────────
docker system prune -f              # Remove stopped containers, dangling images
docker image prune -af              # Remove ALL unused images (aggressive)
docker volume prune -f              # Remove unused volumes (careful!)
docker builder prune -f             # Remove build cache

# ── Log compression and cleanup ─────────────────────
sudo journalctl --vacuum-size=500M  # Keep only last 500 MB of systemd journal
sudo journalctl --vacuum-time=30d   # Or keep only last 30 days

# Compress old logs
sudo find /var/log -name "*.log" -mtime +7 | \
    xargs -I{} gzip -9 {} 2>/dev/null

# ── Old kernel versions ─────────────────────────────
# List installed kernels
dpkg -l linux-image-* | grep -E '^ii'

# Remove old kernels (keeps current + one previous):
sudo apt autoremove --purge -y

# ── Temporary files ──────────────────────────────────
sudo rm -rf /tmp/* /var/tmp/*
sudo find /home -name ".cache" -type d | xargs du -sh 2>/dev/null

# ── PostgreSQL VACUUM ──────────────────────────────
sudo -u postgres psql -c "VACUUM FULL;" database_name   # Reclaim dead tuples space

Step 3: Expand VPS Disk (Add New Volume)

<code"># After adding a disk via VPS provider dashboard:
# 1. Verify new disk appears
lsblk
# Should show new disk, e.g., /dev/sdb

# 2. Partition the new disk
sudo fdisk /dev/sdb
# Commands: n (new partition) → p (primary) → Enter × 3 → w (write)

# Or use sgdisk for GPT:
sudo sgdisk -n 0:0:0 -t 0:8300 /dev/sdb

# 3. Format the partition
sudo mkfs.ext4 /dev/sdb1

# 4. Get the UUID for fstab
sudo blkid /dev/sdb1

# 5. Create mount point and mount
sudo mkdir -p /mnt/data
echo "UUID=YOUR-UUID /mnt/data ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab
sudo mount -a

# Verify
df -h /mnt/data

Step 4: Extend Root Partition (Cloud Volume Resize)

<code"># After resizing the root volume in your VPS dashboard:
lsblk   # Should show larger disk but same partition size

# For LVM-based systems (common on Ubuntu cloud images):
sudo pvresize /dev/sda   # Resize physical volume to use new space
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv   # Extend logical volume
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv   # Resize filesystem

# For non-LVM (direct partition):
sudo growpart /dev/sda 1    # Extend partition 1 to fill disk
sudo resize2fs /dev/sda1    # Resize filesystem

# Verify
df -h /

Step 5: Set Up LVM for Flexible Storage

<code"># LVM lets you combine multiple disks and resize volumes without unmounting
# Good for setups where you expect to add disks over time

sudo apt install -y lvm2

# Create Physical Volume on a disk
sudo pvcreate /dev/sdb

# Create Volume Group named "data-vg"
sudo vgcreate data-vg /dev/sdb

# Create Logical Volumes
sudo lvcreate -L 50G -n app-lv data-vg      # 50 GB for app data
sudo lvcreate -L 100G -n db-lv data-vg      # 100 GB for database
sudo lvcreate -l 100%FREE -n media-lv data-vg  # Rest for media

# Format logical volumes
sudo mkfs.ext4 /dev/data-vg/app-lv
sudo mkfs.ext4 /dev/data-vg/db-lv
sudo mkfs.ext4 /dev/data-vg/media-lv

# Mount them
sudo mkdir -p /opt /var/lib/mysql /srv/media
echo "/dev/data-vg/app-lv /opt ext4 defaults 0 2" | sudo tee -a /etc/fstab
echo "/dev/data-vg/db-lv /var/lib/mysql ext4 defaults 0 2" | sudo tee -a /etc/fstab
echo "/dev/data-vg/media-lv /srv/media ext4 defaults 0 2" | sudo tee -a /etc/fstab
sudo mount -a

# Later: extend a volume when needed (no unmounting required for ext4):
sudo pvcreate /dev/sdc   # Add new disk
sudo vgextend data-vg /dev/sdc   # Add to volume group
sudo lvextend -l +100%FREE /dev/data-vg/db-lv   # Extend DB volume
sudo resize2fs /dev/data-vg/db-lv   # Resize filesystem online

Step 6: Monitor Disk Usage and I/O

<code"># Real-time disk I/O
iostat -x 1   # Extended I/O stats every second
iotop          # Top-like view of disk I/O by process

# Disk usage history (ncdu — ncurses disk usage)
sudo apt install -y ncdu iotop
ncdu /        # Interactive disk usage browser

# Check filesystem health
sudo tune2fs -l /dev/sda1 | grep "Mount count\|Last checked"
sudo fsck -n /dev/sdb1   # Check without fixing (non-destructive)

Step 7: Disk Usage Alerts

<code">sudo nano /usr/local/bin/disk-alert.sh
<code">#!/bin/bash
BOT_TOKEN="YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID="YOUR_TELEGRAM_CHAT_ID"
THRESHOLD=80   # Alert when disk is over 80% full

df -h --output=pcent,target | grep -v Filesystem | while read usage mount; do
    # Remove the % sign
    pct="${usage%\%}"
    if [ "$pct" -ge "$THRESHOLD" ]; then
        MESSAGE="⚠️ *Disk Alert*
Host: \`$(hostname)\`
Mount: \`$mount\`
Usage: ${usage} (threshold: ${THRESHOLD}%)
Time: $(date)"

        curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
            -d "chat_id=${CHAT_ID}" \
            -d "parse_mode=Markdown" \
            -d "text=${MESSAGE}" > /dev/null
    fi
done
<code">chmod +x /usr/local/bin/disk-alert.sh

# Schedule every hour
echo "0 * * * * root /usr/local/bin/disk-alert.sh" | \
    sudo tee /etc/cron.d/disk-alert

# Test immediately
sudo /usr/local/bin/disk-alert.sh

Log Rotation Configuration

<code"># Ensure logrotate is configured for your applications
sudo nano /etc/logrotate.d/myapp
<code">/var/log/myapp/*.log {
    daily
    rotate 14         # Keep 14 days of logs
    compress          # Gzip old logs
    delaycompress     # Don't compress yesterday's log (may still be in use)
    missingok         # Don't error if log file doesn't exist
    notifempty        # Don't rotate empty files
    create 640 www-data www-data   # Permissions on new log file
    postrotate
        systemctl reload myapp 2>/dev/null || true
    endscript
}

Getting Started

Disk monitoring should be automated on every VPS from day one. The hourly disk alert script in this guide runs on any Ubuntu VPS at VPS.DO and sends Telegram alerts before storage is exhausted. For growing applications, set up LVM when provisioning so future storage expansion (adding a volume) requires no downtime or partition manipulation.

Conclusion

Proactive disk management prevents the most common cause of unplanned VPS outages — full storage. Automate cleanup of Docker images, APT cache, and old logs; monitor usage with hourly Telegram alerts; and choose LVM for new deployments to make future storage expansion seamless. When a disk does fill up, du -sh /* | sort -rh | head -15 quickly identifies the culprit, and Docker cleanup alone often reclaims 5–20 GB on active deployments.

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!