【KVM】実機Windows 11を仮想マシンとして起動し、WinAppsでLinuxに統合する
実機でもVM(QEMU/KVM)でもWindowsを起動したい。
そのうえでWinAppsを使いたい。
前提
- パーティションが死ぬ可能性があります。バックアップしてからやるか、消えてもいいものでやること。
- Windowsのインストールiso(例:
Win11_25H2_Japanese_x64.iso)を用意する - 作業ディレクトリはどこでもよいが
~/.config/winapps/imagesとかがいいかも
手順
1. 実機でWindowsをセットアップする
普通にセットアップすればいいです。
WindowsHelloはつけないほうがいいかも。
つけてもいいけど、MicrosoftのパスワードでもログオンできるようにしないとVMでログオンできません。
2. EFIイメージを作成
# 100MB(1MB x 100)のイメージを ./efi1 に作成
dd if=/dev/zero of=efi1 bs=1M count=100
# 1MB(1MB x 1)のイメージを ./efi2 に作成
dd if=/dev/zero of=efi2 bs=1M count=1
3. パーティションを特定する
lsblk -o NAME,SIZE,TYPE,PARTUUID
Windowsが入っているパーティションのPARTUUIDをメモする(EFIや回復パーティションではない)
4. 仮想ストレージデバイスを作成するスクリプトを作成
start_md0.sh (1箇所PARTUUIDを貼り付けするところがある)
#!/usr/bin/env bash
# 管理者権限で実行
if [ "$(id -u)" -ne 0 ]; then
echo "Requesting root privileges..."
exec sudo "$0" "$@"
fi
# Windows 11 Partition
WIN=/dev/disk/by-partuuid/{ここにWindowsパーティションのPARTUUID}
# このスクリプトがあるパス
EFIDIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
# エラーがあればそこで終了
set -e
# すでに仮想デバイスが作成されていれば終了
if [[ -e /dev/md0 ]]; then
echo "/dev/md0 already exists"
exit 1
fi
# Windowsのパーティションがマウントされていたらアンマウント
if mountpoint -q -- "${WIN}"; then
echo "Unmounting ${WIN}..."
umount ${WIN}
fi
# 必要なモジュールをロード
modprobe loop
modprobe linear
# ループデバイスの作成
LOOP1=$(losetup -f --show "${EFIDIR}/efi1")
echo "Created loop device: $LOOP1"
LOOP2=$(losetup -f --show "${EFIDIR}/efi2")
echo "Created loop device: $LOOP2"
# RAID array (md0) の作成
echo "Building /dev/md0 ..."
mdadm --build --verbose /dev/md0 --chunk=512 --level=linear --raid-devices=3 ${LOOP1} ${WIN} ${LOOP2}
REAL_USER=${SUDO_USER:-$USER}
echo "Changing ownership to user: $REAL_USER"
chown $REAL_USER:disk /dev/md0
echo "$LOOP1 $LOOP2" > /root/.win11-loop-devices
stop_md0.sh
#!/usr/bin/env bash
if [ "$(id -u)" -ne 0 ]; then
echo "Requesting root privileges..."
exec sudo "$0" "$@"
fi
mdadm --stop /dev/md0
xargs losetup -d < /root/.win11-loop-devices
# 作成したスクリプトファイルに実行権限を与える
sudo chmod +X start_md0.sh stop_md0.sh
# 実際に /dev/md0 を作成できるか試す
./start_md0.sh
# /dev/md0 と出てデバイスが存在すればOK
ls /dev/md0
# /dev/md0 を削除
./stop_md0.sh
4. 仮想ストレージデバイスを構成
./start_md0.sh
# /dev/md0 のパーティションを構成
sudo parted /dev/md0
# 単位をセクタに指定
(parted) unit s
# パーティションテーブルをGPTで作成
(parted) mktable gpt
# 2048セクタ から 204799セクタ を FAT32 に指定 (efi1 用)
(parted) mkpart primary fat32 2048 204799
# 204800セクタ から 末尾2049セクタ を NTFS に指定 (Windows 11パーティション用)
(parted) mkpart primary ntfs 204800 -2049
# 1つ目のパーティション(efi1)をEFIとして指定
(parted) set 1 boot on
(parted) set 1 esp on
(parted) name 1 EFI
# 2つ目のパーティション(Windows 11)をWindowsとして指定
(parted) set 2 msftdata on
(parted) name 2 Windows
# parted を抜ける
(parted) quit
./stop_md0.sh
5. WindowsのブートエントリをEFIに書き込む
./start_md0.sh
virt-managerで作業を行う。
QEMU/KVM があることを確認する。
左上のアイコンの「新しい仮想マシンの作成」をクリック。
「接続」をQEMU/KVMにする。 (1つしかないなら選択できない場合もある)
「既存のディスクイメージをインポート」を選択。

