Configuration is supported by either process ENV variables or with YAML config file. For very quick & simple setups ENV vars might be sufficient, YAML otherwise.
If a YAML file is found, all process env variables are ignored.
-
PO_TFTP_SERVER_DIR_PATH
: Path to the local directory to be served by the TFTP service. Optional and if not supplied, it is expected thatPO_TFTP_SERVER_IPV4
will be given instead to use an external TFTP server.When this option is configured, it activates the TFTP service at port 69 on the configured
PO_IFACES
and the specified directory in read only mode. No remote changes are allowed but⚠️ the directory becomes accessible to any client connecting⚠️ . TFTP doesn't support authentication. -
PO_TFTP_SERVER_IPV4
: IPv4 of the running Trivial File Transfer Protocol (TFTP) boot server. Only necessary when using a separate TFTP server. If not specified, a TFTP service will be started, indicating its own IP to the booting clients to reach the service. If this has a value, the TFTP service is disabled. -
PO_BOOT_FILE
: The UNIX path to the file to be executed at boot time from within the TFTP service. The boot file path is relative to the directory of the TFTP service. If the file is at/tmp/boot/file.bin
on the local disk and the TFTP service is configured to serve from/tmp/boot
then theboot_file
specified should be justfile.bin
. Parameter is required. -
PO_LOG_LEVEL
: Filter and verbosity level for output tostdout
.Syntax:
<component>
=level
.Example:
PO_LOG_LEVEL=preboot_oxide=info
Allows setting log level to Preboot Oxide and its dependencies. The supported levels are: error, warn, info, debug, trace.
Example:
PO_LOG_LEVEL=preboot_oxide=info
, for even more verbose output:PO_LOG_LEVEL=trace
.Default:
error
. -
PO_IFACES
: Comma separated names of the network interfaces the program should listen on. Example:PO_IFACES=enp0s3,enp0s8
. Optional, unless specified, it will listen on all network interfaces. -
PO_CONF_PATH
: Path for overriding the default YAML configuration file. -
PO_MAX_SESSIONS
: Optional number of maximum concurrent sessions to be allowed. Defaults to 500, used to protect against flood filling the system memory.
Specifying ENV variables can be achieved in a number of ways depending on the OS and how the executable is ran. Some examples:
👉 Simple CLI invocation:
PO_TFTP_SERVER_DIR_PATH=/dir/hosting/the/boot/files PO_BOOT_FILE=/path/to/the/bootable/image preboot-oxide
👉 .env
file in the same directory as the executable
content="
PO_TFTP_SERVER_DIR_PATH=/dir/hosting/the/boot/files
PO_BOOT_FILE=/the/bootable/image
"
echo "$content" > ./target/release/.env
# and run
./target/release/preboot-oxide
👉 OS-level, useful when running as a service, it will depend on the OS used - for most Linux distros it is possible by adding the variables to the /etc/environment
file
In short, YAML is a static configuration format similar to JSON that uses tabs instead of braces ({}
). Simple tutorial.
The YAML content is loaded from PO_CONF_PATH
env variable or from ~/.config/preboot-oxide/preboot-oxide.yaml
. There is a sample file at the project root here, reading on is recommended for a better understanding.
This .yaml file config will override process ENV variables. When running as service with systemd
, the location will correspond to the root
user at /root/.config/preboot-oxide/preboot-oxide.yaml
. It is possible to override the path using the PO_CONF_PATH
env variable. This SO answer describes how to set env variables for systemd services.
Conceptually, all PXE booting devices require only two parameters. The path of the executable file to run at boot time and where to get that file from. The first is a Unix style path, the 2nd is an IPv4 address where the Trivial File Transfer Protocol (TFTP) service is available to serve the file.
The configuration is split between global vs client specific sections. The global section applies to the boot server generally, such as what network cards to use or where are the files for booting. The client sections define the boot file and the TFTP IP. Here are a few examples:
tftp_server_dir: /where/the/boot/files/are
# if given, the TFTP service will be started and serve this path
# if not given, it is expected that a boot_server_ipv4 is given instead
# this section defines the boot file and server to be used by all clients
default:
boot_file: /the/boot/file.efi
# that's it, place this in ~/.config/preboot-oxide/preboot-oxide.yaml
tftp_server_dir: /where/the/boot/files/are
match:
# device #1
- select:
ClientMacAddress: 08:00:27:E7:DE:FE # this can also be lowercase
conf:
boot_file: /path/to/bootfile.efi
# device #2
- select:
ClientMacAddress: 01:02:03:04:05:06
conf:
boot_file: /other/path/to/bootfile.efi
# any other client will be ignored
tftp_server_dir: /where/the/boot/files/are
default:
# by default we will use this
boot_file: /path/for/all/clients.bin
match:
# however for this client only
- select:
ClientMacAddress: 08:00:27:E7:DE:FE
# is given this
conf:
boot_file: /path/to/bootfile.efi
boot_server_ipv4: 1.2.3.4
When overriding for a specific client, we can specify either boot_file
or the boot_server_ipv4
or both. If any is not given, the ones in default
will be used. Thus in the example above, client 08:00:27:E7:DE:FE
will be told to contact server 1.2.3.4
via TFTP and use /path/to/bootfile.efi
instead.
tftp_server_dir: /where/the/boot/files/are
match:
# UEFI aarch64 (ARM)
- select:
ClassIdentifier: Arch:00011
regex: true # the value above is treated as a regular expression
conf:
boot_file: /path/to/arm64/uefi.efi
# UEFI amd64 or x86
- select:
ClassIdentifier: Arch:0000[6-7]
regex: true
conf:
boot_file: /path/to/uefi.efi
The list of standardized archtectures is here.
# tftp_server_dir: /where/the/boot/files/are
# commenting this out will disable TFTP service
default:
boot_file: /path/to/bootfile.efi
boot_server_ipv4: 12.34.56.78 # for all clients
match:
- select:
ClientMacAddress: 08:00:27:E7:DE:FE
conf:
boot_file: /path/to/bootfile.efi
boot_server_ipv4: 123.45.67.89 # different TFTP for this client
or just override the boot file but use the same TFTP server
default:
boot_file: /path/to/x86-bios.bin
boot_server_ipv4: 12.34.56.78
match:
- select:
ClientMacAddress: 00:01:02:03:04:05
conf:
boot_file: /path/to/x86-uefi.efi # this client boots UEFI
ifaces:
- enp0s3
- enp0s8
default:
boot_file: /path/for/all/clients.bin
boot_server_ipv4: 12.34.56.78
-
ifaces
: List of network interfaces for listening. Ex:ifaces: - enp0s3 - enp0s8
-
tftp_server_dir
: Path to the local directory to be served by the TFTP service.tftp_server_dir: /where/the/boot/files/are
Optional, if not given, it is expected that
boot_server_ipv4
will be given instead to use an external TFTP server.When this option is configured, it activates the TFTP service at port 69 on the configured
ifaces
and the specified directory in read only mode. No remote changes are allowed but⚠️ the directory becomes accessible to any client connecting⚠️ . TFTP doesn't support authentication. -
boot_file
: The UNIX path to the file to be executed at boot time from within the TFTP service. The boot file path is relative to the directory of the TFTP service. If the file is at/tmp/boot/file.bin
on the local disk and the TFTP service is configured to serve from/tmp/boot
then theboot_file
specified should be justfile.bin
. -
boot_server_ipv4
: IPv4 address of TFTP service, for when it is desirable to use an external TFTP service. If not specified, a TFTP service will be started, serving files from the specifiedtftp_server_dir
. -
default
: Holds theboot_file
and, optionally,boot_server_ipv4
to provide to the booting client devices.boot_server_ipv4
. -
max_sessions
: Optional, defaults to 500. Represents the maximum number of allowed sessions at the same time. A session starts when an OFFER message is seen from DHCP to the booting client and ends when either the client ACKed or refused the request. Sessions older than 3 minutes are automatically removed. This is used to prevent filling the system memory in case of a flood of DHCP messages on the network. -
match
: List of entries to match, optional. Subfields:-
select
: List of fields and values to match. Unlessregex
istrue
, the matching is done by value, case insensitive.-
Supported fields:
ClientMacAddress ClassIdentifier HardwareType ClientSystemArchitecture RequestedIpAddress ServerIdentifier
-
Example:
match: - select: ClassIdentifier: PXEClient:Arch:00007:UNDI:003000 ClientMacAddress: 08:00:27:be:d8:91 HardwareType: eth ...etc conf: boot_file: debian-installer/amd64/bootnetx64.efi
-
-
regex
:true
orfalse
. Whentrue
, the value of theselect
field will be interpreted as a regular expression. The engine used can be tested with https://regex101.com/ (select Rust from the Flavor on the left). -
conf
: The resulting config when the client matched theselect
. Subfields:boot_file
: Same as above. If not specified, theboot_file
in thedefault
section will be usedboot_server_ipv4
: Same as above. If not specified theboot_server_ipv4
will be used. Ifdefault
doesn't specify aboot_server_ipv4
either, it is expected to set a path intftp_server_dir
and clients will be instructed to use the included TFTP service.
-
match_type
:all
orany
. Forany
, if any of theselect
field-values match, the entry is considered a match. Forall
, all field-values inselect
have to match. In both cases, the first matching entry in the order of definition is used, thus it is best to declare the more specific matches first.
-
The best way to troubleshoot configuration issues is to inspect the output of preboot-oxide
. By default only hard errors are printed however we can activate the trace
log level to get a view on the internal logic of the booting process. This is possible by starting preboot-oxide
with the PO_LOG_LEVEL
environment variable. Depending on how it was installed, here are the two options:
We can add ENV variables to systemd processes by:
sudo systemctl edit preboot-oxide
The above should open an editor to the override.conf
for the service. In the file we add the environment definition:
[Service]
Environment="PO_LOG_LEVEL=preboot_oxide::conf=trace"
We should end up with something like this:
### Editing /etc/systemd/system/preboot-oxide.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file
[Service]
Environment="PO_LOG_LEVEL=preboot_oxide::conf=trace"
### Lines below this comment will be discarded
### /lib/systemd/system/preboot-oxide.service
# [Unit]
# Description=PXE Boot server
# After=network.target
# Wants=
#
# [Service]
# Restart=always
# Type=simple
# ExecStart=/bin/preboot-oxide
# Environment=
#
# [Install]
# WantedBy=multi-user.target
Save the file, restart the service and open the logs in follow mode:
sudo systemctl restart preboot-oxide
sudo journalctl -f -u preboot-oxide # starts the logging in -f follow mode
Now that output logs are in trace
mode and they are followed, the network boot from the client device can be started which should result like those in Example trace logs.
It is possible to see what the clients are reporting this way and configure accordingly.
The preboot-oxide process should be started with PO_LOG_LEVEL
environment variable having the value preboot_oxide::conf=trace
. Check the OS/shell manual on how to specify environment variables to processes.
Once the started, the process will output logs as seen in Example trace logs.
When a match was found:
2024-06-06T14:56:54.454Z TRACE preboot_oxide::conf > Matching regex field ClassIdentifier="PXEClient:Arch:00007:UNDI:003000" to "Arch:00007", matching = true
2024-06-06T14:56:54.454Z TRACE preboot_oxide::conf > Found matching entry from 'match' rule.
ConfEntry {
boot_file: Some(
"/this/specific/client",
),
boot_server_ipv4: None,
}
2024-06-06T14:56:54.454Z TRACE preboot_oxide::conf > Final result combined with default:
ConfEntry {
boot_file: Some(
"/this/specific/client",
),
boot_server_ipv4: None,
}
2024-06-06T14:56:58.071Z TRACE preboot_oxide::conf > Matching regex field ClassIdentifier="PXEClient:Arch:00007:UNDI:003000" to "Arch:00007", matching = true
2024-06-06T14:56:58.071Z TRACE preboot_oxide::conf > Found matching entry from 'match' rule.
When a match was not found
2024-06-06T15:36:21.363Z TRACE preboot_oxide::conf > Matching regex field ClassIdentifier="PXEClient:Arch:00007:UNDI:003000" to "Arch:00009", matching = false
2024-06-06T15:36:21.363Z TRACE preboot_oxide::conf > No matching entry found from 'match' rule.