Deployment guide

netboot.xyz

Overview

This image runs netboot.xyz 3.0.2 on Ubuntu 24.04 LTS. netboot.xyz is an open source network boot toolkit: an iPXE bootloader paired with a curated menu tree covering well over a hundred operating systems and utilities. Point a machine's network boot at this server, and it boots straight into a live desktop, a rescue shell, a disk utility or a full OS installer, with no USB media and no trip to the rack.

This image runs the official netboot.xyz local instance, which upstream ships only as a container. SecureAnyCloud packages it natively on Ubuntu 24.04 with real systemd units and no container layer. Running your own instance means that your machines boot from infrastructure you control and keep working when your internet link does not. You can also mirror the images you need locally, so provisioning runs at LAN speed instead of pulling gigabytes from the internet for every machine.

The appliance has two planes, and they deliberately have different security postures:

  • The management plane is the netboot.xyz web admin UI, which decides what your machines boot. It is authenticated, with a password generated uniquely on your VM's first boot.
  • The boot plane is TFTP on port 69/udp plus the menus and mirrored assets over HTTP. It is anonymous, because a machine that is powering on cannot present credentials. You scope it with your Azure network security group (NSG).

What you get:

  • netboot.xyz 3.0.2: the iPXE menu tree (104 menus) and all ten official bootloaders (BIOS, UEFI, Secure Boot, arm64 and legacy variants). Each bootloader is verified against a pinned sha256 at build time.
  • The netboot.xyz web application 0.7.6 on Node.js 22 LTS, bound to 127.0.0.1:3000 and reachable only through the authenticating reverse proxy
  • nginx on port 80, serving the admin UI at / behind HTTP Basic Auth, the boot menus at /menus/, the local asset mirror at /assets/, and an unauthenticated /healthz for Azure Load Balancer probes
  • dnsmasq serving TFTP only, on port 69/udp (its DNS listener is disabled)
  • netbootxyz-web.service, netbootxyz-tftp.service, nginx.service and a one-shot netbootxyz-firstboot.service, all enabled
  • A per-VM admin password, generated on first boot and written to /root/netbootxyz-credentials.txt, which only root can read. No shared or default login exists in the image
  • An Ubuntu 24.04 LTS base, patched at build time, with unattended security upgrades enabled
  • 24/7 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

Standard_B2s (2 vCPU / 4 GiB RAM) is the recommended size. If you plan to mirror many installer images locally, attach and mount a data disk for /assets. The image itself is small, but mirrored images are large.

Configure the NSG to allow inbound 22/tcp from your management network, 80/tcp from the networks that need the admin UI and HTTP boot, and 69/udp from the subnets whose machines will network boot. Do not expose 69/udp or 80/tcp to the internet. The boot plane is anonymous by design, so the NSG is what scopes it.

Network booting requires your clients to be on a network whose DHCP server you can configure, so that you can set next-server to this VM. The clients must also be in the same broadcast domain as that DHCP server. For this reason, deploy the appliance into the VNet that serves your machines, or reach it from on-premises over a VPN or ExpressRoute link.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for netboot.xyz by SecureAnyCloud, and select Create.

On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).

Select Review + create, then Create. After deployment, add the 69/udp TFTP rule, scoped to your client subnets.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:netbootxyz-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name netbootxyz \
  --image sac1647283583153:netbootxyz-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard
# Admin UI + HTTP boot, scoped to the networks that need it
az network nsg rule create --resource-group <your-rg> --nsg-name <your-nsg> \
  --name allow-http --priority 1010 --protocol Tcp --destination-port-ranges 80 \
  --source-address-prefixes <your-mgmt-cidr>
# TFTP for network boot, scoped to your client subnets
az network nsg rule create --resource-group <your-rg> --nsg-name <your-nsg> \
  --name allow-tftp --priority 1020 --protocol Udp --destination-port-ranges 69 \
  --source-address-prefixes <your-client-subnet-cidr>

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

Three services make up the appliance: the web admin application, the TFTP server and nginx. Confirm that all three are active and check what is listening.

Note the :3000 line. The admin application is bound to 127.0.0.1, not 0.0.0.0. This is deliberate: the admin UI can be reached only through nginx, which enforces authentication. Connecting to port 3000 directly cannot bypass it.

systemctl is-active netbootxyz-web netbootxyz-tftp nginx
sudo ss -tlnp | grep -E ':80 |:3000 '
sudo ss -ulnp | grep ':69 '

Expected output:

active active active LISTEN 0 511 127.0.0.1:3000 0.0.0.0:* users:(("node",pid=...)) LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=...)) LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=...)) UNCONN 0 0 0.0.0.0:69 0.0.0.0:* users:(("dnsmasq",pid=...)) UNCONN 0 0 [::]:69 [::]:* users:(("dnsmasq",pid=...))

Step 5 - Retrieve your per-VM admin password

Upstream, the netboot.xyz web application has no login of its own. That application decides which operating systems your machines boot, so this image puts it behind HTTP Basic Auth. The password is generated on your VM, on its first boot. Nothing in the image contains it, and no other VM shares it.

Read the password from the root-only credentials file:

sudo cat /root/netbootxyz-credentials.txt

Expected output (your password differs, because it is unique to your VM):

# netboot.xyz on Ubuntu 24.04 LTS (sac Azure Marketplace image)
#
# SECURE BY DEFAULT: the password below was generated on THIS VM at first boot and is
# unique to it. It is not baked into the image and no other VM shares it. netbootxyz_admin_user=admin netbootxyz_admin_password=<generated on your VM at first boot> NETBOOTXYZ_URL=http://<vm-ip>/

The file records the VM's own address. To reach the admin UI from your workstation, use the VM's public IP or DNS name.

Step 6 - Confirm the boot server is serving

The boot plane is what your machines actually talk to. Confirm that TFTP serves the iPXE bootloader, that the menus are reachable over HTTP for UEFI HTTP boot, and that the asset mirror answers:

curl -s -o /tmp/probe.kpxe tftp://127.0.0.1/netboot.xyz.kpxe -w 'tftp netboot.xyz.kpxe -> %{size_download} bytes\n' rm -f /tmp/probe.kpxe
curl -s -o /dev/null -w 'http /menus/menu.ipxe -> HTTP %{http_code}\n' http://127.0.0.1/menus/menu.ipxe
curl -s -o /dev/null -w 'http /assets/ -> HTTP %{http_code}\n' http://127.0.0.1/assets/ printf 'menu version: '; cat /config/menuversion.txt; printf '\niPXE menus: '; ls -1 /config/menus/*.ipxe | wc -l

Expected output:

tftp netboot.xyz.kpxe -> 410421 bytes http /menus/menu.ipxe -> HTTP 200 http /assets/ -> HTTP 200 menu version: 3.0.2 iPXE menus: 104

The /assets/ index is empty until you mirror something into it (Step 11). The boot menus work immediately regardless and pull from the official upstream mirrors.

Step 7 - Confirm the admin UI is protected

Prove that the authentication works. A request with no credentials must be rejected, and the per-VM password must be accepted. This example reads the password directly from the credentials file, which is also the pattern to use in your own scripts:

PW=$(sudo awk -F= '/^netbootxyz_admin_password=/{print $2; exit}' /root/netbootxyz-credentials.txt)
curl -s -o /dev/null -w 'admin UI, no credentials -> HTTP %{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w 'admin UI, with credentials -> HTTP %{http_code}\n' -u "admin:$PW" http://127.0.0.1/
curl -s -o /dev/null -w 'healthz (anonymous probe) -> HTTP %{http_code}\n' http://127.0.0.1/healthz

Expected output:

admin UI, no credentials -> HTTP 401 admin UI, with credentials -> HTTP 200 healthz (anonymous probe) -> HTTP 200

/healthz is intentionally anonymous, so that an Azure Load Balancer can probe the VM without credentials. It returns only the string ok and exposes nothing else.

Step 8 - Open the admin dashboard

Browse to http://<vm-public-ip>/ and sign in with admin and the password from Step 5. The dashboard reports the web application and menu versions, whether the menus are up to date, and the TFTP and web servers behind the appliance. On this image, those are dnsmasq and nginx, the native services that the image runs.

Step 9 - Browse the boot menus

Select Menus to see the iPXE menu tree. The sidebar lists every menu file shipped with release 3.0.2, one per operating system or utility family, plus boot.cfg, the global configuration that every menu reads. You can also create your own menu file here with Create New.

Step 10 - Edit a menu file

Select any file to open it in the built-in editor, which provides iPXE syntax highlighting. Select Save Config to write your changes. The key file is boot.cfg. It sets the site name, the boot timeout, live_endpoint (where live assets are pulled from) and the upstream distribution mirrors. Repoint it at your own mirror, as described in Step 11.

The editor saves your edits as local overrides, so your changes survive a menu upgrade. An upgrade replaces the remote menu tree, and your local files are layered back on top. Select Revert to drop an override and return to the shipped version.

Step 11 - Mirror boot assets locally

Select Local Assets. The left pane lists every asset that the 3.0.2 release knows about. The right pane lists what you have mirrored locally, which is empty on a fresh VM. Select the assets that you need and choose Pull Selected to download them into /assets on this VM. nginx serves them at /assets/.

Mirroring has two benefits. Your machines provision at LAN speed instead of pulling gigabytes across the internet each time, and they can boot even when your internet link is down. After mirroring, point live_endpoint in boot.cfg (Step 10) at http://<vm-ip>/assets so that the menus fetch from your mirror instead of from upstream.

Step 12 - Point your network at the boot server

Network boot is driven by DHCP, not by this VM. Your DHCP server tells clients where to fetch a bootloader. It uses next-server (the TFTP server address) and a filename that depends on the client's firmware:

  • Legacy BIOS: netboot.xyz.kpxe
  • Legacy BIOS, with USB keyboard issues: netboot.xyz-legacy.kpxe
  • UEFI x86_64: netboot.xyz.efi
  • UEFI x86_64 with Secure Boot: netboot.xyz-snponly.efi
  • UEFI arm64: netboot.xyz-arm64.efi

With ISC DHCP, the classic form is:

# /etc/dhcp/dhcpd.conf on YOUR DHCP server (not on this VM) next-server <netbootxyz-vm-ip>; if option arch = 00:07 or option arch = 00:09 { filename "netboot.xyz.efi";
# UEFI x86_64 } elsif option arch = 00:0b { filename "netboot.xyz-arm64.efi";
# UEFI arm64 } else { filename "netboot.xyz.kpxe";
# legacy BIOS }

With dnsmasq as your DHCP server:

# on YOUR DHCP server (not on this VM) dhcp-boot=netboot.xyz.kpxe,,<netbootxyz-vm-ip> dhcp-match=set:efi-x86_64,option:client-arch,7 dhcp-boot=tag:efi-x86_64,netboot.xyz.efi,,<netbootxyz-vm-ip>

Then set a client to boot from the network. The client fetches the bootloader over TFTP from this VM and chainloads the menu, and the netboot.xyz menu appears. Choose an entry to boot it.

If you cannot change DHCP, you can still use the appliance. Burn netboot.xyz.iso or write netboot.xyz.img to a USB stick from the netboot.xyz downloads, and set ${boot_domain} to this VM. This approach gives up the no-media benefit in exchange for leaving DHCP unchanged.

Security

  • Protect the admin UI. The admin UI controls what your machines boot, so treat it accordingly. It is protected with HTTP Basic Auth using a password unique to your VM, and the application is bound to loopback so that the authentication cannot be bypassed. Rotate the password whenever you need to with sudo htpasswd -B /etc/nginx/netbootxyz.htpasswd admin.
  • Encrypt web traffic. Basic Auth is only as private as the transport. Port 80 is plain HTTP, so credentials cross the network base64-encoded, not encrypted. For anything beyond a trusted VNet, front the VM with TLS, for example your own domain behind Azure Application Gateway or a TLS-terminating reverse proxy. Restrict port 80 in the NSG to the networks that need it.
  • Scope the boot plane. The boot plane is anonymous by design. TFTP has no authentication in the protocol at all, and a machine that is powering on cannot present a credential. 69/udp, /menus/ and /assets/ are therefore open to anyone who can reach them, and they serve only public installer artifacts. Your NSG is the control. Scope 69/udp to your client subnets and never expose it to the internet.
  • Know that iPXE signature checking is off on a local instance. The netboot.xyz web application sets sigs_enabled false in boot.cfg at startup, because locally mirrored assets are not signed by the netboot.xyz project. This is upstream's own behaviour for local instances, not a SecureAnyCloud change, and you can see it on line 17 of boot.cfg in Step 10. The integrity of what you boot therefore rests on the mirrors you point at and the network path to them, which is another reason to keep the boot plane on trusted networks.
  • Keep the VM patched. Unattended security upgrades are enabled, so the OS keeps itself patched. Reboot when a new kernel is installed.

Maintenance

  • Upgrading the menus. The dashboard reports when a newer netboot.xyz release is available and offers Upgrade Menus to latest. Your local menu overrides are layered back on top after an upgrade, so custom entries survive.
  • What to back up. /config holds your menu overrides and endpoints.yml, so back it up. /assets holds mirrored installer images, which you can download again, so they are usually not worth backing up.
  • Disk usage. Mirrored assets in /assets grow quickly. Watch usage with df -h /assets, and move the folder to a dedicated data disk if you mirror a lot.
  • Modifications. This image makes two documented changes to the upstream web application, both recorded in /opt/netbootxyz/SAC-CHANGES.txt as the Apache License 2.0 requires. The admin app is bound to loopback so that its authentication cannot be bypassed, and several dependencies are raised to versions that carry no known advisories.

Support

SecureAnyCloud provides 24/7/365 expert technical support for this image. Contact sales@secureanycloud.com.

netboot.xyz is licensed under the Apache License 2.0. SecureAnyCloud provides this image, which is not affiliated with or endorsed by the netboot.xyz project. Additional charges apply for build, maintenance and 24/7 support.

Deploy on Azure

Launch netboot.xyz on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure