Windows10にPXEブートサーバをたてる

# 0. 概要

テクニカルサポート業務に就いている中野と申します。
同じ部署に中野が二人いるので、中野(明)と下の名前も付けて呼び分けられています。

本記事では、Python製のPXEブートサーバ PyPXEを使って、Windows 10 PCをPXEブートサーバにします。

作業は以下の流れです。

1. Pythonをインストールする
1. PyPXEをインストールする
1. PyPXEを起動する


# 1. Pythonをインストールする
PyPXEを実行できるようにするため、Pythonをインストールします。
本記事ではPythonインストールにembeddable packageを使用します。
embeddable packageはレジストリやPATHを書き換えないので、Windows環境への影響を小さくできます。

embeddable packageについては以下の記事を参考にさせていただきました。

https://qiita.com/mm_sys/items/1fd3a50a930dac3db299

## Python embeddable packageをダウンロードする

下記配布サイトからWindows embeddable package (64-bit)をクリックしてダウンロードします。
執筆時(2022/11/26)にダウンロードした際のファイル名はpython-3.11.0-embed-amd64.zipでした。

https://www.python.org/downloads/windows/



## ZIPファイルを展開する
ダウンロードしたzipを任意のフォルダに展開します。
本記事ではC:\pypxeを新規に作成して使用します。

## pythonXXX._pthファイルを編集する
c:\pypxe直下のpythonXXX.\_pthをメモ帳などで編集します。
XXXはPythonのバージョンが入ります。執筆時はpython311\_.pthでした。
編集内容ですが、#import siteのコメントを外します。
```python311_.pth
編集前
python311.zip
.

# Uncomment to run site.main() automatically
#import site
--------------------------------------------------
編集後
python311.zip
.

# Uncomment to run site.main() automatically
import site
```

## pipをインストールする

Powershellを開いて以下を実行します。

```Powershell.
cd c:\pypxe
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;
wget "https://bootstrap.pypa.io/get-pip.py" -O "get-pip.py"
```


続いてコマンドプロンプトを開いて以下を実行します。
```cmd.exe
C:\Users\nknkhr>cd \pypxe

C:\pypxe>.\python.exe .\get-pip.py
Collecting pip
  Using cached pip-22.3.1-py3-none-any.whl (2.1 MB)
Collecting setuptools
  Using cached setuptools-65.6.3-py3-none-any.whl (1.2 MB)
Collecting wheel
  Using cached wheel-0.38.4-py3-none-any.whl (36 kB)
Installing collected packages: wheel, setuptools, pip
  WARNING: The script wheel.exe is installed in 'C:\pypxe\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The scripts pip.exe, pip3.11.exe and pip3.exe are installed in 'C:\pypxe\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pip-22.3.1 setuptools-65.6.3 wheel-0.38.4
C:\pypxe>
```


# 2. PyPXEをインストールする

いよいよPyPXEをインストールします。

## PyPXEをダウンロードする

githubからPyPXEのリリース版 Source code (zip) をダウンロードします。
執筆時のバージョンはv1.8.4(PyPXE-1.8.4.zip)でした。

https://github.com/pypxe/PyPXE/releases

pipを使おうとしたのですがエラーで失敗したので、今回はソースコード版で進めます。


## PyPXEを展開する

ダウンロードしたPyPXE-1.8.4.zipを展開するとフォルダPyPXE-1.8.4があります。
このフォルダの中身をc:\pypxeに配置します。


## プログラムの一部を修正する

WindowsやWindows版Pythonの制限で、プログラムの一部が動きません。
エラーを避けるため以下の4行をコメントアウトします。(PyPXEのバージョンによって行は異なります)

C:\pypxe\pypxe\server.py 173-174行目
```diff_python
-        if os.getuid() != 0:
-            print(sys.stderr, '\nWARNING: Not root. Servers will probably fail to bind.\n')       
+        #if os.getuid() != 0:
+        #    print(sys.stderr, '\nWARNING: Not root. Servers will probably fail to bind.\n')       
```

C:\pypxe\pypxe\server.py 303-304行目
```diff_python
-            signal.signal(signal.SIGALRM, dhcp_export_leases)
-            signal.signal(signal.SIGHUP, dhcp_export_leases)
+            #signal.signal(signal.SIGALRM, dhcp_export_leases)
+            #signal.signal(signal.SIGHUP, dhcp_export_leases)
```


## Pythonの通信をファイアウォールで許可する

コマンドプロンプトから以下のようにPyPXEを実行します。
```cmd.exe
C:\Users\nknkhr>cd \pypxe

C:\pypxe>dir /B pypxe\server.py
server.py

C:\pypxe>.\python.exe -m pypxe.server 
```
すると以下のようにPythonの通信がファイアウォールにブロックされます。
「アクセスを許可する」をクリックして許可します。この作業は以降は必要ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77765/e0caf8a0-b81f-531a-6fe4-866e039c555c.png)

アクセス許可が終わったら、実行しているPyPXEはCTRL-Cで止めます。


# 3. PyPXEを起動する

## ブートクライアントを用意する

PyPXE起動のまえに、ブートクライアントを用意します。
PXEブートするコンピュータとして、PyPXEと同一PC上の仮想マシン(VirtualBox)を使用しました。
事前にVirtualBoxの設定で、ネットワークを「起動順序」の最上にします。
NICをブリッジ接続にしてホスト側Windows 10と通信できるようにしておきます。

また、仮想マシンの「EFIを有効化」をオフにしておきます。
今回UEFIモードではうまくPXE起動させられませんでした。今後の課題です。

## PyPXEに適切にオプションをつけて起動する

いよいよオプション指定をつけてPyPXEを起動します。

実行環境は以下の通りです。
| 情報 | 値 |
|:-:|:-:|
|PyPXEを実行しているPC(TFTPD/DHCPD)のアドレス| 192.168.0.99  |
|ルーターのアドレス   | 192.168.0.1 |
|ブートクライアント|同一PC上のVirtualBoxの仮想マシン(Legacy BIOS)|

 
コマンドプロンプトからPyPXEを実行した結果は以下の通り。コマンドラインでパラメータを指定しています。
各パラメータの意味は[PyPXEドキュメント](https://github.com/pypxe/PyPXE#readme)を参照してください。
なお、下記のコマンドラインは見やすさのため改行をいれていますが、実際に入力するときは一行で入力します。
```
C:\pypxe>.\python.exe -m pypxe.server --no-ipxe --debug all --dhcp --no-http --dhcp-server-ip 192.168.0.99 
           --dhcp-begin 192.168.0.200 --dhcp-end 192.168.0.210 --dhcp-subnet 255.255.255.0 
           --dhcp-router 192.168.0.1 --dhcp-broadcast 192.168.0.255  --dhcp-fileserver 192.168.0.99

2022-11-26 16:05:11,544 [INFO] PyPXE Starting TFTP server...
2022-11-26 16:05:11,544 [DEBUG] PyPXE.TFTP NOTICE: TFTP server started in debug mode. TFTP server is using the following:
2022-11-26 16:05:11,544 [DEBUG] PyPXE.TFTP Server IP: 0.0.0.0
2022-11-26 16:05:11,544 [DEBUG] PyPXE.TFTP Server Port: 69
2022-11-26 16:05:11,544 [DEBUG] PyPXE.TFTP Network Boot Directory: netboot
2022-11-26 16:05:11,545 [INFO] PyPXE Starting DHCP server...
2022-11-26 16:05:11,545 [DEBUG] PyPXE.DHCP NOTICE: DHCP server started in debug mode. DHCP server is using the following:
2022-11-26 16:05:11,545 [INFO] PyPXE.DHCP DHCP Server IP: 192.168.0.99
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP DHCP Server Port: 67
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP Lease Range: 192.168.0.200 - 192.168.0.210
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP Subnet Mask: 255.255.255.0
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP Router: 192.168.0.1
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP DNS Server: 8.8.8.8
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP Broadcast Address: 192.168.0.255
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP File Server IP: 192.168.0.99
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP File Name: pxelinux.0
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP ProxyDHCP Mode: False
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP Using iPXE: False
2022-11-26 16:05:11,546 [INFO] PyPXE.DHCP Using HTTP Server: False
2022-11-26 16:05:11,547 [INFO] PyPXE PyPXE successfully initialized and running!

```
仮想マシンを電源ONすると、DHCP + TFTP でpxelinuxが起動しました。
このあとPyPXE同梱のTiny Linuxの起動も確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77765/fd74c09c-5b9b-2f8b-709a-cc9b42aaabbd.png)

# まとめ
Python embeddable packageとPyPXEで、PXEブートサーバをWindows 10 PC上にたてることができました。