DEV Community

Cover image for WSL: Let's Create Multiple Instances with Shared Home Directory
Marco Trulla
Marco Trulla

Posted on • Edited on

WSL: Let's Create Multiple Instances with Shared Home Directory

ℹ️ The article has been re-edited, keeping its content unchanged while enhancing it where possible and making it clearer where needed.

Table of Contents

Intro

I often find myself fighting with the problem of having more than one WSL session for the same Linux distribution.

💡It is not officially possible to install two or more fresh copies of the same distro unless you rename the executable downloaded from the Microsoft Store for each session you want to install.

Of course, it is possible to export a previously installed session and import it as many times as needed, but this leads to another (in my humble opinion) problem – the duplication of your home directory for every imported session. Having more independent sessions, on the other hand, introduces the challenge of mirroring your home directory between each session, thereby necessitating a shared home directory.

To address this issue, I conducted research on the internet to find a solution that worked for me. I then documented it in a step-by-step guide (or more like a memo for myself), putting it in writing for future reference.

DISCLAIMER: The following steps require running Windows 10/11 and performing actions that demand Administrator privileges. Incorrect execution can lead to disastrous results. While these steps have proven successful on my system, there is no guarantee they will work on yours. Proceed only if you are confident in your understanding of the process, and I cannot be held responsible if any issues arise.

Prerequisites

To follow this guide, it is expected that the system has the following:

  • Windows 10/11 Education/Pro/Enterprise (Home edition is supported but may require additional steps)
  • Windows Subsystem for Linux version 2 installed
  • Sufficient disk space for sessions' and home's virtual disks
  • Administrator privileges
  • One or more Linux rootfs tarballs
  • Basic understanding of shell commands

Preparing the virtual disk for your home

⚠️ This step is required ONLY if you haven't already created your own virtual disk for the home directory.

The initial step is to create a virtual disk serving as our shared home partition across all sessions. Various methods can achieve this.

Option 1: Disk Management snap-in
It can be created via the Disk Management snap-in (diskmgmt.msc) by following these steps:
  • Select Create VHD from the Action menu.
  • Set options for VHDX and Dynamically expanding.
  • Specify the path and size for the virtual disk file.

Option 2: Windows Settings
The same result can be achieved through the Windows Settings panel by selecting Create VHD in Disks & volumes under Settings > System > Storage > Advanced storage settings.

Option 3: Diskpart

ℹ️ To perform these steps, it is necessary to run the console with Administrator privileges.

The same result can be achieved via the command line using diskpart (diskpart.exe). Once the console (cmd.exe) is opened, simply type:

diskpart.exe

DISKPART> create vdisk file="<path>" maximum=<size> type=expandable
Enter fullscreen mode Exit fullscreen mode

where <path> is the file path for the virtual disk, and <size> represents the maximum size (in KiB) to be assigned to the virtual disk.

Option 4: Hyper-V

ℹ️ Running PowerShell with Administrator privileges is necessary. Users of Windows Home edition need to complete an additional step before being able to use the Hyper-V module.

In PowerShell it is possible to use the New-VHD cmdlet from the Hyper-V module:

New-VHD -Path <path> -Dynamic -SizeBytes <size>
Enter fullscreen mode Exit fullscreen mode

where <path> is the file path to the virtual disk, and <size> represents the maximum size, specified in MiB, GiB, or TiB, to be assigned to it.

⚠️ Ensure that you have sufficient space for the virtual disk, as its minimum size will significantly increase once formatted in ext4. To estimate the required space, you can use the following formula.

Reserved Space=Partition Size×(Reserved ext4 Percentage100) \text{Reserved Space} = \text{Partition Size} \times \left(\frac{\text{Reserved ext4 Percentage}}{100}\right)\newline

As example, for a 10GiB virtual disk formatted in ext4:

10737418240×(5100)=536870912 (~512MiB) 10737418240 \times \left(\frac{5}{100}\right) = 536870912\text{ (\textasciitilde512MiB)}

Mounting the virtual disk on WSL

After creating the virtual disk, it is necessary to make it available in WSL for use by all sessions. In PowerShell type:

