Build a Custom Linux Distribution for WSL
This guide will walk through the steps to create and distribute a WSL distribution, which is a .wsl
file.
WSL distributions have two parts:
- A root filesystem (distributed as a tar file)
- A manifest entry (which contains the distribution metadata)
This guide only applies to WSL release 2.4.4 and higher.
Note
See this repository for the previous appx based distribution packaging instructions.
What are WSL root filesystem tar files?
WSL distributions are defined by a tar file with a .wsl
file extension on Windows.
A TAR file (short for Tape Archive) is a type of archive file used to store multiple files together in a single file for easier distribution or backup. The TAR file contains the root file system of a Linux distribution (all the distribution files), as well as the WSL configuration files. WSL configuration files tell the WIndows operating system how to install and launch the distribution.
Once you have a Linux system that you'd like to make into a WSL distribution, follow the steps below to get started.
Create WSL configuration files
There are two configuration files that the distribution should include:
/etc/wsl-distribution.conf
: A file created by the distribution maintainer responsible for controlling how the Linux distribution should be configured when first launched with WSL./etc/wsl.conf
: A file containing global system settings that are specific to the user and control how the distribution is launched. Learn more about WSL configuration files..
Add the WSL distribution configuration file
The distribution configuration file, /etc/wsl-distribution.conf
, defines how the Linux distribution should be configured when first launched by the user. This file can be used to interactively create a user account, show a license agreement, etc.
Here is a sample /etc/wsl-distribution.conf
file:
# /etc/wsl-distribution.conf
[oobe]
command = /etc/oobe.sh
defaultUid = 1000
defaultName = my-distro
[shortcut]
icon = /usr/lib/wsl/my-icon.ico
[windowsterminal]
ProfileTemplate = /usr/lib/wsl/terminal-profile.json
WSL distribution file configuration options:
key | value | default | notes |
---|---|---|---|
oobe.command |
string | <none> |
OOBE stands for out of box experience. This command runs the first time the user opens an interactive shell in the distribution. If that command returns non zero, it is considered unsuccessful, and the user won't be able to open a shell. |
oobe.defaultUid |
integer | <none> |
The default UID that the distribution starts with. This is useful when the oobe.command script creates a new user. |
oobe.defaultName |
string | <none> |
The default name that the distribution is registered under. This default name can be replaced with the command: wsl.exe --install <distro> --name <name> |
shortcut.icon |
string | The default WSL icon | The icon in the start menu shortcut for the distribution. Must be in .ico format with a maximum size of 10MB |
windowsterminal.profileTemplate |
string | Path to a terminal template file | The JSON template to generate a Windows Terminal profile for this distribution. |
You need to create an out of box experience (OOBE) first run experience for the distribution. Below is a sample bash script that you can use. This script assumes that oobe.defaultUid
is set to 1000
:
#!/bin/bash
set -ue
DEFAULT_GROUPS='adm,cdrom,sudo,dip,plugdev'
DEFAULT_UID='1000'
echo 'Please create a default UNIX user account. The username does not need to match your Windows username.'
echo 'For more information visit: https://aka.ms/wslusers'
if getent passwd "$DEFAULT_UID" > /dev/null ; then
echo 'User account already exists, skipping creation'
exit 0
fi
while true; do
# Prompt from the username
read -p 'Enter new UNIX username: ' username
# Create the user
if /usr/sbin/adduser --uid "$DEFAULT_UID" --quiet --gecos '' "$username"; then
if /usr/sbin/usermod "$username" -aG "$DEFAULT_GROUPS"; then
break
else
/usr/sbin/deluser "$username"
fi
fi
done
Generate a Windows Terminal profile
WSL automatically generates a Windows Terminal profile when a distribution is installed. Distribution maintainers can customize the generated profile generated by setting windowsterminal.profileTemplate
in the WSL configuration file, /etc/wsl-distribution.conf
.
The json file follows the terminal profile json format. Here’s an example profile:
{
"profiles": [
{
"antialiasingMode": "aliased",
"fontWeight": "bold",
"colorScheme": "Postmodern Tango Light"
}
],
"schemes": [
{
"name": "Postmodern Tango Light",
"black": "#0C0C0C",
"red": "#C50F1F",
"green": "#13A10E",
"yellow": "#C19C00",
"blue": "#0037DA",
"purple": "#881798",
"cyan": "#3A96DD",
"white": "#CCCCCC",
"brightBlack": "#767676",
"brightRed": "#E74856",
"brightGreen": "#16C60C",
"brightYellow": "#F9F1A5",
"brightBlue": "#3B78FF",
"brightPurple": "#B4009E",
"brightCyan": "#61D6D6",
"brightWhite": "#F2F2F2"
}
]
}
This file doesn’t need to specify the profile name
, or commandLine
. Those are automatically added by WSL when generating the terminal profile.
Add a WSL configuration for local settings on a per-distribution basis
In the context of a distribution root filesystem, we recommend that you configure systemd settings, including whether systemd starts by default, in the /etc/wsl.conf
local settings on a per-distribution basis. See the example below.
# /etc/wsl.conf
[boot]
systemd=true|false
The distribution author determines whether systemd is enabled by default by setting the boot.systemd
value to true
(enabled) or false
(not enabled).
See the Systemd recommendations if you chose to enable systemd by default.
See Advanced settings configuration in WSL for all supported settings in /etc/wsl.conf
.
Create the tar file
Once the distribution and configuration files are in place, the root filesystem can be captured in the tar file.
The recommended way of creating the tar file:
$ cd /path/to/rootfs
$ tar --numeric-owner --absolute-names -c * | gzip --best > ../install.tar.gz
The root of the tar should be the root of the filesystem (not a directory containing the root filesystem).
The recommended compression format is gzip. Other compression formats run the risk of breaking compatibility with older WSL versions.
See the Configuration file recommendations for a list of files that should and shouldn't be included in the configuration.
To obtain a tar file of an existing Linux distribution, find guidance on how to export a docker container in Import any Linux distribution to use with WSL.
Once the tar file archive is ready, see Test the distribution locally to try it out locally.
Create a .wsl file extension
The final step, once you have create a tar file to represent your custom Linux distribution, is to change the .tar
file extension to a .wsl
file extension by renaming it. Renaming this file extension will mark it as a WSL distribution. Once the tar has be renamed from .tar
to .wsl
, the file will install correctly on Windows when opened (double-clicked) in File Explorer. A oobe.defaultName
entry is required in the /etc/wsl-distribution.conf
file for this double-click experience to function properly.
Distribute your WSL distribution
WSL users can view available distributions by running wsl --list --online
and can install them directly with wsl --install <distroName>
(replacing <distroName>
with the actual name of the Linux distribution. This process is controlled by a distribution manifest file. You can add this manifest file to your customer Linux distribution for it to be included in the wsl --install
command options.
The custom Linux distribution tar that you’ve created and renamed with a .wsl
file extension can be distributed however you please. Once downloaded a user can install it directly from the command line with wsl --install --from-file <fileLocation>
(replacing <fileLocation>
with the actual location of the file). Alternatively, the .wsl
file for your custom WSL distribution can be opened by double-clicking it.
Distribution manifest details
The distribution manifest contains metadata about the distributions that are available for installation via wsl --install <distribution>
.
Linux distributions that are tar-based are listed under ModernDistribution
, with the below format:
"ModernDistributions": {
"<flavor>": [
{
"Name": "<version name>",
"FriendlyName": "<friendly name>",
"Default": true | false,
"Amd64Url": {
"Url": "<tar url>",
"Sha256": "<tar sha265 hash>"
},
"Arm64Url": {
"Url": "<tar url>",
"Sha256": "<tar sha265 hash>"
}
}
}
Each flavor
entry contains a list of installable distributions. Distributions can be installed either via the flavor name (in which case the default entry is installed), or the version name.
See how wsl --install
commands work with the below manifest:
{
"ModernDistributions": {
"my-distro": [
{
"Name": "my-distro-v3",
"Default": true,
"FriendlyName": "My distribution version 3 (latest)"
[...]
},
{
"Name": "my-distro-v2",
"Default": false,
"FriendlyName": "My distribution version 2"
[...]
}
}
}
Sample install commands:
$ wsl --install my-distro # Installs 'my-distro-v3' since it's the default for 'my-distro' flavor
$ wsl --install my-distro-v3 # Installs 'my-distro-v3' explicitly
$ wsl --install my-distro-v2 # Installs 'my-distro-v2' explicitly
Adding your distribution to wsl --install
for all WSL users
To make your WSL distribution available to all users, open a pull request on the WSL GitHub repository that modifies the DistributionInfo.json file to include your distribution information.
This pull request will be reviewed by the WSL team.
Adding your distribution to wsl --install
for your enterprise or business group
You can also make your distribution available in wsl --install
only to a select group by editing registry keys on the chosen Windows devices.
The WSL distribution manifest can be overridden by creating registry values in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss
.
DistributionListUrl
: Overrides the distribution manifest URLDistributionListUrlAppend
: Add distributions from that manifest URL to the list of installable distributions
Both registry values are strings (REG_SZ) and are expected to be in URL format.
Starting with WSL release 2.4.4, the file://
protocol is supported to make local testing easier. The expected format is: file:///C:/path/to/file
.
Test the distribution locally
To test a distribution tar, you can use the following sample powershell script to override the distribution manifest with the new distribution. First save the script below as override-manifest.ps1
:
#Requires -RunAsAdministrator
[cmdletbinding(PositionalBinding = $false)]
param (
[Parameter(Mandatory = $true)][string]$TarPath,
[string]$Flavor = "test-distro",
[string]$Version = "test-distro-v1",
[string]$FriendlyName = "Test distribution version 1")
Set-StrictMode -Version latest
$TarPath = Resolve-Path $TarPath
$hash = (Get-Filehash $TarPath -Algorithm SHA256).Hash
$manifest= @{
ModernDistributions=@{
"$Flavor" = @(
@{
"Name" = "$Version"
Default = $true
FriendlyName = "$FriendlyName"
Amd64Url = @{
Url = "file://$TarPath"
Sha256 = "0x$hash"
}
})
}
}
$manifestFile = "$PSScriptRoot/manifest.json"
$manifest | ConvertTo-Json -Depth 5 | Out-File -encoding ascii $manifestFile
Set-ItemProperty -Path "HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss" -Name DistributionListUrl -Value "file://$manifestFile" -Type String -Force
Then configure the local manifest by running the following command in an elevated Powershell:
.\override-manifest.ps1 -TarPath /path/to/tar
Once completed, you should see the following output from wsl.exe --list --online
:
$ wsl --list --online
The following is a list of valid distributions that can be installed.
Install using 'wsl.exe --install <Distro>'.
NAME FRIENDLY NAME
test-distro-v1 Test distribution version 1
You can then run wsl.exe --install test-distro-v1
to try the installation of the new distribution.
When you're done, you can delete HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss\DistributionListUrl
to revert to the official manifest.
WSL custom Linux distribution recommendations
Configuration file recommendations
- Ensure that your custom distribution includes both the
/etc/wsl.conf
and/etc/wsl-distribution.conf
configuration files. Both files should be owned byroot:root
and their permissions should be0644
. - If the
oobe.command
setting is used to create a new user, bothuid
andoobe.defaultUid
should be set to1000
. - Ensure that you set both
oobe.defaultName
andshortcut.icon
in the distribution configuration file:/etc/wsl-distribution.conf
- Do not include the file
/etc/resolv.conf
in the root filesystem. - Do include a root user in
/etc/passwd
. Theuid
for this root user should be0
. - There should be no password hashes in
/etc/shadow
. - The archive should not contain a kernel or an initramfs.
Systemd recommendations
If systemd is enabled, units that can cause issues with WSL should be disabled or masked. The below units are known to cause issues in WSL distributions (applies to both system and user units):
- systemd-resolved.service
- systemd-networkd.service
- NetworkManager.service
- systemd-tmpfiles-setup.service
- systemd-tmpfiles-clean.service
- systemd-tmpfiles-clean.timer
- systemd-tmpfiles-setup-dev-early.service
- systemd-tmpfiles-setup-dev.service
- tmp.mount
Windows Subsystem for Linux