How To

Run RHEL 10 and Fedora 45 / 44 on WSL in Windows 11

Red Hat Enterprise Linux does not appear in wsl --list --online, while Fedora Linux, AlmaLinux, Oracle Linux and CIQ’s Rocky Linux Plus all do. Running RHEL on WSL therefore means bringing your own root filesystem, and the two realistic sources are the subscription-gated WSL image from Red Hat and the freely redistributable Universal Base Image (UBI). The UBI route imported in 10.9 seconds on the test box and needed one systemd fix before user sessions worked.

Original content from computingforgeeks.com - post 138730

Fedora is in the catalog, but only up to FedoraLinux-44, so reaching Fedora 45 means a dnf system-upgrade inside a distro that WSL stops 15 seconds after the last shell exits. Our first attempt died at package 27 of 514 and left an RPM database that dnf could not repair. This guide installs Fedora and upgrades it safely, then uses it to export a RHEL 10 UBI distro and fix its masked systemd-logind unit.

Benchmarked October 2026 on WSL 3.0.1, with the Fedora 44 to 45 upgrade and the catalog rechecked on WSL 3.0.3 (Windows 11).

Prerequisites

  • Windows 11 with hardware virtualization enabled in firmware. The test box runs Windows 11 Enterprise, build 26100
  • WSL 2 installed. A machine without it gets the platform from wsl --install --no-distribution in an elevated PowerShell, followed by a reboot. The WSL containers guide covers the MSI install path used on the test box
  • About 4 GB of free disk on C: for both distros, the Fedora backup taken before the upgrade, the UBI tarball and a few container images
  • A Red Hat account with a subscription only if you want the official RHEL image (the free Developer Subscription for Individuals qualifies)

Step 1: Confirm the WSL version and what the catalog offers

All Windows-side commands in this guide run in a normal PowerShell window, starting with a check of the installed WSL build:

wsl --version

The recheck box reports WSL 3.0.3 on kernel 6.18 and Windows build 26100. The benchmark numbers later in this guide came from WSL 3.0.1, and we hit two behaviour differences between the builds. One is the sparse disk check near the end. The other is a one-off wsl: Failed to start the systemd user session line on cold starts under 3.0.3, on plain Fedora 44 as well as after the upgrade, and a later start was clean each time we checked:

WSL version: 3.0.3.0
Kernel version: 6.18.54.1-1
WSLg version: 1.0.79
MSRDC version: 1.2.7391
Direct3D version: 1.611.1-81528511
DXCore version: 10.0.26100.1-240331-1435.ge-release
Windows version: 10.0.26100.9457

Filtering the online catalog with Select-String returned nothing on the first attempt. wsl.exe writes UTF-16 by default, which the text matching in PowerShell does not parse, so set WSL_UTF8 for the session before piping its output anywhere:

$env:WSL_UTF8=1
wsl --list --online | Select-String -Pattern 'Fedora|Red Hat|RHEL|Oracle|Alma|Rocky|NAME'

Fedora, AlmaLinux and Oracle Linux are listed, and Rocky Linux now shows up only as CIQ’s Rocky Linux Plus builds. Red Hat Enterprise Linux is still absent from the catalog:

NAME                            FRIENDLY NAME
RLCPlus-9                       Rocky Linux Plus 9 (CIQ)
RLCPlus-10                      Rocky Linux Plus 10 (CIQ)
AlmaLinux-8                     AlmaLinux OS 8
AlmaLinux-9                     AlmaLinux OS 9
AlmaLinux-Kitten-10             AlmaLinux OS Kitten 10
AlmaLinux-10                    AlmaLinux OS 10
FedoraLinux-44                  Fedora Linux 44
FedoraLinux-43                  Fedora Linux 43
OracleLinux_7_9                 Oracle Linux 7.9
OracleLinux_8_10                Oracle Linux 8.10
OracleLinux_9_5                 Oracle Linux 9.5

The RLCPlus entries are CIQ’s own images, added to the Microsoft manifest on October 2, 2026. The community Rocky Linux images from RESF are not in the list. The catalog names carry the release number, and FedoraLinux-44 is the newest Fedora entry here. Step 3 moves it to Fedora 45 in place. If your list already offers FedoraLinux-45, install that instead, skip Step 3, and use FedoraLinux-45 wherever this guide says FedoraLinux-44.

Step 2: Install Fedora on WSL

The --no-launch flag registers the distro without opening a shell. The Fedora image ships an out-of-box script (/usr/libexec/wsl/oobe.sh) that prompts for a username on the first interactive launch. Creating the user non-interactively as root keeps the whole setup scriptable and the prompt never appears.

wsl --install FedoraLinux-44 --no-launch

Download and registration of the Fedora image took 51.8 seconds on the test box, with no prompts along the way:

Downloading: Fedora Linux 44
Installing: Fedora Linux 44
Distribution successfully installed. It can be launched via 'wsl.exe -d FedoraLinux-44'

WSL stores the instance as a single ext4.vhdx under %LOCALAPPDATA%\wsl, and the fresh disk measured 556 MB with 253 RPM packages installed. The first start took 17.2 seconds while WSL booted its utility VM, and the Fedora image already enables systemd in /etc/wsl.conf.

Fedora installed on WSL from the catalog in Windows 11

The terminal above shows the install and the post-setup checks covered next, run from the same PowerShell window.

Create the default user and set the hostname

Run the setup as root through wsl -d ... -u root -- <command>. Passing a command matters here. A bare wsl -d FedoraLinux-44 -u root is an interactive launch, so on a fresh install the out-of-box script runs first and prints Please create a default user account. The username does not need to match your Windows username. before any root shell appears.

Create a user in the wheel group and give it passwordless sudo for lab use. Drop the sudoers part and run passwd klinsmann instead if you prefer sudo to ask for a password.

wsl -d FedoraLinux-44 -u root -- bash -c "useradd -m -G wheel klinsmann && echo 'klinsmann ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/klinsmann"

Write /etc/wsl.conf with systemd, the default user and a fixed hostname. Without the [network] section, WSL hands every distro the Windows computer name.

wsl -d FedoraLinux-44 -u root -- bash -c "printf '[boot]\nsystemd=true\n\n[user]\ndefault=klinsmann\n\n[network]\nhostname=bench01\n' > /etc/wsl.conf && cat /etc/wsl.conf"

The file prints back with the three sections in place:

[boot]
systemd=true

[user]
default=klinsmann

[network]
hostname=bench01

With UID 1000 now present, the next interactive launch prints the same banner followed by User account already exists, skipping creation, then drops into the shell. Changes to wsl.conf only apply after the instance stops, so terminate it and reopen it:

wsl --terminate FedoraLinux-44
wsl -d FedoraLinux-44

The shell now opens as klinsmann, with one small surprise in the Fedora WSL image. The hostname binary is not installed, so the usual check fails with bash: hostname: command not found. hostnamectl is present and confirms the setting took effect:

whoami
hostnamectl hostname
systemctl is-system-running

All three checks pass, and the hostname from wsl.conf replaced the Windows computer name:

klinsmann
bench01
running

Bring the image current before building anything on it, since the catalog image lags the update repository. The first full upgrade took 142.6 seconds on the test box:

sudo dnf -y upgrade --refresh

The enabled repositories are the stock fedora, updates and fedora-cisco-openh264. The Fedora instance is a normal Fedora system from here, so the Distrobox and Toolbx workflows and GUI apps through WSLg work the same way they do on any Linux desktop.

Step 3: Upgrade Fedora 44 to Fedora 45 inside WSL

An in-place upgrade keeps the home directory, installed packages and the wsl.conf settings, and it uses the same dnf system-upgrade command as a Fedora workstation. The difference is the reboot. WSL has no real one, and it stops a distro 15 seconds after the last wsl.exe session attached to it exits. Microsoft documents this as instanceIdleTimeout in the .wslconfig reference, default 15000 ms, and on the test box a running systemd job did not count as activity. The upgrade transaction runs as a systemd service after that reboot, so something has to hold the instance open, and the order below is built around that:

  1. Export the distro to a tarball, so a broken upgrade costs a re-import instead of a rebuild
  2. Download the Fedora 45 packages with dnf system-upgrade download
  3. Trigger the stored transaction with dnf5 offline reboot, then terminate the instance from PowerShell
  4. Start it again with journalctl -f attached, which keeps it alive until the transaction ends
  5. Verify the release, the RPM database and the repositories

The sequence ran end to end twice on the test box. An earlier attempt without the held session broke the distro, and that failure and its recovery come right after the verification.

Back up the distro before upgrading

Stop the instance and export it from PowerShell. The export here and the restore import later both write into C:\wsl, and an import into a missing folder failed on the test box with Wsl/ERROR_PATH_NOT_FOUND, so create it first:

New-Item -ItemType Directory -Force C:\wsl
wsl --terminate FedoraLinux-44
wsl --export FedoraLinux-44 C:\wsl\fedora-44-backup.tar

The tarball came to 562 MB for an updated Fedora 44 instance and took 333 seconds to write on the test VM’s virtual disk. Keep it until the upgraded distro has run your own work for a while, because it is the only clean way back from a half-applied upgrade.

Download the Fedora 45 packages

Inside the Fedora shell, the download step resolves the whole release change and stores it. Apart from importing the Fedora 45 signing key, nothing on the running system changes yet, and sudo dnf5 offline clean still cancels the stored transaction at this point:

sudo dnf -y system-upgrade download --releasever=45

The transaction summary and the Fedora 45 key import close the output:

Transaction Summary:
 Installing:         4 packages
 Upgrading:        244 packages
 Replacing:        255 packages
 Downgrading:        9 packages

Total size of inbound packages is 126 MiB. Need to download 126 MiB.
After this operation, 16 MiB extra will be used (install 406 MiB, remove 390 MiB).
--------------------------------------------------------------------------------
Testing offline transaction
Importing OpenPGP key 0xF577861E:
 UserID     : "Fedora (45) <[email protected]>"
 Fingerprint: 4F50A6114CD5C6976A7F1179655A4B02F577861E
 From       : file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-45-x86_64
The key was successfully imported.
Transaction stored to be performed offline. Run `dnf5 offline reboot` to reboot and run the transaction. To cancel the transaction and delete the downloaded files, use `dnf5 offline clean`.
Complete!

The downgrades are the line to read before going on. They are packages where the Fedora 44 updates repository was ahead of Fedora 45 on the test date, among them tzdata (2026e back to 2026c), rsync and the wget2 packages. That count shrinks as the Fedora 45 updates repository catches up, so a different number on your machine is normal. The 126 MiB download took between 106 and 279 seconds across three runs, depending on the mirror.

Run the offline transaction with a session attached

Still inside Fedora, hand the stored transaction to the offline service:

sudo dnf5 -y offline reboot

It prints The system will now reboot to upgrade to release version 45., but WSL does not restart anything. wsl -l -v still listed the distro as Running. Commands sent to it in that state printed Failed to translate path errors and session failures, so terminate it from PowerShell, then start it again with the transaction’s journal attached. Leave that window alone until the command returns: no Ctrl+C, no closing PowerShell and no letting Windows sleep, since any of them can end the session and leave the half-applied state described below. The last package step sat for 31 seconds on the test box, which looks like a hang and is not one:

wsl --terminate FedoraLinux-44
wsl -d FedoraLinux-44 -u root -- journalctl -f -o cat -u dnf5-offline-transaction

That start boots into system-update.target, and the transaction begins within seconds. journalctl -f never exits on its own, so the instance stays up, and the command returns only when the service reboots the distro at the end. That took 348 and 373 seconds on the two complete runs. The last lines look like a failure even though nothing failed:

[512/514] Removing fedora-release-ident 100% |   8.0   B/s |   2.0   B |  00m00s
[513/514] Removing ncurses-base-0:6.6-1 100% |   2.0 KiB/s | 180.0   B |  00m00s
[514/514] Removing libgcc-0:16.2.1-2.fc 100% |   0.0   B/s |  11.0   B |  00m31s
Warning: skipped OpenPGP checks for 257 packages from repository: fedora
Transaction complete! Cleaning up and rebooting...
Complete!
dnf5-offline-transaction.service: Main process exited, code=exited, status=1/FAILURE
dnf5-offline-transaction.service: Failed with result 'exit-code'.
Stopped dnf5-offline-transaction.service - Offline upgrades/transactions using DNF 5.
dnf5-offline-transaction.service: Consumed 1min 50.335s CPU time over 5min 29.614s wall clock time, 841.9M memory peak.
dnf5-offline-transaction.service: Triggering OnFailure= dependencies.

Both warnings come from dnf5, not from WSL, and both are known, still-open upstream issues. Maintainers attribute the status=1/FAILURE after Complete! to a race between dnf5 exiting and systemd stopping it during the reboot it asked for (dnf5 issue 2896), and it appeared on one of the two complete runs. For the skipped OpenPGP checks, a maintainer explains in dnf5 issue 2206 that a stored transaction verifies signatures in the test that runs right after the download, then skips them when the transaction is replayed. Whether that is intended is still an open question in the thread. The checks in the next section decide whether the upgrade worked, not the unit status.

The other way to keep the instance alive is instanceIdleTimeout=-1 under [general] in %UserProfile%\.wslconfig, which turns the automatic stop off for every distro. We used the attached session instead, since it leaves no setting to undo, and the .wslconfig route was not tested here.

Verify the upgraded distro

Terminate the instance once more and open it. The first two starts after the upgrade are slow. On the final run the first was still starting after 34 seconds, printed wsl: Failed to start the systemd user session for 'klinsmann', and left /sbin/init failed to start within 10000ms in the journal, because WSL waits only 10 seconds for systemd. Terminate it and start again. On that second start systemd needed 24.4 and 31.8 seconds on the two runs, still past the 10-second wait, but the shell opened without the error and the system reported running. Then check the release and the package database:

grep -E '^(VERSION_ID|VARIANT_ID)=' /etc/os-release
cat /etc/fedora-release
sudo dnf check && rpm -qa | grep -c fc44
systemctl is-system-running
loginctl list-sessions --no-legend
sudo dnf repolist

All of it came back healthy on the second start of the final run, which went from a fresh catalog install through every command in this step:

VERSION_ID=45
VARIANT_ID=wsl
Fedora release 45 (Forty Five)
0
running
c1 1000 klinsmann - 242 user          pts/1 no -
c2 1000 klinsmann - 256 manager       -     no -
c4    0 root      - 305 manager-early -     no -
repo id               repo name
fedora                Fedora 45 - x86_64
fedora-cisco-openh264 Fedora 45 openh264 (From Cisco) - x86_64
updates               Fedora 45 - x86_64 - Updates
updates-testing       Fedora 45 - x86_64 - Test Updates

dnf check printing nothing means no duplicate or broken packages, and the 0 means no Fedora 44 package survived, where the interrupted run below left 249. The distro had 259 packages afterwards, with systemd 262 and glibc 2.44 from the Fedora 45 repositories, and logind registered the user session that Step 8 has to repair on RHEL. If updates-testing shows up in the repository list, as it did on the test box, Fedora’s test-update channel is enabled next to the regular repositories. Turn it off unless you want packages that have not finished testing:

sudo dnf config-manager setopt updates-testing.enabled=0

Three things carry over from Fedora 44 and are worth knowing before you plan disk or scripts around the upgraded distro:

  • Download cache: 170 MiB of repository metadata from both releases stayed in /var/cache/libdnf5 until sudo dnf clean all removed it.
  • Disk size: the ext4.vhdx measured 1,420 MB after the cleanup, and WSL disks do not shrink by themselves.
  • Distro name: wsl -l -v still lists FedoraLinux-44, although the upgraded wsl-setup package writes defaultName = FedoraLinux-45 into /etc/wsl-distribution.conf. That file only supplies defaults for a fresh install.

The name is the one to remember. Every wsl -d command in the rest of this guide keeps using FedoraLinux-44, and scripts that call it keep working after the upgrade.

Fedora 44 to 45 offline upgrade finishing inside WSL and the release check in PowerShell

The capture above is the end of the attached journal and the release check, run from PowerShell on the test box. It is trimmed: the slow first start and the second terminate between the two are left out.

What an interrupted upgrade leaves behind

Our first attempt skipped the attached session. After dnf5 offline reboot and a terminate, short status commands started and polled the distro while the transaction ran, and each one returned within seconds. Shortly after the last of them closed, WSL stopped the instance at package 27 of 514, right after the new setup package went in. The next start was an ordinary boot with both releases in the RPM database:

sudo dnf check 2>&1 | tail -4
rpm -qa | wc -l
rpm -qa | grep -c fc44

dnf counted 54 problems, mostly duplicate packages, and 249 of the 283 installed packages were still Fedora 44 builds:

 duplicate with "xkeyboard-config-0:2.48-4.fc45.noarch"
xkeyboard-config-0:2.48-4.fc45.noarch
 duplicate with "xkeyboard-config-0:2.47-1.fc44.noarch"
Check discovered 54 problem(s) in 48 package(s)
283
249

Both fedora-release-common 44 and 45 were installed, so even dnf repolist still reported the Fedora 44 repositories. The obvious repairs failed. sudo dnf -y --releasever=45 distro-sync stopped with The operation would result in removing the following protected packages: setup. sudo dnf -y remove --duplicates ended in a chain of unresolvable dependencies that ran through sudo, libselinux and pcre2. The Fedora docs call a plain distro-sync release change not a supported upgrade method in any case. Restoring the export is the repair that worked:

wsl --unregister FedoraLinux-44
wsl --import FedoraLinux-44 C:\wsl\FedoraLinux-44 C:\wsl\fedora-44-backup.tar

Importing the export taken before that first attempt took 112.2 seconds and brought back Fedora 44 with the klinsmann user, the wsl.conf settings and a clean dnf check. The upgrade then succeeded from the restored distro with the session attached. The commands above were tested once more on the backup from the final clean run, where the import took 68.4 seconds with the same result. wsl --unregister deletes the broken ext4.vhdx for good, so confirm the tarball exists before running it.

Step 4: Choose the RHEL source

The two sources differ in what you get from dnf afterwards, not in how WSL runs them:

SourceAccount neededRepositoriesTested here
Official RHEL for WSL image (Red Hat downloads or image builder)Red Hat login plus a subscriptionFull BaseOS, AppStream and CRB after registrationDocumented steps only
UBI 10 container image exported to a tarballNoneUBI subset of BaseOS, AppStream and CodeReady BuilderYes, end to end

Pick the official image for anything that has to match a supported RHEL host, such as building RPMs against packages outside UBI or reproducing a production issue. Pick UBI for a quick, legally redistributable RHEL userland on a laptop with no Red Hat account. Earlier versions of this guide used a community wrapper around UBI. The steps below use images published by Red Hat directly, which removes the third-party binary from the chain.

The official Red Hat image

Red Hat publishes a prebuilt RHEL WSL image on the RHEL downloads page and can build a customized one in the Hybrid Cloud Console image builder with WSL as the output type. Both routes require a Red Hat login. The test box did not use this image, so the commands below follow the Red Hat getting-started article rather than a capture. With the download in your Downloads folder, import it from PowerShell:

$img = (Get-ChildItem $HOME\Downloads\rhel-10*wsl2* | Select-Object -First 1).FullName
wsl --import RHEL-10-official C:\wsl\RHEL-10-official $img

The prebuilt download follows the rhel-10.0-x86_64-wsl2.tar.gz naming. An image-builder download is named composer-api-<uuid>-image.wsl instead, so point $img at that file directly. The distro name differs from the UBI import below so both can coexist.

Inside the distro, register with an activation key created in the Hybrid Cloud Console, replacing the example organization ID and key name below with your own:

export RH_ORG="1234567"
export RH_KEY="wsl-dev"
sudo rhc connect --organization "${RH_ORG}" --activation-key "${RH_KEY}"

Registration is what enables the BaseOS, AppStream and CodeReady Builder repositories on the official image, which has no usable repositories before it. A system that skips it prints This system is not registered with an entitlement server on every dnf call, and the entitlement server error guide covers the other causes of that message. User creation and the wsl.conf layout are the same as in Step 7. Apply the Step 8 fix only if the same session error appears.

Step 5: Export the RHEL 10 UBI root filesystem with Podman

A container image is a root filesystem plus metadata, and podman export writes out the filesystem part as a plain tar archive that wsl --import accepts. The Fedora instance from Step 2 is a convenient place to run Podman, and /mnt/c puts the tarball straight onto the Windows drive.

sudo dnf -y install podman

Pull the UBI 10 image, run it once so a container exists to export, then write the archive to C:\wsl:

podman pull registry.access.redhat.com/ubi10/ubi:latest
podman run --name ubi10-export registry.access.redhat.com/ubi10/ubi:latest cat /etc/redhat-release
mkdir -p /mnt/c/wsl
podman export ubi10-export -o /mnt/c/wsl/ubi10.tar
podman rm ubi10-export
ls -lh /mnt/c/wsl/ubi10.tar

The container reports RHEL 10.2, and the archive lands at 210 MB:

Red Hat Enterprise Linux release 10.2 (Coughlan)
ubi10-export
-rwxrwxrwx 1 klinsmann klinsmann 210M Oct  1 16:29 /mnt/c/wsl/ubi10.tar

Podman also prints "/" is not a shared mount, this could cause issues or missing mounts with rootless containers during the run. That warning is cosmetic for a one-shot export and did not affect the archive.

The Podman install has one side effect on the Fedora instance, because it pulls in qemu-user-static as a weak dependency, which changes the health status of the instance in a way that looks worse than it is.

Fedora shows “degraded” after installing Podman

This behaviour was measured on Fedora 44. After the next restart, systemctl is-system-running reports degraded and systemctl --failed lists systemd-binfmt.service. The journal for the unit shows why it exits with a failure on every boot:

sudo journalctl -b -u systemd-binfmt --no-pager | tail -4

The flush step fails on a read-only file that WSL mounts over /proc/sys/fs/binfmt_misc/status:

Oct 01 16:45:13 bench01 systemd-binfmt[98]: Failed to flush binfmt_misc rules, ignoring: Read-only file system
Oct 01 16:45:13 bench01 systemd[1]: systemd-binfmt.service: Main process exited, code=exited, status=1/FAILURE
Oct 01 16:45:13 bench01 systemd[1]: systemd-binfmt.service: Failed with result 'exit-code'.
Oct 01 16:45:13 bench01 systemd[1]: Failed to start systemd-binfmt.service - Set Up Additional Binary Formats.

The failure turns out to be cosmetic on the test box. After a full wsl --shutdown with the unit left alone, all 31 qemu handlers still registered and podman run --arch arm64 printed aarch64. Masking the unit with sudo systemctl mask systemd-binfmt.service turns the status back to running, but after the next shutdown the test box had zero qemu handlers and arm64 containers no longer started. Mask it only if a clean status matters more than cross-architecture builds.

Step 6: Import RHEL into WSL

Back in PowerShell, import the archive as a new distro. The second argument is the folder that will hold its ext4.vhdx:

wsl --import RHEL-10 C:\wsl\RHEL-10 C:\wsl\ubi10.tar
wsl -l -v

The import completed in 10.9 seconds on the first run and 14.1 seconds on a repeat, and RHEL-10 now sits beside Fedora as a WSL 2 distro:

The operation completed successfully.
  NAME              STATE           VERSION
* Ubuntu-26.04      Stopped         2
  FedoraLinux-44    Running         2
  RHEL-10           Stopped         2

The same import, release check and repository list, captured from PowerShell on the test box:

RHEL 10 UBI root filesystem imported into WSL with dnf repolist

The first start of an imported distro took 3.4 seconds because the utility VM was already running for Fedora. An imported tarball has no default user, so the shell opens as root. Confirm the release and the subscription state:

wsl -d RHEL-10 -- cat /etc/redhat-release
wsl -d RHEL-10 -- subscription-manager status
wsl -d RHEL-10 -- dnf repolist

subscription-manager is part of the UBI image and reports the system as unregistered. dnf still works because the three UBI repositories need no entitlement:

Red Hat Enterprise Linux release 10.2 (Coughlan)
+-------------------------------------------+
   System Status Details
+-------------------------------------------+
Overall Status: Not registered

Updating Subscription Management repositories.
Unable to read consumer identity

This system is not registered with an entitlement server. You can use subscription-manager to register.

repo id                                  repo name
codeready-builder-for-ubi-10-x86_64-rpms Red Hat Universal Base Image 10 (RPMs) - CodeReady Builder
ubi-10-for-x86_64-appstream-rpms         Red Hat Universal Base Image 10 (RPMs) - AppStream
ubi-10-for-x86_64-baseos-rpms            Red Hat Universal Base Image 10 (RPMs) - BaseOS

The CodeReady Builder channel is already enabled here, unlike a fresh RHEL server where it has to be enabled by hand. The fresh import counted 175 packages on a 300 MB ext4.vhdx.

Step 7: Add a user and wsl.conf to the RHEL distro

UBI strips tools that a container does not need and an interactive system does, so install them before creating the user:

wsl -d RHEL-10 -- dnf -y -q install sudo passwd shadow-utils procps-ng iproute hostname

On the test box dnf added sudo, procps-ng and hostname plus three libraries. passwd, shadow-utils and iproute were already present in this UBI build:

Installed:
  cyrus-sasl-lib-2.1.28-30.el10_2.x86_64    hostname-3.23-14.el10.x86_64
  libevent-2.1.13-1.el10_2.x86_64           openldap-2.6.10-1.el10.x86_64
  procps-ng-4.0.4-11.el10.x86_64            sudo-1.9.17-10.p2.el10_2.6.x86_64

Create the same user, sudoers entry and wsl.conf as on Fedora, then restart the instance:

wsl -d RHEL-10 -- useradd -m -G wheel klinsmann
wsl -d RHEL-10 -- bash -c "echo 'klinsmann ALL=(ALL) NOPASSWD:ALL' | tee /etc/sudoers.d/klinsmann"
wsl -d RHEL-10 -- bash -c "printf '[boot]\nsystemd=true\n\n[user]\ndefault=klinsmann\n\n[network]\nhostname=bench01\n' | tee /etc/wsl.conf"
wsl --terminate RHEL-10

