{% extends "ui/_layout.html" %} {% block title %}Netboot artifacts - bty-web{% endblock %} {% block subnav %} {% with sections=[ {"key": "list", "label": "List", "icon": "list-ul", "href": "/ui/boot"}, {"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 %} {% 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. Use the Fetch control in the table header below (tag defaults to latest) to populate them from GitHub releases. {% endcall %} {% endblock %} {% block content %} {% if 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 artifacts 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): the netboot artifacts table, with the Fetch control (tag input, default "latest") inline in its header -- List and Fetch are merged into one view, like the Catalog. Live fetch activity shows in the top-nav indicator. #}
Netboot artifacts {# The release tag is an editable magic value (Settings -> Upstream sources); the button just fetches whatever it resolves to. #}
{% for a in artifacts %} {% endfor %}
File Status Size SHA256 Last fetched Action
{{ a.name }} {% if a.present %} present {% else %} missing {% endif %} {% if a.size is not none %} {{ "{:,}".format(a.size) }} bytes {% else %} - {% endif %} {% set sha = artifact_shas.get(a.name) %} {% if sha %} {{ sha[:12] }}... {% else %} - {% endif %} {% if a.mtime %} {{ a.mtime | fmt_ts }} {% else %} - {% endif %} {% if a.present %} {% else %} - {% endif %}
{# Live release-fetch jobs: active (queued / running) + previous (completed / failed, backfilled from events on restart). Polls GET /boot/releases, the same endpoint the top-nav worker indicator counts. Mirrors the Images -> Downloads jobs table. #}
Release fetches refreshing...
Tag Status Progress Bytes Action
No fetches yet.
{% endif %} {# Recent activity for boot artifacts: 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 %}