「既存のストレージのパス」として/dev/md0を入力。
「インストールするオペレーティングシステム」としてMicrosoft Windows 11を入力(選択)。

メモリとCPUの設定をそのまま通過して、

「インストールの前に設定をカスタマイズする」にチェックを入れて「完了」

「ハードディスクを追加」>「ストレージ」で
「カスタムストレージ」をWindowsインストーラーのiso
「デバイスの種類」を「CD-ROMデバイス」
「バスの種類」を「SATA」
に指定して「完了」

ブートオプションを
「SATA CD-ROM」にチェックを入れ、一番上に指定する。
「適用」をクリック

左上の「インストールの開始」をクリック。
セットアップウィザードが起動したら、言語とキーボードを日本語に設定し、Shift + F10を押してコマンドプロンプトを起動する。
diskpartで仮想パーティションの構成
diskpart
REM ボリュームの一覧を表示
DISKPART> list volume
REM EFIパーティションを選択 (Size に 99MB と書いてあるもの。ここでは Volume 2
DISKPART> select volume 2
REM fat32でフォーマット
DISKPART> format quick fs=fat32 label="EFI"
REM ドライブレターをSとして登録
DISKPART> assign letter=S
REM Windowsパーティションを選択 (Fs に NTFS と書いてあるもの。ここでは Volume 1)
DISKPART> select volume 1
REM ドライブレターをCとして登録
DISKPART> assign letter=C
DISKPART> exit
Windows Boot Managerを書き込み
bcdboot C:\Windows /s S: /f UEFI
ブート ファイルは正常に作成されました。と出れば完了。
「コマンドプロンプト」と「Windows 11 セットアップ」をXボタンをクリックして終了させる。
「本当に終了しますか?」が出たら「はい」をクリック。
待っていたら「デバイスを準備しています」が終わって、勝手に再起動します。
これでWindows 11が起動するはずです。
6. ネットワークの設定
Windowsが起動するのを待っている間にLinux側のファイアウォールの設定をします。
おそらくデフォルトのままではNATや仮想ブリッジデバイスを通してVM側からネットワークにアクセスできません。
/etc/default/ufwのファイルを編集します。
DEFAULT_FORWARD_POLICY="DROP"
# の DROP を ACCEPT に書き換えます。
DEFAULT_FORWARD_POLICY="ACCEPT"
仮想ブリッジデバイス(virbr0)を信頼させます。
デバイス名が違うかもしれませんがip aとかで確認してください。
sudo ufw allow in on virbr0
sudo ufw allow out on virbr0
Windows 11 が起動したらログインしてネットワーク接続を確認します。
REM Windows 11 内
ping <自分のIP>
ping <enp1s0 とか wlan0 のIP>
ping <virbr0 のIP>
ping 1.1.1.1
curl ipinfo.io
# Linux 内
ping <virbr0 のIP>
curl ipinfo.io
7. virtio-guest-toolsを入れる。
virtio-win-0.1.285.isoとかをダウンロードして
cd-romでマウントするなりVM内でisoをダウンロードするなりして、
インストールしてください。
めんどいので詳しくは説明しません。
ついでにWindows 11のCD-ROMデバイスも削除しておいてください。
ドライバーとゲストツールをインストールしてください。どうせWinAppsあるしいらないかもしれないけど
8. パフォーマンス最適化
- 「NIC」の「デバイスのモデル」を
virtioに変更 「ビデオ」の「モデル」をVirtioに変更- 「ハードウェアの追加」から「ストレージ」で新しく
VirtIOの「ディスクデバイス」を追加してください。私は1GBで試しましたが、100MBとかでも問題ないと思います。読めればいいので。
WindowsのVMを起動してログオンします。
デバイスマネージャー(devmgmt.msc)を開いて
- 「ディスクドライブ」に
Red Hat VirtIO SCSI Disk Device 「ディスプレイアダプター」にRed Hat VirtIO GPU DOD controller- 「ネットワークアダプター」に
Red Hat VirtIO Ethernet Adapter
があり、ドライバが当たっていることを確認します。
追加した「VirtIOディスク」を削除し、/dev/md0のディスクを「SATAディスク」から「VirtIOディスク」に置き換えます。
接続方法が選択できるわけではないので、削除して追加します。
WindowsのVMが起動して描画されることを確認します。
WinAppsをいれる
設定 > システム > リモートデスクトップ
で「リモートデスクトップ」を有効化します。
VMの名前をRDPWindowsに変更する。
チャンネルのorg.qemu.guest_agent.0 Unixを追加する。
メモリの現在割当を1024MBにする
<clock>を以下に書き換える
<clock offset='localtime'>
<timer name='rtc' present='no' tickpolicy='catchup'/>
<timer name='pit' present='no' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
<timer name='kvmclock' present='no'/>
<timer name='hypervclock' present='yes'/>
</clock>
<hyperv>をこれに書き換える
<hyperv mode="custom">
<relaxed state="on"/>
<vapic state="on"/>
<spinlocks state="on" retries="8191"/>
<vpindex state="on"/>
<runtime state="on"/>
<synic state="on"/>
<stimer state='on'>
<direct state='on'/>
</stimer>
<reset state='on'/>
<frequencies state="on"/>
<reenlightenment state='on'/>
<tlbflush state="on"/>
<ipi state="on"/>
<evmcs state="on"/>
<avic state="on"/>
</hyperv>
echo 'LIBVIRT_DEFAULT_URI="qemu:///system"' | sudo tee -a /etc/environment
# または
echo 'export LIBVIRT_DEFAULT_URI="qemu:///system"' >> ~/.zshrc
# .zshrc は各自のファイルに書き換えてください
再起動するか、
export LIBVIRT_DEFAULT_URI="qemu:///system"
をやって
virsh qemu-agent-command RDPWindows '{"execute":"guest-get-osinfo"}' --pretty
を実行して
{
"return": {
"name": "Microsoft Windows",
"kernel-release": "26200",
"version": "Microsoft Windows 11",
"variant": "client",
"pretty-name": "Windows 10 Pro",
"version-id": "11",
"variant-id": "client",
"kernel-version": "10.0",
"machine": "x86_64",
"id": "mswindows"
}
}
が出たら成功。
RDPApps.reg
install.bat
NetProfileCleanup
をWindows VMで実行します。
VMを再起動して、
絶対にVMでログオンしないこと
Windowsにログオンしたいときは通常通りWindowsを起動してください。
あと、Windowsのパーティションを絶対にマウントしないでください。
NTFSが死んでWindowsが起動できなくなります。
以下の項目を変更する
RDP_USER = "<ユーザー名>"
RDP_PASS = "<ユーザーパスワード>"
RDP_IP = ""
VM_NAME = RDPWindows (RDPWindows以外にしたならそれを)
WAFLAVOR = libvirt
このコマンドを実行して表示される手順に従えばインストールされます。
bash <(curl https://raw.githubusercontent.com/winapps-org/winapps/main/setup.sh)
日本語設定だと動かないっぽいです。
が、
設定 > 時刻と言語 > 言語と地域 > システムロケールの変更 > ベータ:ワールドワイド言語サポートでUnicode UTF-8を使用
にチェックを入れて再起動すると機能します。
TODO: 続きを書く
参考
Gemini
Discussion