Founder

Ubuntu 24.04 WSL2 Architecture: Preventing VHDX Bloat, Docker Sprawl, and Filesystem Corruption

Site Owner: Michael Baggett

Role: Project Developer

Joined: May 2023

Overview

This guide builds a modern Ubuntu 24.04 LTS environment on Windows Subsystem for Linux using an architecture specifically designed to avoid the most common long-term WSL problems:

  • Massive ext4.vhdx growth
  • WSL disks that never shrink
  • Docker overlay storage explosion
  • Filesystem corruption after disks reach 100%
  • Slow exports and backups
  • Runaway Linux page cache memory usage
  • Windows PATH pollution inside Linux
  • Poor separation between ephemeral and persistent data

This architecture keeps the Linux VHDX intentionally small while moving heavy persistent storage onto native Windows storage.

What Causes WSL Bloat?

The default WSL installation model encourages users to store everything inside the Linux filesystem:

  • Git repositories
  • Docker layers
  • AI models
  • datasets
  • build artifacts
  • node_modules
  • databases
  • caches

All of this lives inside:

ext4.vhdx

Over time:

  • the VHDX grows continuously
  • deleted files are not reclaimed efficiently
  • Docker overlay2 storage becomes enormous
  • filesystem corruption risk increases dramatically when disks fill completely

Once ext4 metadata corruption occurs after a 100% full condition, WSL may report massive phantom usage that cannot be reclaimed normally.

This guide avoids that entirely.

Architecture Goals

This deployment strategy:

  • Keeps the Linux root filesystem lightweight
  • Externalizes heavy persistent data
  • Keeps Docker storage outside the VHDX
  • Makes backups/export simple
  • Reduces corruption risk
  • Keeps compaction effective
  • Provides predictable long-term performance
C:\WSL\
├── Ubuntu\
│   └── ext4.vhdx
├── docker-data\
├── repos\
├── models\
├── datasets\
├── builds\
├── cache\
└── Backups\

Requirements

  • Windows 11 Pro
  • WSL 2.6+ recommended
  • Administrative PowerShell access
  • SSD/NVMe strongly recommended

Step 1 — Verify WSL and Windows Versions

This architecture depends on modern WSL2 features that improve:

  • memory reclaim
  • VHD behavior
  • networking
  • Docker stability
  • filesystem performance
ComponentRecommended
WindowsWindows 11 23H2 or newer
WSL2.6.x or newer
WSL Kernel6.6.x or newer

Verify Versions

Open PowerShell as Administrator:

wsl --version

Example healthy output:

WSL version: 2.6.3.0
Kernel version: 6.6.87.2-1

Then verify Windows version:

systeminfo | findstr /B /C:"OS Name" /C:"OS Version"

Example:

OS Name: Microsoft Windows 11 Pro
OS Version: 10.0.26200

Why This Matters

This guide uses modern WSL capabilities including:

  • mirrored networking
  • automatic memory reclaim
  • improved VHD handling
  • modern systemd support

Older WSL versions may:

  • ignore some settings
  • have networking issues
  • leak memory more aggressively
  • exhibit worse VHD growth behavior

If your WSL version is older than 2.6.x, update WSL before continuing:

wsl --update

Then reboot Windows.

Step 2 — Configure Global WSL Settings

Create:

C:\Users\<USERNAME>\.wslconfig

Contents:

[wsl2]
memory=16GB
processors=8
swap=8GB
swapFile=C:\\WSL\\swap.vhdx
networkingMode=mirrored
dnsTunneling=true
firewall=true

[experimental]
sparseVhd=true
autoMemoryReclaim=gradual

Step 3 — Reload WSL Configuration

wsl --shutdown

Step 4 — Install Ubuntu 24.04 LTS

wsl --install Ubuntu-24.04 --no-launch

Verify:

wsl --list --verbose

Step 5 — Relocate Ubuntu Outside AppData

wsl --export Ubuntu-24.04 C:\WSL\ubuntu24.tar
wsl --unregister Ubuntu-24.04
wsl --import Ubuntu C:\WSL\Ubuntu C:\WSL\ubuntu24.tar --version 2

Step 6 — Launch Ubuntu

wsl -d Ubuntu

Step 7 — Create the Permanent Linux User

adduser <USERNAME>
usermod -aG sudo <USERNAME>

Verify:

id <USERNAME>

Step 8 — Configure /etc/wsl.conf

sudo nano /etc/wsl.conf

Contents:

[boot]
systemd=true

[user]
default=<USERNAME>

[automount]
enabled=true
root=/mnt/
options="metadata,umask=22,fmask=11"

[interop]
enabled=true
appendWindowsPath=false

[network]
generateHosts=true
generateResolvConf=true

Step 9 — Restart WSL

wsl --shutdown

Reopen Ubuntu:

wsl -d Ubuntu

Verify:

whoami
systemctl is-system-running
echo $PATH

Step 10 — Configure Linux Directory Layout

mkdir -p ~/repos
mkdir -p ~/projects
mkdir -p ~/bin

Create symlinks:

ln -s /mnt/c/WSL/repos ~/winrepos
ln -s /mnt/c/WSL/models ~/models
ln -s /mnt/c/WSL/datasets ~/datasets
ln -s /mnt/c/WSL/builds ~/builds
ln -s /mnt/c/WSL/cache ~/cache

Step 11 — Install Docker Correctly

sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) \
  signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin

Step 12 — Externalize Docker Storage

sudo nano /etc/docker/daemon.json

Contents:

{
  "data-root": "/mnt/c/WSL/docker-data",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "features": {
    "buildkit": true
  }
}

Step 13 — Enable Docker

sudo systemctl enable docker
sudo systemctl restart docker
sudo usermod -aG docker <USERNAME>

Exit WSL:

exit

Shutdown WSL:

wsl --shutdown

Reopen Ubuntu:

wsl -d Ubuntu

Verify Docker:

docker version
docker info | grep "Docker Root Dir"

Expected:

Docker Root Dir: /mnt/c/WSL/docker-data

Final Validation

df -h /
docker system df

Example expected healthy output:

Filesystem      Size  Used Avail Use% Mounted on
/dev/sdd       1007G  2.0G  954G   1% /

Operational Best Practices

DO NOT Store These Inside Linux Home

Avoid:

  • large Git repositories
  • AI models
  • Docker data
  • databases
  • build outputs
  • huge caches

inside:

/home/<user>

DO Store Outside the VHDX

Store these in:

C:\WSL\

Examples:

  • repositories
  • datasets
  • AI models
  • build artifacts
  • Docker layers
  • caches

Open repositories from:

/mnt/c/WSL/repos

NOT:

~/repos

Backup Strategy

Monthly export:

wsl --export Ubuntu C:\WSL\Backups\ubuntu-$(Get-Date -Format yyyyMMdd).tar

Periodic Maintenance

wsl --shutdown

Then compact:

Optimize-VHD -Path "C:\WSL\Ubuntu\ext4.vhdx" -Mode Full

Final Result

This architecture provides:

  • Minimal VHDX growth
  • Safer Docker operation
  • Better long-term stability
  • Easier backup/recovery
  • Better filesystem health
  • Easier storage management
  • Lower corruption risk
  • Cleaner Linux/Windows separation

Posted: