From 25ef084bd057e049c766d44159e85cad0eba5cd2 Mon Sep 17 00:00:00 2001 From: Robert Coleman <154176+rjocoleman@users.noreply.github.com> Date: Thu, 10 Oct 2024 23:25:06 +1300 Subject: [PATCH 1/3] use a config file for dnsmasq --- root/defaults/dnsmasq.conf | 5 +++++ root/etc/supervisor.conf | 2 +- root/init.sh | 14 ++++++++++---- 3 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 root/defaults/dnsmasq.conf diff --git a/root/defaults/dnsmasq.conf b/root/defaults/dnsmasq.conf new file mode 100644 index 0000000..8b5f16e --- /dev/null +++ b/root/defaults/dnsmasq.conf @@ -0,0 +1,5 @@ +# TFTP config +enable-tftp +user=nbxyz +tftp-secure +tftp-root=/config/menus diff --git a/root/etc/supervisor.conf b/root/etc/supervisor.conf index 142e043..7fbe308 100644 --- a/root/etc/supervisor.conf +++ b/root/etc/supervisor.conf @@ -22,7 +22,7 @@ directory=/app priority = 3 [program:dnsmasq] -command=/usr/sbin/dnsmasq --port=0 --keep-in-foreground --enable-tftp --user=nbxyz --tftp-secure --tftp-root=/config/menus %(ENV_TFTPD_OPTS)s +command=/usr/sbin/dnsmasq --conf-file=/config/dnsmasq/dnsmasq.conf --port=0 --keep-in-foreground %(ENV_TFTPD_OPTS)s stdout_logfile=/config/tftpd.log redirect_stderr=true priority = 4 diff --git a/root/init.sh b/root/init.sh index 2eec0d7..b777e51 100755 --- a/root/init.sh +++ b/root/init.sh @@ -5,15 +5,21 @@ mkdir -p \ /assets \ /config/nginx/site-confs \ /config/log/nginx \ + /config/dnsmasq \ /run \ /var/lib/nginx/tmp/client_body \ /var/tmp/nginx # copy config files -[[ ! -f /config/nginx/nginx.conf ]] && \ +[[ ! -f /config/nginx/nginx.conf ]] && cp /defaults/nginx.conf /config/nginx/nginx.conf -[[ ! -f /config/nginx/site-confs/default ]] && \ - envsubst < /defaults/default > /config/nginx/site-confs/default +[[ ! -f /config/nginx/site-confs/default ]] && + envsubst /config/nginx/site-confs/default + +# create dnsmasq config +if [[ ! -f /config/dnsmasq/dnsmasq.conf ]]; then + cp /defaults/dnsmasq.conf /config/dnsmasq/dnsmasq.conf +fi # Ownership chown -R nbxyz:nbxyz /assets @@ -67,7 +73,7 @@ if [[ ! -f /config/menus/remote/menu.ipxe ]]; then /config/menus/remote/netboot.xyz-arm64-snponly.efi -sL \ "https://github.com/netbootxyz/netboot.xyz/releases/download/${MENU_VERSION}/netboot.xyz-arm64-snponly.efi" # layer and cleanup - echo -n "${MENU_VERSION}" > /config/menuversion.txt + echo -n "${MENU_VERSION}" >/config/menuversion.txt cp -r /config/menus/remote/* /config/menus rm -f /tmp/menus.tar.gz fi From f36963f39d27a2f15db060be4d1b4b243154501c Mon Sep 17 00:00:00 2001 From: Robert Coleman <154176+rjocoleman@users.noreply.github.com> Date: Thu, 10 Oct 2024 23:26:19 +1300 Subject: [PATCH 2/3] add proxy-DHCP support via dnsmasq --- README.md | 22 ++++++---- docker-compose.yml.example | 1 + root/defaults/dnsmasq-dhcpproxy.conf | 66 ++++++++++++++++++++++++++++ root/init.sh | 13 +++++- 4 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 root/defaults/dnsmasq-dhcpproxy.conf diff --git a/README.md b/README.md index ed3ea0c..d9a4acb 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,19 @@ ## Overview -The [netboot.xyz docker image](https://github.com/netbootxyz/docker-netbootxyz) allows you to easily set up a local instance of netboot.xyz. The container is a small helper application written in node.js. It provides a simple web interface for editing menus on the fly, retrieving the latest menu release of netboot.xyz, and enables mirroring the downloadable assets from Github to your location machine for faster booting of assets. +The [netboot.xyz docker image](https://github.com/netbootxyz/docker-netbootxyz) allows you to easily set up a local instance of netboot.xyz. The container is a small helper application written in node.js. It provides a simple web interface for editing menus on the fly, retrieving the latest menu release of netboot.xyz, and enables mirroring the downloadable assets from Github for faster booting of assets. ![netboot.xyz webapp](https://netboot.xyz/images/netboot.xyz-webapp.jpg) -It is a great tool for developing and testing custom changes to the menus. If you have a machine without an optical drive that cannot boot from USB then having a local netboot server provides a way to install an OS. If you are looking to get started with netboot.xyz and don't want to manage iPXE menus, you should use the boot media instead of setting up a container. +It is a great tool for developing and testing custom changes to the menus. If you have a machine without an optical drive that cannot boot from USB, then having a local netboot server provides a way to install an OS. If you are looking to get started with netboot.xyz and don't want to manage iPXE menus, you should use the boot media instead of setting up a container. The container is built upon Alpine Linux and contains several components: * netboot.xyz [webapp](https://github.com/netbootxyz/webapp) * Nginx for hosting local assets from the container -* tftp-hpa +* tftp server (dnsmasq) * syslog for providing tftp activity logs +* optional proxy-DHCP mode Services are managed in the container by [supervisord](http://supervisord.org/). @@ -25,7 +26,7 @@ The container runs fine under ARM-based hosts as well as x86-64. ## Usage -The netboot.xyz docker image requires an existing DHCP server to be setup and running in order to boot from it. The image does not contain a DHCP server service. Please see the DHCP configuration setup near the end of this document for ideas on how to enable your environment to talk to the container. In most cases, you will need to specify the next-server and boot file name in the DHCP configuration. Your DHCP server will need to be assigned a static IP. +The netboot.xyz docker image requires an existing DHCP server to be set up and running in order to boot from it by default. The image does not contain a full DHCP server service by default, but it **includes an optional proxy-DHCP mode**. Please see the DHCP configuration setup near the end of this document for ideas on how to enable your environment to talk to the container. In most cases, you will need to specify the next-server and boot file name in the DHCP configuration, or enable the proxy-DHCP mode. Your DHCP server will need to be assigned a static IP if using the default mode. ### Installing docker @@ -59,6 +60,7 @@ docker run -d \ -e MENU_VERSION=2.0.76 `# optional` \ -e NGINX_PORT=80 `# optional` \ -e WEB_APP_PORT=3000 `# optional` \ + -e DHCP_RANGE_START=192.168.0.1 `# optional, enables DHCP Proxy mode. set to your network's DHCP range first IP` \ -p 3000:3000 `# sets web configuration interface port, destination should match ${WEB_APP_PORT} variable above.` \ -p 69:69/udp `# sets tftp port` \ -p 8080:80 `# optional, destination should match ${NGINX_PORT} variable above.` \ @@ -96,13 +98,13 @@ docker compose up -d netbootxyz # start containers in the background Once the container is started, the netboot.xyz web application can be accessed by the web configuration interface at `http://localhost:3000` or via the specified port. -Downloaded web assets will be available at `http://localhost:8080` or the specified port. If you have specified the assets volume, the assets will be available at `http://localhost:8080`. +Downloaded web assets will be available at `http://localhost:8080` or the specified port. If you have specified the assets volume, the assets will be available at `http://localhost:8080`. If you wish to start over from scratch, you can remove the local configuration folders and upon restart of the container, it will load the default configurations. ### Local Mirror Access -If you want to pull the Live Images images down from your own mirror, modify the boot.cfg file and override the default `live_endpoint` setting from `https://github.com/netbootxyz` and set it to your deployment IP or domain, e.g. `http://192.168.0.50:8080`. It will then redirect asset download to the local location you set for assets on port `8080` and you can download the assets by using the local assets menu down to your local server. This can result in a much faster boot and load time. +If you want to pull the Live Images down from your own mirror, modify the boot.cfg file and override the default `live_endpoint` setting from `https://github.com/netbootxyz` and set it to your deployment IP or domain, e.g. `http://192.168.0.50:8080`. It will then redirect asset downloads to the local location you set for assets on port `8080` and you can download the assets using the local assets menu to your local server. This can result in a much faster boot and load time. ## Parameters @@ -117,16 +119,19 @@ Container images are configured using parameters passed at runtime (such as thos | `-e NGINX_PORT=80` | Specify a different port for NGINX service to listen on. | | `-e MENU_VERSION=2.0.76` | Specify a specific version of boot files you want to use from netboot.xyz (unset pulls latest) | | `-e TFTPD_OPTS='--tftp-single-port'` | Specify arguments for the TFTP server (this example makes TFTP send all data over port 69) | +| `-e DHCP_RANGE_START=192.168.0.1` | Optionally enables DHCP Proxy mode. Set to your network's DHCP range first IP | | `-v /config` | Storage for boot menu files and web application config | | `-v /assets` | Storage for netboot.xyz bootable assets (live CDs and other files) | ## DHCP Configurations -This image requires the usage of a DHCP server in order to function properly. If you have an existing DHCP server, usually you will need to make some small adjustments to make your DHCP server forward requests to the netboot.xyz container. You will need to typically set your `next-server` and `boot-file-name` parameters in the DHCP configuration. This tells DHCP to forward requests to the TFTP server and then select a boot file from the TFTP server. +This image requires the usage of a DHCP server in order to function properly, unless you enable the **optional proxy-DHCP mode**. If you have an existing DHCP server, you will need to make some small adjustments to forward requests to the netboot.xyz container. You will typically set your `next-server` and `boot-file-name` parameters in the DHCP configuration. This tells DHCP to forward requests to the TFTP server and then select a boot file from the TFTP server. + +If you prefer not to modify your existing DHCP server, you can enable the **proxy-DHCP mode** by setting the `DHCP_RANGE_START` environment variable to the first IP in your DHCP range (e.g. 192.168.1.1). This mode allows netboot.xyz to provide PXE boot configuration while your existing DHCP server continues to handle IP address assignment. ### Examples -These are a few configuration examples for setting up a DHCP server. The main configuration you will need to change are `next-server` and `filename/boot-file-name`. `Next-server` tells your client to check for a host running tftp and retrieve a boot file from there. Because the docker image is hosting a tftp server, the boot files are pulled from it and then it will attempt to load the iPXE configs directly from the host. You can then modify and adjust them to your needs. See [booting from TFTP](https://netboot.xyz/docs/booting/tftp/) for more information. +These are a few configuration examples for setting up a DHCP server. The main configuration you will need to change are `next-server` and `filename/boot-file-name`. `next-server` tells your client to check for a host running tftp and retrieve a boot file from there. Because the docker image is hosting a tftp server, the boot files are pulled from it and then it will attempt to load the iPXE configs directly from the host. You can then modify and adjust them to your needs. See [booting from TFTP](https://netboot.xyz/docs/booting/tftp/) for more information. #### isc-dhcp-server @@ -195,3 +200,4 @@ The following bootfile names can be set as the boot file in the DHCP configurati | `netboot.xyz-arm64-snp.efi` | UEFI w/ Simple Network Protocol, attempts to boot all net devices | | `netboot.xyz-arm64-snponly.efi` | UEFI w/ Simple Network Protocol, only boots from device chained from | | `netboot.xyz-rpi4-snp.efi` | UEFI for Raspberry Pi 4, attempts to boot all net devices | +``` diff --git a/docker-compose.yml.example b/docker-compose.yml.example index d67dd0f..f4247d6 100644 --- a/docker-compose.yml.example +++ b/docker-compose.yml.example @@ -8,6 +8,7 @@ services: - MENU_VERSION=2.0.47 # optional - NGINX_PORT=80 # optional - WEB_APP_PORT=3000 # optional + - DHCP_RANGE_START=192.168.0.1 # optional, enables DHCP Proxy mode. set to your network's DHCP range first IP volumes: - /path/to/config:/config # optional - /path/to/assets:/assets # optional diff --git a/root/defaults/dnsmasq-dhcpproxy.conf b/root/defaults/dnsmasq-dhcpproxy.conf new file mode 100644 index 0000000..2feef44 --- /dev/null +++ b/root/defaults/dnsmasq-dhcpproxy.conf @@ -0,0 +1,66 @@ +# Only used if DHCP_RANGE_START is set, requires ENV vars changed via envsubst +# DHCP Proxy range and enable verbose DHCP logging +dhcp-range=${DHCP_RANGE_START},proxy +log-dhcp +leasefile-ro + +# Prevents reusing servername and filename fields to avoid confusing old clients +dhcp-no-override + +# Disable multicast/broadcast discovery, and instruct client to download the boot file immediately +dhcp-option=vendor:PXEClient,6,2b + +# Based on logic in https://gist.github.com/robinsmidsrod/4008017 +# iPXE sends a 175 option, checking suboptions +dhcp-match=set:ipxe-http,175,19 +dhcp-match=set:ipxe-https,175,20 +dhcp-match=set:ipxe-menu,175,39 +# pcbios specific +dhcp-match=set:ipxe-pxe,175,33 +dhcp-match=set:ipxe-bzimage,175,24 +dhcp-match=set:ipxe-iscsi,175,17 +# efi specific +dhcp-match=set:ipxe-efi,175,36 +# combination +# set ipxe-ok tag if we have correct combination +# http && menu && iscsi ((pxe && bzimage) || efi) +tag-if=set:ipxe-ok,tag:ipxe-http,tag:ipxe-menu,tag:ipxe-iscsi,tag:ipxe-pxe,tag:ipxe-bzimage +tag-if=set:ipxe-ok,tag:ipxe-http,tag:ipxe-menu,tag:ipxe-iscsi,tag:ipxe-efi + +# Match BIOS PXE clients +dhcp-match=set:bios,60,PXEClient:Arch:00000 +# Match UEFI 32-bit PXE clients +dhcp-match=set:efi32,60,PXEClient:Arch:00002 +# Match UEFI 32-bit (variant 1) PXE clients +dhcp-match=set:efi32-1,60,PXEClient:Arch:00006 +# Match UEFI 64-bit PXE clients +dhcp-match=set:efi64,60,PXEClient:Arch:00007 +# Match UEFI 64-bit (variant 1) PXE clients +dhcp-match=set:efi64-1,60,PXEClient:Arch:00008 +# Match UEFI 64-bit (BC variant) PXE clients +dhcp-match=set:efi64-2,60,PXEClient:Arch:00009 +# Match ARM64 UEFI clients +dhcp-match=set:arm64-efi,60,PXEClient:Arch:0000A +# Match Raspberry Pi 4 (aarch64) architecture based on Option 60 (PXEClient vendor class) +dhcp-match=set:rpi4,60,PXEClient:Arch:00011:UNDI:003000 + +# Serve appropriate bootloaders for non-iPXE clients (initial PXE boot) +# Legacy BIOS (not iPXE) +pxe-service=tag:bios,tag:!ipxe-ok,X86PC,"Legacy BIOS",netboot.xyz-undionly.kpxe +# UEFI 32-bit (not iPXE) +pxe-service=tag:efi32,tag:!ipxe-ok,BC_EFI,"UEFI 32-bit",netboot.xyz.efi +# UEFI 64-bit (not iPXE) +pxe-service=tag:efi64,tag:!ipxe-ok,X86-64_EFI,"UEFI 64-bit",netboot.xyz.efi +# ARM64 UEFI (not iPXE) +pxe-service=tag:arm64-efi,tag:!ipxe-ok,ARM64_EFI,"ARM64 UEFI",netboot.xyz-arm64.efi +# Raspberry Pi Boot (using rpi4 tag, not iPXE) +pxe-service=tag:rpi4,tag:!ipxe-ok,0,"Raspberry Pi Boot",netboot.xyz-rpi4-snp.efi + +# DHCP Boot options for non-iPXE clients using envsubst for dynamic IP handling +dhcp-boot=tag:bios,netboot.xyz.kpxe,,${CONTAINER_IP} +dhcp-boot=tag:efi32,netboot.xyz.efi,,${CONTAINER_IP} +dhcp-boot=tag:efi32-1,netboot.xyz.efi,,${CONTAINER_IP} +dhcp-boot=tag:efi64,netboot.xyz.efi,,${CONTAINER_IP} +dhcp-boot=tag:efi64-1,netboot.xyz.efi,,${CONTAINER_IP} +dhcp-boot=tag:efi64-2,netboot.xyz.efi,,${CONTAINER_IP} +dhcp-boot=tag:rpi4,netboot.xyz-rpi4-snp.efi,,${CONTAINER_IP} diff --git a/root/init.sh b/root/init.sh index b777e51..addff58 100755 --- a/root/init.sh +++ b/root/init.sh @@ -16,9 +16,20 @@ mkdir -p \ [[ ! -f /config/nginx/site-confs/default ]] && envsubst /config/nginx/site-confs/default -# create dnsmasq config +# create dnsmasq config, and conditionally add DHCP proxy support if [[ ! -f /config/dnsmasq/dnsmasq.conf ]]; then cp /defaults/dnsmasq.conf /config/dnsmasq/dnsmasq.conf + + if [ -n "${DHCP_RANGE_START}" ]; then + echo "[netbootxyz-init] Enabling DHCP Proxy mode for DHCP_RANGE_START=${DHCP_RANGE_START}" + + # Get the container's IP address using hostname if not already set + if [ -z "${CONTAINER_IP}" ]; then + CONTAINER_IP=$(hostname -i) + export CONTAINER_IP + fi + envsubst >/config/dnsmasq/dnsmasq.conf + fi fi # Ownership From 17c18135977fd30bf8bdf48d38e9e7d61b311cb2 Mon Sep 17 00:00:00 2001 From: Robert Coleman <154176+rjocoleman@users.noreply.github.com> Date: Sun, 3 Nov 2024 09:43:38 +1300 Subject: [PATCH 3/3] Update docs and examples for ProxyDHCP required network modes --- README.md | 4 +++- docker-compose.yml.example | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d9a4acb..5d5f4a9 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ docker run -d \ -p 8080:80 `# optional, destination should match ${NGINX_PORT} variable above.` \ -v /local/path/to/config:/config `# optional` \ -v /local/path/to/assets:/assets `# optional` \ + --cap-add NET_ADMIN `# only required for DHCP Proxy mode` \ + --network host `# only required for DHCP Proxy mode` \ --restart unless-stopped \ ghcr.io/netbootxyz/netbootxyz ``` @@ -127,7 +129,7 @@ Container images are configured using parameters passed at runtime (such as thos This image requires the usage of a DHCP server in order to function properly, unless you enable the **optional proxy-DHCP mode**. If you have an existing DHCP server, you will need to make some small adjustments to forward requests to the netboot.xyz container. You will typically set your `next-server` and `boot-file-name` parameters in the DHCP configuration. This tells DHCP to forward requests to the TFTP server and then select a boot file from the TFTP server. -If you prefer not to modify your existing DHCP server, you can enable the **proxy-DHCP mode** by setting the `DHCP_RANGE_START` environment variable to the first IP in your DHCP range (e.g. 192.168.1.1). This mode allows netboot.xyz to provide PXE boot configuration while your existing DHCP server continues to handle IP address assignment. +If you prefer not to modify your existing DHCP server, you can enable the **proxy-DHCP mode** by setting the `DHCP_RANGE_START` environment variable to the first IP in your DHCP range (e.g. 192.168.1.1). This mode allows netboot.xyz to provide PXE boot configuration while your existing DHCP server continues to handle IP address assignment. This mode requires the docker (or docker compose) parameter `--cap-add NET_ADMIN` be added and for the container to be running directly on the network to see the DHCP messages, i.e. with network mode set to `host` or via `ipvlan`/`macvlan` or a bridge. ### Examples diff --git a/docker-compose.yml.example b/docker-compose.yml.example index f4247d6..d7eb50e 100644 --- a/docker-compose.yml.example +++ b/docker-compose.yml.example @@ -8,7 +8,7 @@ services: - MENU_VERSION=2.0.47 # optional - NGINX_PORT=80 # optional - WEB_APP_PORT=3000 # optional - - DHCP_RANGE_START=192.168.0.1 # optional, enables DHCP Proxy mode. set to your network's DHCP range first IP + - DHCP_RANGE_START=192.168.0.1 # optional, enables DHCP Proxy mode. set to your network's DHCP range first IP. volumes: - /path/to/config:/config # optional - /path/to/assets:/assets # optional @@ -17,3 +17,6 @@ services: - 69:69/udp - 8080:80 # optional, destination should match ${NGINX_PORT} variable above. restart: unless-stopped + # cap_add: + # - NET_ADMIN # required for DHCP Proxy mode. + # network_mode: host # required for DHCP Proxy mode - network mode host, (or ipvlan/macvlan or a bridge).