{% extends "ui/_layout.html" %} {% block title %}Netboot artifacts - bty-web{% endblock %} {% block subnav %} {% set right_html %}{{ boot_root }}{% endset %} {% with sections=[ {"key": "list", "label": "List", "icon": "list-ul", "href": "/ui/boot"}, {"key": "fetch", "label": "Fetch netboot artifacts", "icon": "cloud-download", "href": "/ui/boot?section=fetch"}, {"key": "dhcp-pxe", "label": "DHCP / PXE", "icon": "hdd-network", "href": "/ui/boot?section=dhcp-pxe"}, {"key": "tftp", "label": "TFTP daemon", "icon": "cpu", "href": "/ui/boot?section=tftp"}, ] , active=section, right_html=right_html %} {% include "ui/_subnav.html" %} {% endwith %} {% endblock %} {% block intro %} {% from "ui/_intro_box.html" import render as intro_box %} {% call intro_box() %} The bty live env that PXE clients chain into when their assignment has boot_policy=flash. Until these files are present, machines with boot_policy=flash cannot actually flash. Click Fetch netboot artifacts to populate. {% endcall %} {% endblock %} {% block content %} {% if section == "fetch" %}
Fetch from GitHub releases

Pulls vmlinuz + initrd + squashfs + sha256 from {{ release_repo }}, verifies the manifest, and atomically installs into {{ boot_root }}.

latest resolves through GitHub's redirect to the most recent release.
{# Active + recent fetches live alongside the fetch form so the operator who just clicked "Fetch" sees progress without leaving the page. #}
Active + recent fetches refreshing...
Tag Status Progress Started Action
Loading...
{% elif section == "dhcp-pxe" %} {# Router-side cheatsheet. The bits the operator pastes into UniFi / pfSense / dnsmasq DHCP config to point PXE clients at this appliance. Reference-only; no editable fields here -- bty doesn't run DHCP, the LAN router does. #}

DHCP / PXE

bty-server runs a TFTP daemon (dnsmasq) and serves boot artefacts over HTTP. The DHCP side stays with your LAN's router (or DHCP server); bty deliberately doesn't try to replace it. Point your router at this appliance with the settings below.

{% if missing_netboot_artifacts %}
Netboot environment incomplete. Missing under {{ boot_root }}: {% for name in missing_netboot_artifacts %} {{ name }}{% if not loop.last %}, {% endif %} {% endfor %}. PXE clients will chain into iPXE but get 404 on the kernel fetch until these files are present.
Fetch latest
{% endif %}

This appliance

{% for iface in interfaces %} {% else %} {% endfor %}
Interface State IPv4
{{ iface.name }} {{ iface.operstate }} {% if iface.ipv4 %} {{ iface.ipv4 }}/{{ iface.prefix }} {% else %} (no address) {% endif %}
(no interfaces detected)

Router-side configuration

Configure your LAN's DHCP server to tag PXE clients with the options below. For UniFi: Settings → Networks → [your LAN] → Advanced → DHCP → Network Boot. For pfSense / OpenWRT / dnsmasq: equivalent options on the DHCP service.

Option Value Notes
option 60 PXEClient Vendor-class echo. Strict UEFI firmware filters offers without it.
option 66 / Next-Server {% if primary and primary.ipv4 %} {{ primary.ipv4 }} {% else %} (this appliance's LAN IP) {% endif %} The TFTP server. Same box as bty-web.
option 67 / Boot-Filename ipxe.efi For UEFI PXEClient (arch 6/7/9). Use undionly.kpxe for legacy BIOS (arch 0).
option 67 for user-class=iPXE http://{% if primary and primary.ipv4 %}{{ primary.ipv4 }}{% else %}<bty-server>{% endif %}:8080/pxe-bootstrap.ipxe Stops iPXE chain-loop. Different bootfile when iPXE re-DHCPs.

For UEFI HTTP-Boot (vendor-class HTTPClient), point option 67 at http://{% if primary and primary.ipv4 %}{{ primary.ipv4 }}{% else %}<bty-server>{% endif %}:8080/boot/ipxe.efi instead (no TFTP roundtrip).

{% elif section == "tftp" %} {# Local dnsmasq.service state + start/stop/restart. The "take PXE offline briefly" knob, separate from the cheatsheet because most operators never touch it. #}

TFTP daemon

The local dnsmasq.service serves the TFTP root (/var/lib/tftpboot). Stop it to take PXE offline without disabling DHCP; restart it to pick up new bootfiles staged into the TFTP root.

{% if tftp.state == 'active' %} {{ tftp.state }} {% elif tftp.state == 'failed' %} {{ tftp.state }} {% elif tftp.state in ('activating', 'deactivating', 'reloading') %} {{ tftp.state }} {% else %} {{ tftp.state }} {% endif %} dnsmasq.service
{% if tftp_controllable %}
{% else %} Controls disabled (no daemon helper here) {% endif %}
{% else %} {# section == "list" (default): present/missing per-artefact + live fetch table. Operators land on the OBSERVABLE boot state when they click "Netboot" in the top nav. The single Fetch flow is one sub-nav click away. #}
{% for a in artifacts %} {% endfor %}
File Status Size Last fetched
{{ a.name }} {% if a.present %} present {% else %} missing {% endif %} {% if a.size is not none %} {{ "{:,}".format(a.size) }} bytes {% else %} - {% endif %} {% if a.mtime %} {{ a.mtime }} {% else %} - {% endif %}
{% endif %} {# Recent activity for boot artefacts: release fetches + fetch failures via the per-subject events card. On the default list view only -- the DHCP / TFTP sections have their own focused content and the events log link in the top nav covers the cross-section view. #} {% if section in ("list", "fetch") %} {% with events=boot_events, title="Recent netboot activity", link_to_full="/ui/events?subject_kind=boot" %} {% include "ui/_events_card.html" %} {% endwith %} {% endif %} {% endblock %}