wsl.exe --mount <virtual_disk_path> --vhd --bare 
Enter fullscreen mode Exit fullscreen mode

This will make the virtual disk at <virtual_disk_path> available in the current WSL, ready for mounting in every session."

ℹ️ This step is required each time a new virtual disk is created and after every system restart, as there is currently no way to automount the disks when WSL is initiated.

Preparing the Linux distribution

The guide should work with any Linux distribution that offers a rootfs tarball compatible with WSL.

For the sake of simplicity, all steps will be executed in PowerShell with Administrator privileges.

Ubuntu
You can download an image from https://cloud-images.ubuntu.com/releases/ (for releases before 22.04) or https://cloud-images.ubuntu.com/wsl/ (for releases from 22.04 and later).
Invoke-WebRequest https://cloud-images.ubuntu.com/wsl/mantic/current/ubuntu-mantic-wsl-amd64-wsl.rootfs.tar.gz -OutFile ubuntu-mantic-wsl-amd64-wsl.rootfs.tar.gz
Enter fullscreen mode Exit fullscreen mode

Arch
Additional steps are required within a Linux session to prepare Arch Linux before importing. Firstly, download the bootstrap archive from the Arch repository https://archmirror.it/repos/iso/:
wget https://geo.mirror.pkgbuild.com/iso/latest/archlinux-bootstrap-x86_64.tar.gz
Enter fullscreen mode Exit fullscreen mode

or

wget https://geo.mirror.pkgbuild.com/iso/latest/archlinux-bootstrap-x86_64.tar.zstd
Enter fullscreen mode Exit fullscreen mode

After downloading, it is necessary to prepare the rootfs tarball required for the import in WSL.

sudo tar -xzf archlinux-bootstrap-x86_64.tar.gz
# or, if tar ball is compressed with zstd
sudo tar --zstd -xf archlinux-bootstrap-x86_64.tar.std

cd root.x86_64

sudo tar -czvf ArchWSL.tar.gz .

sudo cp ArchWSL.tar.gz /mnt/<path_for_tarball>
Enter fullscreen mode Exit fullscreen mode

where <path_for_tarball> represents the location on your Windows system where the tarball will be stored for future imports.


Creating a new session

To create a new Linux session in WSL, the first step is to import the chosen rootfs tarball. In PowerShell, type

wsl.exe --import <session> <session_path> <rootfs_tarball_path> --version 2
Enter fullscreen mode Exit fullscreen mode

where <session> is the name to assign to the newly created Linux session, <session_path> is the directory where the session's virtual disk will be created by WSL (the virtual disk always has the name ext4.vhdx, so it is mandatory to specify a different directory for each unique instance), and <rootfs_tarball_path> is the path to the tarball downloaded in the previous step.

Then, start the session to allow WSL to install the distribution:

wsl.exe -d <session>
Enter fullscreen mode Exit fullscreen mode

At this point, the bare minimum Linux session is ready. However, unlike the default installation procedure via wsl --install, which installs a session with Ubuntu and an already configured home directory, the session just created only has the root user. Further configuration is required to connect an user home directory to the previously created home virtual disk.

Configuring the new session

WSL sessions can be configured using the wsl.conf configuration file. This is the first step required to configure the newly created session. Open the file with your preferred editor (here, nano is used for the sake of simplicity).

nano /etc/wsl.conf
Enter fullscreen mode Exit fullscreen mode

Type in the following, save, and then exit:

[boot]
systemd=true

[user]
default=<user_name>
Enter fullscreen mode Exit fullscreen mode

where <user_name> is the default non-root login user when the session starts.

💡Further information about the configuration parameters available for the wsl.conf file can be found in the documentation on the Microsoft website.

Now, create the user and add it to the sudoers group.

Ubuntu
USERNAME=<user_name> adduser $USERNAME; passwd $USERNAME; adduser $USERNAME sudo; mkdir /home/$USERNAME; chown $USERNAME: /home/$USERNAME
Enter fullscreen mode Exit fullscreen mode

Arch
USERNAME=<user_name> useradd $USERNAME; passwd $USERNAME; mkdir /home/$USERNAME; chown $USERNAME: /home/$USERNAME
Enter fullscreen mode Exit fullscreen mode

In Arch, you can create a file in /etc/sudoers.d/ with the following data:

<user_name> ALL=(ALL:ALL) ALL
Enter fullscreen mode Exit fullscreen mode

Since Arch does not come configured as Ubuntu does, it is necessary to initialize and update Pacman:

curl -s "https://gitlab.archlinux.org/pacman/pacman-contrib/-/raw/master/src/rankmirrors.sh.in" > rankmirrors.sh

chmod +x rankmirrors.sh

COUNTRY=US curl -s "https://www.archlinux.org/mirrorlist/?country=${COUNTRY}&protocol=https&ip_version=4" | cut -b 2- | ./rankmirrors.sh -n 10 - > /etc/pacman.d/mirrorlist

pacman -Syu
Enter fullscreen mode Exit fullscreen mode

And setup the locale:

echo "en_US.UTF-8 UTF-8" > /etc/locale.gen

locale-gen
Enter fullscreen mode Exit fullscreen mode

Initializing the home virtual disk

⚠️ These steps are required ONLY if the virtual disk has not yet been initialized and formatted. DO NOT PERFORM THESE STEPS ON AN EXISTING VIRTUAL DISK, OR YOU WILL LOSE ALL THE DATA ON IT.

The first thing to do is to search for the device mounted in WSL:

lsblk

NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT  
...  
...  
sdc    8:48   0 10G   0 disk  
...
Enter fullscreen mode Exit fullscreen mode

In the example above, the device is sdc with a size of 10G. You will need to identify the device for the virtual disk you prepared as your home.

Once found, it must be initialized by creating the partition table using the parted command. You can install it on Ubuntu with apt install parted, or on Arch with pacman -S parted.

parted /dev/sdc mklabel msdos
parted -a optimal /dev/sdc mkpart primary ext4 0% 100%
Enter fullscreen mode Exit fullscreen mode

Here, replace /dev/sdc with the specific device you previously found.

If everything went OK , a new partition will be shown under the device you specified:

lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT /dev/sdc
NAME FSTYPE SIZE MOUNTPOINT  
sdc          10G  
└─sdc1       10G
Enter fullscreen mode Exit fullscreen mode

It is not done yet. The new partition still needs to be formatted:

mkfs.ext4 /dev/sdc1

mke2fs 1.47.0 (5-Feb-2023)
Discarding device blocks: done
Creating filesystem with 2621184 4k blocks and 655360 inodes
Filesystem UUID: c91c874f-28fb-4d81-8eea-004fee865db0
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
Enter fullscreen mode Exit fullscreen mode

And labeled (this is not mandatory, but it can be useful later as a replacement for the UUID value):

e2label /dev/sdc1 wsl-home
Enter fullscreen mode Exit fullscreen mode

Mounting the virtual disk to the home directory

This step is no different from the usual procedure used to mount external devices in your Linux filesystem.

Once found the device:

blkid

...
/dev/sdc1: LABEL="wsl-home" UUID="e9999b9b-5a8e-41e1-9881-a2f766838798" BLOCK_SIZE="4096" TYPE="ext4" ....  
...
Enter fullscreen mode Exit fullscreen mode

You can use its LABEL or UUID value for the home mount point. Open the /etc/fstab file and add:

UUID=<device_UUID> /home/<user_name> ext4 defaults 0 2
Enter fullscreen mode Exit fullscreen mode

Alternatively (if you are sure no other devices with the same label are mounted in WSL):

LABEL=<device_label> /home/<user_name> ext4 defaults 0 2
Enter fullscreen mode Exit fullscreen mode

Ready, Set, Go 🚀

If you've reached this point without any problems, you're almost done!

The last thing to do is to log out from the current session:

exit
Enter fullscreen mode Exit fullscreen mode

Restart it:

wsl.exe -t <session>
wsl.exe -d <session>
Enter fullscreen mode Exit fullscreen mode

And configure it according to your needs.

Troubleshooting

No Hyper-V installed on the system
To use the New-VHD cmdlet in PowerShell, the Hyper-V service must be enabled. This feature is supported only with Windows 10/11 Education, Pro, or Enterprise editions:
  • Through Hyper-V and sub-options in Windows Features from the Control Panel.
  • Through PowerShell (with Administrator privileges) using the command: Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All.
  • Through the command line (with Administrator privileges) using the command: DISM /Online /Enable-Feature /All /FeatureName:Microsoft-Hyper-V.

