netboot
PXE provisioning management: describe your targets, images and DHCP zones in
config, and netboot renders each machine's boot artifacts and arms (or
disarms) DHCP for it as it enters and leaves the install. The command is
pixie (PXE is pronounced "pixie"); netboot is the engine it drives.
Documentation: https://jose-pr.github.io/netboot/.
Features
-
One config, every machine — targets (by hostname, MAC or IP), images (what to boot), DHCP zones (the network and its servers) and repos (where artifacts are served from), as layered YAML with
!include. -
Templates in any engine — a target's artifacts are found by MAC, then hostname, then IP, then the bare name, and rendered by tplx: Jinja and a
%{NAME}shell engine built in, mako, Liquid, Handlebars, Mustache, ERB and EPP behind extras, and a byte-exact copy for anything else. -
Four DHCP servers through dhcpctl, each imported only when a config names it:
Scheme Server Install dnsmasq://dnsmasq, hosts and options files nothing locally; netboot[ssh]forsftp://pathskea://,keas://ISC Kea control agent netboot[kea]dhcpd://ISC dhcpd over OMAPI netboot[dhcpd]windhcp://Windows DHCP, cmdlets or netsh nothing locally; netboot[ssh]/netboot[winrm]remotely -
Conditional options — an iPXE client can be served a different boot file from the ROM that chainloads it, as each server expresses that.
-
Completion that keeps the machine — a finished target can keep its reservation without the installer's boot options.
-
Hooks on every step — lookup, context building, DHCP options and the arm/disarm lifecycle each fire an event a hook can change.
Installation
pip install netboot[config] # the engine plus what `pixie` needs to read a config
| Extra | Enables |
|---|---|
netboot[config] |
YAML config loading for the CLI (pyyaml) |
netboot[dns] |
The dnspython resolver backend (without it hostname targets still resolve via the system/nslookup fallbacks) |
netboot[mako] |
*.mako templates (tplx[mako]) |
netboot[liquid] |
*.liquid templates (tplx[liquid]) |
netboot[handlebars] |
*.hbs / *.handlebars templates (tplx[handlebars]) |
netboot[mustache] |
*.mustache templates (tplx[mustache]) |
netboot[kea] |
The kea:// DHCP backend |
netboot[dhcpd] |
The dhcpd:// DHCP backend over OMAPI |
netboot[winrm] |
windhcp:// over WinRM |
netboot[ssh] |
windhcp:// over ssh, and dnsmasq:// with remote sftp:// paths and reload |
netboot[docs] |
Build the documentation site |
*.erb and *.epp templates need no extra, but do need ruby or puppet
installed: they render through the real program. TPLX_RUBY / TPLX_PUPPET
name it when it is not on PATH. Python 3.9 or later.
Quick start
config/pixie.yaml, which pixie finds in the working directory:
targets:
web01: {ip: 10.0.0.10, mac: "52:54:00:00:00:10", image: debian}
images:
debian:
template_path: [debian]
dhcp_options: {boot-file-name: pxelinux.0, next-server: 10.0.0.2}
dhcpzones:
lan:
network: 10.0.0.0/24
gateway: 10.0.0.1
dhcpservers:
- dnsmasq:///?hostsfile=/etc/dnsmasq.d/netboot/hosts/&optsfile=/etc/dnsmasq.d/netboot/opts/
config/templates/debian/boot.cfg.j2, which answers to boot.cfg:
default install
label install
kernel vmlinuz
append ip={{ target.ip }} hostname={{ target.hostname }}
pixie render web01 boot.cfg # what web01 would be served, from config/templates/debian/
pixie initiate web01 # arm DHCP for it
pixie complete web01 # disarm it once the install is done
The same from Python:
import anycfg
from netboot import Pixie
config = anycfg.load("config/pixie.yaml")
# The CLI defaults the template root to the config's directory; here it is given.
pixie = Pixie(templates=["config/templates"], **config)
target = pixie.lookup_target("web01")
ctx = pixie.make_context(target) # image + zone + target, and a renderer
print(ctx.render("boot.cfg"))
pixie.initialize(target) # arm DHCP
pixie.complete(target) # disarm it
A complete runnable setup — config, templates and a DHCP plugin that records
instead of arming — is in examples/.
Command line
pixie initiate <target> [--iscsi] # arm DHCP; hooks may render and run more
pixie complete <target> # disarm DHCP
pixie render <target> NAME... [--out DIR] # render artifacts, arming nothing
pixie dhcp-config [target] [--apply] [--as USER] # what the servers need set up once
A target is named by id, hostname, MAC or IP, or a unique hostname prefix.
Global options: -c/--config FILE, --baseconfig DIR (default ./config),
-l/--load-module M (import a plugin first), --cmdspath PATH (more
commands), -v/-q/--loglevel. Exit status 0 is success, 1 a target not
found or ambiguous, 2 a configuration that cannot be used, reported as one line.
API overview
| Module | Purpose |
|---|---|
netboot |
Pixie (the engine), PixieTarget, PixieImage, PixieContext, PixieEvent, the errors |
netboot.dhcp |
DHCP zones and what a target is served: DHCPZone, build_lease, reservation_for, arm, disarm |
netboot.content |
Repository and Resource: where artifacts are served from |
netboot.exceptions |
PixieError, PixieConfigError, PixieLookupError |
netboot.cli |
the pixie command line, main(argv=None, *, name=None) -> int; one class per command |
Extending
- Hooks. Pass
hooks=[...](callables or"module.func"import strings) toPixie(...), or list them underhooks:. Each hookf(event, netboot, value, kwargs) -> valueis called for everyPixieEventand returns the value to pass on. - DHCP backends. Subclass
dhcpctl.DHCPServerand register it withdhcpctl.register_backend(scheme, cls)from a--load-moduleplugin, or thedhcpctl.backendsentry point. A server URI says how to reach the server; what it tells a client comes from the zone, image and target. - Commands. A module with
register(parser, args)andrun(netboot, args, conf), or a duho class command, on--cmdspathis apixiecommand.
Development
python -m venv .venv/3.14
.venv/3.14/bin/pip install -e ".[dev,docs,config]" # Scripts/ on Windows
.venv/3.14/bin/python -m pytest -q -rs # the suite
.venv/3.14/bin/python -m black src tests benchmarks # formatter
.venv/3.14/bin/python -m mkdocs build --strict # docs
dev carries every library a test needs (the DHCP backends' and the template
engines'), so only the .erb/.epp tests skip, unless ruby/puppet are
installed; -rs shows what skipped. Develop on the latest Python and also run
the floor (3.9) before finishing a piece of work. More detail, plus the layout
and CI notes, in AGENTS.md.
Releasing
Tags and CHANGELOG.md use SemVer; pyproject.toml uses PEP 440. Pre-1.0 the
minor slot is reserved for breaking the documented API — additions and fixes are
patches. Pushing a v* tag runs test → build → GitHub release → PyPI and then
deploys the docs for that tag; the release body is scraped from the matching
## [x.y.z] changelog section.
License
MIT — see LICENSE.
Metadata
Release files for netboot 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| netboot-0.4.0.tar.gz | 132.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| netboot-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 193.6 kB
Release files / netboot-0.4.0.tar.gz
| Download URL | netboot-0.4.0.tar.gz |
|---|---|
| Size | 132.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
758c10cb4491f03904df11a8bb4be800b8ff0e0ce072ca7468c008fd3ab9ad21
|
|
BLAKE2b-256 checksum How to use checksums |
c57fffb074d18979821708c4c6644880639ece3bc4334a0633b67a6e6633bd31
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logRelease files / netboot-0.4.0-py3-none-any.whl
| Download URL | netboot-0.4.0-py3-none-any.whl |
|---|---|
| Size | 60.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e22c5c01ec1c45d26ae8d5d521cd76de5397a58dc1bfb56fc61bb51ab419059a
|
|
BLAKE2b-256 checksum How to use checksums |
0f90a8ec6440c04830d31e5514d75cf1feb07ce2b7c833d2395fb2361b86f6c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logSecurity for netboot 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for netboot-0.4.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.