How To

Create a Windows 11 or 10 Bootable USB on Linux

A Windows 11 ISO will not go onto a USB stick the way a Linux ISO does. Writing it with dd gives you a stick that starts Windows Setup and then fails, and the obvious fix of formatting the stick FAT32 and copying the files over stops at one file that is too big. On Linux the reliable answer is a FAT32 stick with that one file split in two, which boots on almost any UEFI PC with Secure Boot left on.

Original content from computingforgeeks.com - post 1198

This guide builds that stick with plain Linux tools, then covers WoeUSB-ng as the one-command alternative and shows exactly why dd fails. Every command below was run on Ubuntu 26.04 in October 2026, and both finished sticks were booted on a UEFI machine with Secure Boot enabled, with one of them taken through a full Windows 11 install.

Pick a method

We wrote the same Windows 11 ISO to a 16 GB stick three ways and booted each one on a UEFI virtual machine with Secure Boot on. You can see the outcome of each in this table.

MethodResult with Secure Boot onTime on the lab VMWhat it needs
FAT32 + split install.wimBooted, full Windows install completedAbout 1.5 minutesparted, mkfs.vfat, rsync, wimlib
WoeUSB-ngBooted to Windows Setup2 minutes 13 secondsA Python tool with an awkward install on current Ubuntu
dd straight to the stickSetup started, then “A media driver your computer needs is missing”Not measuredNothing, which is why people try it

The times come from a virtual disk, so on real hardware the stick’s write speed sets the pace. At 30 MB/s, 7.7 GB takes over four minutes on its own. The FAT32 method wins because the stick boots Microsoft’s own Windows-signed boot loader, so it does not depend on any extra certificate in your firmware. If you want one stick that carries several ISOs at once, Ventoy on Linux is the better tool, and the general bootable USB guide covers Linux ISOs, where dd is fine.

Download the Windows ISO and check it

Get the ISO from Microsoft’s Windows 11 download page in a browser. On Linux the page offers the ISO directly, without the Media Creation Tool. Scripted downloads are a different story. quickget from the quickemu package got this reply from Microsoft on our lab VM, shown here trimmed to the two relevant lines, so expect to click through the page yourself.

 - WARNING! Microsoft blocked the automated download request based on your IP address.
   Manually download the Windows 11 ISO using a web browser from: https://www.microsoft.com/en-us/software-download/windows11

Our lab used the Windows 11 Enterprise evaluation ISO from Microsoft’s Evaluation Center, because it has a direct download link. Its layout is the same as the consumer ISO, and Windows 10 ISOs use the same layout too. Mount the ISO read-only and look at the size of sources/install.wim, because that one file decides which method you need:

ISO=~/Win11_Enterprise_Eval_x64.iso
sha256sum "$ISO"
sudo mkdir -p /mnt/iso /mnt/usb
sudo mount -o loop,ro "$ISO" /mnt/iso
ls -l /mnt/iso/sources/install.wim

Set ISO to wherever your browser saved the file; ours sat in the home directory. Compare the hash with the one on Microsoft’s download page when it lists one. The evaluation page did not, so we recorded ours, which only matches that exact Enterprise evaluation build. The important number is the size of install.wim:

bc3f24086ebadc94489066b5ad78089e2cf5c3491e90e790bb81a2b199c10e38  /home/josphat/Win11_Enterprise_Eval_x64.iso
-r-xr-xr-x 1 nobody nogroup 7333902541 Sep 13 19:17 /mnt/iso/sources/install.wim

That is 7.3 GB in a single file. UEFI firmware reads FAT32, and FAT32 cannot hold a file of 4 GiB or more, so copying install.wim to a FAT32 stick fails partway with this error from cp:

cp: error writing '/mnt/usb/install.wim': File too large

If your install.wim is under 4 GiB, skip the split step below and drop --exclude=sources/install.wim from the rsync command so it copies everything. Check the number rather than assuming, because it grows with each Windows release. We tested with a Windows 11 ISO; Windows 10 media uses the same sources layout, so the steps carry over, but we did not boot a Windows 10 stick.

Find the USB stick

Everything on the stick is erased, so make sure you are pointing at the right device. Plug it in and list the block devices:

lsblk -o NAME,SIZE,TYPE,TRAN,MODEL,MOUNTPOINTS

On the lab VM the 16 GB stick is sda, and the system disk is vda with / mounted on it. A physical stick also shows usb in the TRAN column and its brand under MODEL, which makes it easy to tell apart from your SSD:

NAME     SIZE TYPE TRAN   MODEL         MOUNTPOINTS
sda       16G disk        QEMU HARDDISK
sr0        4M rom  ata    QEMU DVD-ROM
vda       60G disk virtio
├─vda1  58.9G part virtio               /
├─vda13 1023M part virtio               /boot
├─vda14    4M part virtio
└─vda15  106M part virtio               /boot/efi

Store the device in a variable so the commands below cannot drift onto the wrong disk halfway through, and so you only have to get it right once. If your desktop auto-mounted the stick, unmount its partitions before you go on, since the next step rewrites the partition table under them and wipefs refuses a busy device. An error from the second line saying nothing is mounted is harmless:

USB=/dev/sda
sudo umount ${USB}?*

The commands below name the partition ${USB}1, which is right for sdX devices. A built-in SD card reader or an NVMe device adds a p, so use ${USB}p1 there, for example /dev/mmcblk0p1.

Build the stick with FAT32 and a split install.wim

You need a GPT partition table, one FAT32 partition, every file from the ISO except install.wim, and then install.wim split into .swm parts under 4 GiB. Windows Setup reads split images natively, so nothing else on the stick changes. The split comes from wimlib, which every major distribution packages:

  • Ubuntu and Debian: wimtools
  • Fedora: wimlib-utils
  • Arch Linux: wimlib

On Ubuntu, install it along with rsync:

sudo apt install -y wimtools rsync

Wipe the old signatures and create the partition. parted marks a FAT32 partition on GPT as Microsoft basic data on its own, which is what Windows Setup expects to see:

sudo wipefs -a $USB
sudo parted -s $USB mklabel gpt mkpart WINUSB fat32 1MiB 100%
sudo parted -s $USB print

The msftdata flag confirms the partition type. We trimmed the output to the partition line, without the disk header above it:

Number  Start   End     Size    File system  Name    Flags
 1      1049kB  17.2GB  17.2GB  fat32        WINUSB  msftdata

Format it FAT32 with a label you will recognise in the firmware boot menu, then mount it next to the ISO:

sudo mkfs.vfat -F 32 -n WIN11 ${USB}1
sudo mount ${USB}1 /mnt/usb

Copy everything except the big file. The -r flag is enough here, because FAT32 cannot store Linux owners or permissions anyway:

sudo rsync -r --exclude=sources/install.wim /mnt/iso/ /mnt/usb/

Now split install.wim straight onto the stick. The last argument is the maximum part size in MiB. We used 3800 rather than something closer to 4096 because wimlib cannot divide a single compressed resource between parts, so a part can come out slightly larger than the number you give it:

sudo wimlib-imagex split /mnt/iso/sources/install.wim /mnt/usb/sources/install.swm 3800

On the lab VM the split took 1 minute 26 seconds and produced two parts, both under the FAT32 limit:

Finished splitting "/mnt/iso/sources/install.wim"
-rwxr-xr-x 1 root root 3984357833 Oct 24 12:42 /mnt/usb/sources/install.swm
-rwxr-xr-x 1 root root 3332199199 Oct 24 12:42 /mnt/usb/sources/install2.swm

Flush the writes and unmount both before you pull the stick. On real USB flash, sync is where you wait, because Linux caches the copy in RAM and only now pushes it to the slow flash:

sync
sudo umount /mnt/usb /mnt/iso
lsblk -o NAME,SIZE,FSTYPE,LABEL,PARTLABEL $USB

The stick should show one vfat partition labelled WIN11:

NAME   SIZE FSTYPE LABEL PARTLABEL
sda     16G
└─sda1  16G vfat   WIN11 WINUSB