However, if you are using Windows 10/11 Home edition, it is possible to modify the system to support Hyper-V through a workaround.

⚠️ This is an unsupported method to enable Windows 10/11 Home edition to run the Hyper-V service. As mentioned, it's not officially supported by Microsoft, there's no guarantee it will work on your machine, it could lead to unexpected issues, and it may potentially violate the terms of the software's license agreement. Use it at your own risk.

Create a batch file that will be executed as Administrator, and it will install and enable the service on the machine. Open your preferred text editor and type:

pushd "%~dp0"  

dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt

for /f %%i in ('findstr /i . hyper-v.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"  

del hyper-v.txt  

dism /online /enable-feature /featurename:Microsoft-Hyper-V -All /LimitAccess /ALL  

pause
Enter fullscreen mode Exit fullscreen mode

Save it (e.g., Enable-Hyper_V.bat), and once executed, the service should be available on your machine.


Missing device on system reboot
As far as I know, there is currently no officially supported way to have your (virtual) external drives mounted in WSL when the operating system starts.

However, with a bit of hacking, it is possible to achieve this result.

Option 1: Task Scheduler or Startup Folder

Task Scheduler:

  • run (WIN+R) the snap-in taskschd.msc
  • select Create Task...
  • General tab: type the task name in Name: "WSL Home Mount" for example
  • General tab: add a description if you want
  • General tab: select Run only when user is logged on
  • General tab: select Windows 10 for Configure for
  • Triggers tab: click New..., create On Access trigger, and set it for your user
  • Actions tab: click New..., create Start Program, set C:\Windows\System32\wsl.exe for Program or Script, and --mount <virtual_disk_path> --vhd --bare for Arguments
  • Conditions tab: deselect everything
  • Settings tab: activate the first 5 checkboxes, and set to Don't start a new instance if the task is already running
  • Save and reboot.

Startup Folder:

  • open the folder: WIN+R, shell:startup
  • create a batch file and name it as you want (e.g. wsl_home_mount.bat)
  • type: @echo off; C:\Windows\System32\wsl.exe --mount <virtual_disk_path> --vhd --bare
  • Save and reboot

By doing so, every time Windows will restart, the specified virtual disk will be mounted into WSL and made ready for all the Linux sessions.

Option 2: Windows Terminal settings

Replace the default startup command line for the specific Linux session in the Windows Terminal

pwsh.exe -Command "wsl.exe -d <session> --mount <virtual_disk_path> --vhd --bare  --cd ~ | out-null; wsl.exe -d <session> --cd ~"
Enter fullscreen mode Exit fullscreen mode

With this hack, WSL will attempt to mount the virtual disk and change to the home (~) directory every time the session starts, if not already mounted.

The (minor) issue with this workaround is that the Windows Terminal won't recognize the started process as a Linux session but rather as a PowerShell process running a script. For this reason, Option 1 is the preferred choice to solve the problem.


VSCode and other Windows executables do not start
This problem may arise with certain Linux distributions, and it is connected to the fact that WSL does not correctly configure the Linux Kernel Support for Binary Formats to work with the WSL interoperability.

To solve the issue, just type:

sudo sh -c 'echo :WSLInterop:M::MZ::/init:PF > /usr/lib/binfmt.d/WSLInterop.conf'
sudo systemctl restart systemd-binfmt
Enter fullscreen mode Exit fullscreen mode

Home directory permissions and race conditions
As the home directory is shared between different Linux sessions, it is advisable for each session to use the same username to prevent conflicts and permission issues. (You may still need to run a chown -R $(whoami): /home/$(whoami) if any issues arise when switching from one session to another.)

Given that all sessions share the same home directory, it is not recommended to work with different sessions simultaneously to prevent race conditions and compromise the data integrity on the mounted virtual disk for the home directory.


References

I hope this guide has been helpful in resolving the problem I was stuck in for a while. I will try to keep it updated with new useful information.

That's all, folks!

Top comments (0)