The next wsl -d RHEL-10 opens as klinsmann, and systemctl is-system-running reports running. That status hides a broken login path, which appears as soon as WSL tries to start a user session.

Step 8: Fix the systemd user session error on the RHEL import

Every shell opened in the UBI-based distro prints this from wsl.exe before the prompt appears:

Error: “wsl: Failed to start the systemd user session for ‘klinsmann’. See journalctl for more details.”

On WSL 3.0.3 the same line can also show up once on a cold start of a healthy distro, as Step 1 notes. The UBI import prints it on every shell, and that repetition is what points at this fault. The shell still opens after the message, but PAM never registers a login session, which leaves no per-user systemd manager behind systemctl --user. The journal names the failing component:

wsl -d RHEL-10 -u root -- bash -c "journalctl -b --no-pager | grep -m2 'pam_systemd'"

PAM cannot reach org.freedesktop.login1, the D-Bus name owned by systemd-logind:

Oct 01 16:30:14 bench01 login[97]: pam_systemd(login:session): Failed to create session: Could not activate remote peer 'org.freedesktop.login1': activation request failed: unit is invalid
Oct 01 16:30:25 bench01 login[155]: pam_systemd(login:session): Failed to create session: Could not activate remote peer 'org.freedesktop.login1': activation request failed: unit is invalid

The phrase “unit is invalid” points at a masked unit, and UBI ships with several units linked to /dev/null because a container has no use for gettys, logind or hugepage mounts:

wsl -d RHEL-10 -u root -- systemctl list-unit-files --state=masked

Seven units are masked on the imported filesystem, and systemd-logind.service is the one PAM needs:

UNIT FILE                           STATE  PRESET
dev-hugepages.mount                 masked disabled
sys-fs-fuse-connections.mount       masked disabled
console-getty.service               masked disabled
dbus-org.freedesktop.login1.service masked disabled
systemd-logind.service              masked disabled
systemd-remount-fs.service          masked disabled
getty.target                        masked disabled

7 unit files listed.

Unmasking that single unit is enough, because the dbus-org.freedesktop.login1.service entry is an alias of the same unit and clears with it. Restart the distro afterwards so systemd starts clean:

wsl -d RHEL-10 -u root -- systemctl unmask systemd-logind.service
wsl --terminate RHEL-10

The unmask removes the /dev/null link that UBI placed in /etc/systemd/system:

Removed '/etc/systemd/system/systemd-logind.service'.

The same two steps, captured from the root shell on a fresh import:

Unmasking systemd-logind on RHEL on WSL to fix the user session error

Open the distro again as the default user and check that logind now registers a real session:

whoami
hostname
loginctl list-sessions
systemctl is-system-running

The error no longer appears, and logind now tracks the interactive session plus the user manager:

klinsmann
bench01
SESSION  UID USER      SEAT LEADER CLASS   TTY   IDLE SINCE
     c1 1000 klinsmann -    99     user    pts/1 no   -
     c2 1000 klinsmann -    105    manager -     no   -

2 sessions listed.
running

The user-side checks from the same session, including a rootless container run that Step 9 expands on:

loginctl sessions and rootless Podman running in RHEL on WSL

The other masked units can stay masked, since nothing in a WSL distro needs a getty or the hugepages mount, and the test box ran rootless containers without touching them.

Step 9: Run rootless Podman inside RHEL on WSL

Podman comes from the UBI AppStream repository, so it installs without a subscription. A rootless container is a good end-to-end test because it exercises the user session, subordinate UIDs and the overlay driver together:

sudo dnf -y install podman
podman --version
podman run --rm registry.access.redhat.com/ubi10/ubi-minimal cat /etc/redhat-release

The UBI repositories carry Podman 5.8.2, and the container starts as klinsmann without sudo:

podman version 5.8.2
Red Hat Enterprise Linux release 10.2 (Coughlan)

With a working session, the distro also handles Podman Quadlet units under systemctl --user. For containers without a full distro around them, the Podman on Windows Server guide and the Microsoft wslc runtime are lighter options. Other distros missing from the catalog import the same way, as the Arch Linux on WSL walkthrough shows.

Fedora vs RHEL on WSL: measured on the same box

Both distros ran on one Windows 11 VM with 6 vCPUs and 12 GB of RAM, of which WSL gave its utility VM 5.8 GB. Restart times are three runs of wsl --terminate followed by wsl -d <distro> -- true. Idle memory was read from the vmmemWSL process after wsl --shutdown, with only that distro running for 90 seconds.