That stick boots through the ISO’s own efi/boot/bootx64.efi. We checked its signature with sbverify --list, and it is signed by Microsoft Windows Production PCA 2011, Microsoft’s own Windows certificate rather than the third-party one. That is the reason we put this method first. One caveat applies to PCs that already have Microsoft’s BlackLotus (CVE-2023-24932) revocations turned on, because those put PCA 2011 on the block list and refuse older media, so on such a PC you need a Windows ISO whose boot files are signed with the 2023 certificate. The stick is also UEFI only, since it has no legacy boot code.

Use WoeUSB-ng for a one-command stick

WoeUSB-ng is an alternative to the FAT32 method, not an extra step, and it erases the same $USB device, so don’t run it on the stick you just built. It does the job in one command, and getting it installed on current Ubuntu is the hard part. The project’s README says sudo pip3 install WoeUSB-ng, and this Ubuntu release refuses that because system Python is marked as externally managed. These are the first lines of the error:

error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.

A normal pipx install fails too, because the package’s setup script tries to write /usr/local/bin/woeusbgui as your user. What worked on the lab VM was the project’s apt dependencies plus a global pipx install with sudo, which puts the tool in its own virtual environment under /opt/pipx. The --global flag needs pipx 1.5 or newer, which the lab’s Ubuntu 26.04 has but Ubuntu 24.04’s packaged pipx doesn’t, so on 24.04 the FAT32 method is the simpler route:

sudo apt install -y git p7zip-full python3-pip python3-wxgtk4.0 grub2-common grub-pc-bin parted dosfstools ntfs-3g pipx
sudo pipx install --global --system-site-packages WoeUSB-ng
woeusb --version

The --system-site-packages flag lets it use Ubuntu’s packaged wxPython, so nothing gets compiled. The version check returned:

0.2.12

We only used the woeusb command line. The install also drops a woeusbgui launcher, which we did not test with this method. WoeUSB-ng also downloads its UEFI:NTFS boot image from the Rufus project on GitHub while it writes the stick, so keep the machine online. Point it at the ISO and the whole device:

sudo woeusb --device "$ISO" $USB

WoeUSB-ng finished in 2 minutes 13 seconds. The run made three decisions for you without asking:

  • NTFS for the main partition, because of the 7.3 GB file
  • a 1 MB FAT partition holding a UEFI:NTFS loader
  • GRUB on the stick for legacy BIOS booting

The resulting layout on the stick:

NAME   SIZE FSTYPE LABEL
sda     16G
├─sda1  16G ntfs   NTFS
└─sda2   1M vfat   RUFUS_BOOT

On our Secure Boot VM this stick also booted into Windows Setup, but the path is different from the FAT32 stick. The firmware runs the UEFI:NTFS loader from the small partition, and that loader is signed through Microsoft Corporation UEFI CA 2011, the third-party certificate, not the Windows one. PCs that ship with the third-party certificate disabled will not start it with Secure Boot on, and you would have to turn Secure Boot off or enable that certificate in your firmware. Microsoft is also replacing its 2011 certificates, which the Secure Boot certificate update guide explains. That extra dependency is why WoeUSB-ng is the second choice here, even though it is the quicker one to run.

Skip dd for Windows ISOs

Writing the ISO with dd finished without an error, which is what makes it a trap. The result is a UDF filesystem written across the whole stick, with no partition table at all:

/dev/sda: UUID="fc4100004d532055" LABEL="CENA_X64FREE_EN-US_DV9" BLOCK_SIZE="2048" TYPE="udf"

Our VM’s firmware still started it, treating the stick like a DVD and showing the prompt you would get from a disc. That alone tells you it is not a USB boot layout, and a physical PC’s firmware may not offer that route at all:

Press any key to boot from CD or DVD prompt from a Windows ISO written to USB with dd

Windows Setup then loaded and stopped on the next screen. It did not find its installation files on the partitionless UDF stick and reported that as a missing driver, even though the disk sat on a standard SATA controller that Windows supports out of the box. Rewrite the stick with the FAT32 method and this screen goes away:

Windows 11 Setup error A media driver your computer needs is missing after booting a dd written USB

Nothing on a dd stick is worth keeping, so go back to the FAT32 steps above and start again at wipefs.

Boot the stick and install Windows

