Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add proxy-DHCP support #73

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,27 @@

## 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/).

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

Expand Down Expand Up @@ -59,11 +60,14 @@ 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.` \
-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
```
Expand Down Expand Up @@ -96,13 +100,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

Expand All @@ -117,16 +121,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. 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

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

Expand Down Expand Up @@ -195,3 +202,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 |
```
4 changes: 4 additions & 0 deletions docker-compose.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -16,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).
66 changes: 66 additions & 0 deletions root/defaults/dnsmasq-dhcpproxy.conf
Original file line number Diff line number Diff line change
@@ -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}
5 changes: 5 additions & 0 deletions root/defaults/dnsmasq.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# TFTP config
enable-tftp
user=nbxyz
tftp-secure
tftp-root=/config/menus
2 changes: 1 addition & 1 deletion root/etc/supervisor.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 21 additions & 4 deletions root/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,32 @@ 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 </defaults/default >/config/nginx/site-confs/default

# 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 </defaults/dnsmasq-dhcpproxy.conf >>/config/dnsmasq/dnsmasq.conf
fi
fi

# Ownership
chown -R nbxyz:nbxyz /assets
Expand Down Expand Up @@ -67,7 +84,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
Expand Down