MetricFedora 44 (catalog install)RHEL 10 (UBI import)
Install or import time51.8 s, including download10.9 s and 14.1 s from a local 210 MB tarball
First start17.2 s (cold utility VM)3.4 s (utility VM already up)
Restart after terminate, median of 36.07 s (range 5.20 to 22.19)7.58 s (range 5.96 to 15.88)
Packages at first boot253175
ext4.vhdx when fresh556 MB300 MB
ext4.vhdx after setup1,421 MB (dnf upgrade, Podman, UBI image pulled)542 MB (tools, Podman, ubi-minimal pulled)
Running services at idle115
Processes at idle3624
vmmemWSL working set, distro alone741 MB858 MB
Memory used inside the guest (free -m)447 MB431 MB
Default userOOBE prompt on interactive launch (UID 1000), skippableNone, opens as root
systemdWorks as shipped; degraded after Podman (cosmetic binfmt failure)Needs systemd-logind unmasked
Repositories without an accountFull Fedora reposUBI BaseOS, AppStream, CRB subset
Podman from repos5.8.75.8.2

Three of these numbers need context before they drive a decision. The RHEL import looks faster mainly because it skips the download and lands on a VM that is already running, so compare the 556 MB and 300 MB disks rather than the start times. The vmmemWSL figure covers the whole utility VM, page cache included, which is why RHEL reads higher despite running half the services. The guest-side free -m figures differ by 16 MB, within the margin of run-to-run noise. The restart outliers (22.19 s and 15.88 s) were single runs where Windows reclaimed the VM between attempts, so the medians are the figures to plan with.

The number that matters for disk is growth, not the starting size. A Fedora instance that tracks updates grew 2.6x in one session, while the UBI distro stayed near half a gigabyte because its repositories carry far fewer packages. Neither disk shrinks on its own, and WSL 3.0.1 refused to turn sparse mode on:

wsl --manage RHEL-10 --set-sparse true

The command fails with a data-corruption warning instead of converting the disk:

Sparse VHD support is currently disabled due to potential data corruption.
To force a distribution to use a sparse VHD, please run:
wsl.exe --manage <DistributionName> --set-sparse true --allow-unsafe
Error code: Wsl/Service/E_INVALIDARG

WSL 3.0.2 changed that, and its release notes list “Enable experimental sparse VHD creation”. On WSL 3.0.3 the switch only works on a stopped distro. Run against the upgraded Fedora instance while it was up, it failed with Wsl/Service/WSL_E_DISTRO_NOT_STOPPED, so shut WSL down first:

wsl --shutdown
wsl --manage FedoraLinux-44 --set-sparse true

The conversion now goes through, with a warning in place of the refusal:

wsl: Sparse VHDs are currently experimental. If you encounter unexpected behavior, please file an issue at
https://github.com/microsoft/WSL.
The operation completed successfully.

Experimental is the word to plan around. We did not measure whether the converted disk gives space back after deletes, so treat sparse mode as a convenience on distros you can rebuild, and keep the Step 3 export as the real safety net. Leave --allow-unsafe alone on older builds for the same reason. Budget disk for the grown size instead, or compact a distro with wsl --export followed by wsl --unregister and wsl --import. The unregister deletes the old ext4.vhdx, so confirm the exported tarball is complete before running it. For RHEL work that needs packages outside UBI, the official image plus rhc connect is the only supported route. For a local OpenShift cluster on top of a registered system, the CRC guide picks up where this one stops.

Keep reading

Install KVM and Virt-Manager on Arch Linux Virtualization Install KVM and Virt-Manager on Arch Linux Create a Bootable Windows 11 USB and Install Windows 11 Windows Create a Bootable Windows 11 USB and Install Windows 11 Install KVM on Debian 13 / Debian 12: Complete Guide KVM Install KVM on Debian 13 / Debian 12: Complete Guide Configure NTP Server on Windows Server 2025 / 2022 (w32tm Guide) Windows Configure NTP Server on Windows Server 2025 / 2022 (w32tm Guide) Windows 11 Keyboard Shortcuts Cheat Sheet (Printable PDF) Cheat Sheets Windows 11 Keyboard Shortcuts Cheat Sheet (Printable PDF) Join Ubuntu / Debian To Active Directory (AD) domain Debian Join Ubuntu / Debian To Active Directory (AD) domain

Leave a Comment

Press ESC to close