Plug the stick into the target PC and open its one-time boot menu, usually F12, F11, F8 or Esc depending on the vendor. Pick the entry that names your stick with a UEFI prefix. Leave Secure Boot on, because both working sticks above booted with it enabled, which we confirmed with mokutil --sb-state on the same VM. If you want to rehearse the install before touching real hardware, the same stick works in a VM, and the Windows 11 on KVM with virt-manager guide shows that setup. The first Setup screen asks for language and keyboard:

Windows 11 Setup language settings screen booted from a FAT32 USB made on Linux

The first time through, our VM had no TPM and Setup refused to continue after the setup option page. The check lists only what failed, so a missing TPM shows up alone like this. Enable the firmware TPM, often labelled fTPM, PTT or Security Device, and boot the stick again. In a KVM guest you add a virtual TPM instead, which the TPM on KVM guide covers:

Windows 11 Setup error This PC doesn't currently meet Windows 11 system requirements, The PC must support TPM 2.0

With a TPM added, Setup read the license from the split image and listed the disks. The stick shows up as a disk too, so pick the internal drive, not the partition labelled WIN11. Setup also printed “Windows 11 can’t be installed on this drive” under the list with the empty disk selected; Next stayed enabled, and the install went ahead when we clicked it:

Windows 11 Setup select location to install with the USB stick and an empty internal disk

The copy phase reads both .swm parts, and on the lab VM it was at 36% after 3 minutes and 76% after about 7:

Installing Windows 11 progress screen reading a split install.swm from the USB stick

Pull the stick when the PC restarts for the first time. We left it in, the firmware booted it again ahead of the internal disk, and Setup stopped with a confusing upgrade question:

Windows Setup dialog It looks like you started an upgrade and booted from installation media

The dialog itself says to remove the media and click Yes to continue. We powered off instead, removed the stick and started the VM again, which works too. It booted from the internal disk, carried on at “Installing 94%” and finished at the first screen of the out-of-box setup:

Windows 11 out-of-box setup country or region screen after installing from the USB stick

From here on, Windows no longer needs the stick. If you are installing next to an existing Linux system, the Fedora and Windows 11 dual boot guide covers the partitioning that comes before this step. Keep the FAT32 stick afterwards, because it doubles as a repair disk and you can refresh it for the next Windows release by deleting its files and repeating the copy and split steps.

Keep reading

Upgrade Ubuntu 24.04 to Ubuntu 26.04 LTS (Step by Step) Ubuntu Upgrade Ubuntu 24.04 to Ubuntu 26.04 LTS (Step by Step) UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 Security UFW Firewall Commands with Examples on Ubuntu 26.04 / 24.04 Create a Bootable Windows 11 USB and Install Windows 11 Windows Create a Bootable Windows 11 USB and Install Windows 11 Rocky Linux 10 Post-Install Tips: Repos, SIGs and rocky-release RHEl Rocky Linux 10 Post-Install Tips: Repos, SIGs and rocky-release dnf versionlock on Fedora: Lock Packages and Kernels (dnf5) Fedora dnf versionlock on Fedora: Lock Packages and Kernels (dnf5) ZimaBoard 2 Media Server: Jellyfin, Arr Stack and Navidrome Containers ZimaBoard 2 Media Server: Jellyfin, Arr Stack and Navidrome

5 thoughts on “Create a Windows 11 or 10 Bootable USB on Linux”

  1. Hi, I get
    “The following packages have unmet dependencies:
    woeusb : Depends: libwxgtk3.0-0v5 (>= 3.0.4+dfsg) but it is not installable
    E: Unable to correct problems, you have held broken packages”

    when trying sudo apt install woeusb on ubuntu 20.04

    when trying mk-build-deps, the control file | package name is missing.
    Could you please update the tutorial?

    Reply
  2. Hey , thank you very much sir ! i tryed to follows the steps in the official page in github woeusb , but with my poor english …. Now everything work , thank again man 🙂

    Reply
  3. It’s not just an English level issue because the steps as you explain here are not mentioned anywhere in git. There’s some information about dependencies, but I think it’s outdated, but you got the job done here! Thanks again 🙂 .

    Reply

Leave a Comment

Press ESC to close