{"id":15780209,"url":"https://github.com/rgl/pxe-raspberrypi-vagrant","last_synced_at":"2026-04-30T00:07:04.698Z","repository":{"id":139753225,"uuid":"230151531","full_name":"rgl/pxe-raspberrypi-vagrant","owner":"rgl","description":"pxe boot a raspberry pi","archived":false,"fork":false,"pushed_at":"2020-06-01T19:13:28.000Z","size":165,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-31T11:06:11.102Z","etag":null,"topics":["pxe","pxe-server","raspberry-pi","raspberrypi"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rgl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-25T20:44:01.000Z","updated_at":"2021-07-10T18:57:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"48c3bc56-489c-43c2-9e24-97b47a13805a","html_url":"https://github.com/rgl/pxe-raspberrypi-vagrant","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rgl/pxe-raspberrypi-vagrant","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rgl%2Fpxe-raspberrypi-vagrant","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rgl%2Fpxe-raspberrypi-vagrant/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rgl%2Fpxe-raspberrypi-vagrant/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rgl%2Fpxe-raspberrypi-vagrant/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rgl","download_url":"https://codeload.github.com/rgl/pxe-raspberrypi-vagrant/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rgl%2Fpxe-raspberrypi-vagrant/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32448889,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T22:27:22.272Z","status":"ssl_error","status_checked_at":"2026-04-29T22:10:49.234Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pxe","pxe-server","raspberry-pi","raspberrypi"],"created_at":"2024-10-04T18:40:52.677Z","updated_at":"2026-04-30T00:07:04.682Z","avatar_url":"https://github.com/rgl.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"This is a [Vagrant](https://www.vagrantup.com/) Environment for a [Preboot Execution Environment (PXE)](https://en.wikipedia.org/wiki/Preboot_Execution_Environment) gateway for Raspberry Pis.\n\n# Usage\n\nThis `gateway` environment is made with isc-dhcp-server (as the DHCP server) and atftpd (as the TFTP server.\n\nIn order for it to work you need to connect the `gateway` virtual network to a physical network that reaches the Raspberry Pis.\n\nI'm using Ubuntu 20.04 as the host, qemu/kvm/libvirt has the hypervisor, and a [tp-link tl-sg108e](https://www.tp-link.com/en/business-networking/easy-smart-switch/tl-sg108e/) switch.\n\nThe network is connected as:\n\n![](network.png)\n\nThe tp-link tl-sg108e switch is configured as:\n\n![](tp-link-sg108e-802-1q-vlan-configuration.png)\n![](tp-link-sg108e-802-1q-vlan-pvid-configuration.png)\n\n**NB** this line of switches is somewhat insecure as, at least, its configuration protocol (UDP port 29808 and TCP port 80) uses clear text messages. For more information see [How I can gain control of your TP-LINK home switch](https://www.pentestpartners.com/security-blog/how-i-can-gain-control-of-your-tp-link-home-switch/) and [Information disclosure vulnerability in TP-Link Easy Smart switches](https://www.chrisdcmoore.co.uk/post/tplink-easy-smart-switch-vulnerabilities/).\n\nThe host network is configured by netplan with `/etc/netplan/config.yaml` as:\n\n```yaml\nnetwork:\n  version: 2\n  renderer: networkd\n  ethernets:\n    enp3s0:\n      dhcp4: yes\n      nameservers:\n        # NB on ubuntu this normally uses the system-resolved dns resolver and\n        #    you can list the current upstream dns server addresses with:\n        #       systemd-resolve --status\n        addresses:\n          # cloudflare+apnic public dns resolvers.\n          # see https://en.wikipedia.org/wiki/1.1.1.1\n          - \"1.1.1.1\"\n          - \"1.0.0.1\"\n          # google public dns resolvers.\n          # see https://en.wikipedia.org/wiki/8.8.8.8\n          #- \"8.8.8.8\"\n          #- \"8.8.4.4\"\n  bridges:\n    # NB this is equivalent of executing:\n    #       ip link add name br-rpi type bridge\n    #       ip addr flush dev br-rpi\n    #       ip addr add dev br-rpi 10.10.10.1/24\n    #       ip link set dev br-rpi up\n    #       ip addr ls dev br-rpi\n    #       ip -d link show dev br-rpi\n    #       ip route\n    # NB later, you can remove with:\n    #       ip link set dev br-rpi down\n    #       ip link delete dev br-rpi\n    br-rpi:\n      addresses:\n        - \"10.10.10.1/24\"\n      interfaces:\n        - vlan2\n  vlans:\n    # NB this is equivalent of executing:\n    #       ip link add link enp3s0 vlan2 type vlan proto 802.1q id 2\n    #       ip link set dev vlan2 up\n    #       ip -d link show dev vlan2\n    # NB later, you can remove with:\n    #       ip link set dev vlan2 down\n    #       ip link delete dev vlan2\n    vlan2:\n      id: 2\n      link: enp3s0\n```\n\nEdit `provision-images.sh` to select which image is installed by default.\n\nAfter the above is in place, run `vagrant up gateway` to launch the gateway.\n\nFor more information about VLANs see the [IEEE 802.1Q VLAN Tutorial](http://www.microhowto.info/tutorials/802.1q.html).\n\n# Raspios sd-card\n\nCreate a [Raspios Lite](https://www.raspberrypi.org/downloads/raspios/) sd-card with [balenaEtcher](https://www.balena.io/etcher/), put it in your pi and boot from it.\n\nLogin with the `pi` username and `raspberry` password.\n\nThen configure it with:\n\n```bash\n# switch to root.\nsudo su -l\n\n# disable automatic flash updates.\nsystemctl mask --now rpi-eeprom-update\n\n# update the system.\napt-get update\napt-get upgrade -y\n\n# reboot.\nreboot\n\n# switch to root.\nsudo su -l\n\n# disable auto-login.\nraspi-config nonint do_boot_behaviour B3\n\n# replace vnc with rdp.\n# NB on your computer, you can use the following command to rdp into your pi:\n#       xfreerdp /v:raspberrypi.local /u:pi /p:raspberry /size:1440x900 +clipboard\napt-get remove -y --purge realvnc-vnc-server\napt-get install -y xrdp\n\n# remove unneeded packages.\napt-get autoremove -y --purge\n```\n\n## Firmware Update for PXE boot\n\nRPi4 has two firmware images:\n\n1. `pieeprom` stored in the SPI-attached FLASH (aka EEPROM; 4MBits/512KB) and used by the SoC as a bootloader. For more information see https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md.\n2. `vl805` stored in the USB controller FLASH (aka EEPROM) and used by it.\n\n**NB** In theory its not possible to brick the RPi, if something is not working as expected, just use a recovery sdcard as described by the [recovery instructions](https://www.raspberrypi.org/downloads/).\n\n**NB** the RPi4 firmware is not open-source (and probably will never be).\n\nThere are two flash image channels:\n\n1. `critical`: contains the stable/finished firmware.\n2. `beta`: contains the testing/development firmware (e.g. currently, this is the only one that has support for PXE network booting).\n\nThey are stored at `/lib/firmware/raspberrypi/bootloader/*/*.bin` (were installed the `rpi-eeprom-images` package; they are also available at https://github.com/raspberrypi/rpi-eeprom/tree/master/firmware), e.g.:\n\n```plain\n    /lib/firmware/raspberrypi/bootloader/beta/pieeprom-2020-04-16.bin\n    /lib/firmware/raspberrypi/bootloader/beta/vl805-000137ad.bin\n/lib/firmware/raspberrypi/bootloader/critical/pieeprom-2020-04-16.bin\n/lib/firmware/raspberrypi/bootloader/critical/vl805-000137ad.bin\n```\n\nTo flash a image we use the `rpi-eeprom-update` command.\n\nFor example, to flash a critical bootloader with its default configuration, use:\n\n```bash\nrpi-eeprom-update -d -f /lib/firmware/raspberrypi/bootloader/critical/pieeprom-2020-04-16.bin\nreboot\n```\n\n**NB** The above will create the following files in the sd-card `/boot` directory:\n\n```plain\n-rwxr-xr-x  1 root root       65 Feb  8 16:06 pieeprom.sig*\n-rwxr-xr-x  1 root root   524288 Feb  8 16:06 pieeprom.upd*\n-rwxr-xr-x  1 root root    60820 Feb  8 16:06 recovery.bin*\n```\n\n**NB** The pi 4 rom will always run `recovery.bin` if it exists, that way, the pi can be recovered by using a recovery sd-card.\n\n**NB** The default flashing procedure using `recovery.bin` **only reads files from the sd-card**, even when the pi is configured to boot from the network.\n\nAt the next boot, the upgrade will be applied by `recovery.bin` and when it successfully flashes the firmware, it will rename itself. If it fails to rename itself (or a power failure happened), the process repeats it self at the next boot.\n\nFor more details see:\n\n* https://github.com/raspberrypi/rpi-eeprom/blob/master/firmware/release-notes.md\n* https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711_bootloader_config.md\n* https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md\n* https://leiradel.github.io/2019/01/06/SmartStart.html\n* https://leiradel.github.io/2019/01/20/Raspberry-Pi-Stubs.html\n\nSee which version you have now by executing `rpi-eeprom-update`, e.g.:\n\n```plain\nBCM2711 detected\nDedicated VL805 EEPROM detected\nBOOTLOADER: up-to-date\nCURRENT: Thu 16 Apr 17:11:26 UTC 2020 (1587057086)\n LATEST: Thu 16 Apr 17:11:26 UTC 2020 (1587057086)\n FW DIR: /lib/firmware/raspberrypi/bootloader/critical\nVL805: up-to-date\nCURRENT: 000137ad\n LATEST: 000137ad\n```\n\nTo flash a bootloader with customized settings, e.g., to boot from a PXE server:\n\n```bash\n# check the current bootloader version and config.\nvcgencmd bootloader_version\nvcgencmd bootloader_config\n\n# extract the configuration file.\ncp /lib/firmware/raspberrypi/bootloader/critical/pieeprom-2020-04-16.bin pieeprom.bin\nrpi-eeprom-config pieeprom.bin \u003ebootconf.txt\n\n# see the configuration file.\ncat bootconf.txt\n# in my case it was:\n#   [all]\n#   BOOT_UART=0\n#   WAKE_ON_GPIO=1\n#   POWER_OFF_ON_HALT=0\n#   DHCP_TIMEOUT=45000\n#   DHCP_REQ_TIMEOUT=4000\n#   TFTP_FILE_TIMEOUT=30000\n#   TFTP_IP=\n#   TFTP_PREFIX=0\n#   BOOT_ORDER=0x1\n#   SD_BOOT_MAX_RETRIES=3\n#   NET_BOOT_MAX_RETRIES=5\n#   [none]\n#   FREEZE_VERSION=0\n\n# save a copy to compare after we change it.\ncp bootconf.txt{,.orig}\n\npython3 \u003c\u003c'EOF'\nimport configparser\n\nconfig = configparser.RawConfigParser()\nconfig.optionxform = str\nconfig.read('bootconf.txt')\n\n# disable wake on GPIO because I do not need it.\n# NB default is 1.\nconfig.set('all', 'WAKE_ON_GPIO', '0')\n\n# really power-off everything.\n# NB this only leaves the 5v rails on.\n# NB this is only applicable when WAKE_ON_GPIO=0,\n# NB default is 0.\nconfig.set('all', 'POWER_OFF_ON_HALT', '1')\n\n# enable network boot.\n# change BOOT_ORDER from 0x1 (sd-boot) to 0x2 (network boot).\n# NB default is 0x1.\n# NB if something goes wrong you can always follow the recovery procedure described at https://www.raspberrypi.org/downloads.\n# see https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711_bootloader_config.md\nconfig.set('all', 'BOOT_ORDER', '0x2')\n# retry forever.\nconfig.set('all', 'NET_BOOT_MAX_RETRIES', '-1')\n\n# identify this RPi as rpi1 to the TFTP server.\nconfig.set('all', 'TFTP_PREFIX', '1')\n# request tftp files using this prefix (if that fails, it will try again, without the prefix).\n# the bootloader will request the following files (until one of them exists):\n#   rpi1/start4.elf\n#   rpi1/start.elf\n#   config.txt\n#   recover4.elf\n#   recovery.elf\n#   start4.elf\n#   start.elf\nconfig.set('all', 'TFTP_PREFIX_STR', 'rpi1/')\n\n# enable the boot UART to help debug (network) boot issues that might arise.\n# NB you need a UART/console cable connect to the RPi and to a computer.\n#    to connect to the UART use picocom --baud 115200 /dev/ttyUSB0.\n#    to quit picocom type Ctrl+A, Ctrl+X.\n# NB default is 0.\nconfig.set('all', 'BOOT_UART', '1')\n\nwith open('bootconf.txt', 'w') as f:\n    config.write(f, space_around_delimiters=False)\nEOF\n\n# see the differences to make sure everything is OK.\ndiff -u bootconf.txt{.orig,}\n\n# apply the configuration change to a new pieeprom-netboot.bin image file.\nrpi-eeprom-config --out pieeprom-netboot.bin --config bootconf.txt pieeprom.bin\n\n# flash the pi.\n#\n# there are two ways to flash the pi:\n#\n#   1. power-off resilient\n#      NB this requires a sd-card to be present.\n#   2. non power-off resilient.\n#      NB if the power is lost while flashing, you need to recover the flash using the recovery sd-card.\n#\n# if we have an sdcard, prefer that method, even when booted from the network.\nif [ \"$(lsblk /dev/mmcblk0p1 -o LABEL | tail -n +2)\" == \"boot\" ]; then\n    # configure the device to be flashed at the next boot.\n    rpi-eeprom-update -d -f pieeprom-netboot.bin\n    # if the sd-card is not mounted we assume we are booting from the network,\n    # as such, rpi-eeprom-update left the files in the network share instead\n    # of the sd-card, so, we just copy the entire /boot tree to the boot\n    # partition.\n    sd_card_boot_mountpoint=\"$(lsblk /dev/mmcblk0p1 -o MOUNTPOINT | tail -n +2)\"\n    if [ \"$sd_card_boot_mountpoint\" == '/media/pi/boot' ]; then\n        # NB this is normally automatically mounted by raspios, but we\n        #    need to re-mount it as root.\n        umount /media/pi/boot\n        sd_card_boot_mountpoint=''\n    fi\n    if [ \"$sd_card_boot_mountpoint\" == \"\" ]; then\n        # when the current system boots from the network we must put the\n        # files in the sd-card boot partition (because the pi bootloader\n        # can only load them from the sd-card).\n        mkdir -p /media/pi-boot\n        mount /dev/mmcblk0p1 /media/pi-boot\n        rsync -a --delete /boot/ /media/pi-boot/\n        umount /media/pi-boot\n        rmdir /media/pi-boot\n    fi\nelse\n    # flash it right now.\n    rm -f /boot/{recovery.bin,pieeprom.*}\n    USE_FLASHROM=1 rpi-eeprom-update -d -f pieeprom-netboot.bin\nfi\n\n# reboot to apply changes.\nreboot\n```\n\nAfter reboot you should verify that the device is using the expected bootloader configuration:\n\n```bash\nvcgencmd bootloader_version\nvcgencmd bootloader_config\n```\n\n# Network Packet Capture\n\nYou can see all the network traffic from within the gateway by running:\n\n```bash\nvagrant ssh-config gateway \u003etmp/gateway-ssh-config.conf\nwireshark -k -i \u003c(ssh -F tmp/gateway-ssh-config.conf gateway 'sudo tcpdump -s 0 -U -n -i eth1 -w - not tcp port 22')\n```\n\nYou can also do it from the host by capturing traffic from the `br-rpi` or `vlan2` interface.\n\n# Reference\n\n* https://www.raspberrypi.org/documentation/hardware/raspberrypi/bootmodes/net_tutorial.md\n* https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md\n* https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711_bootloader_config.md\n* https://leiradel.github.io/2019/01/06/SmartStart.html\n* https://leiradel.github.io/2019/01/20/Raspberry-Pi-Stubs.html\n* https://www.raspberrypi.org/documentation/hardware/raspberrypi/schematics/README.md\n* https://www.raspberrypi.org/documentation/configuration/boot_folder.md\n* https://www.raspberrypi.org/documentation/configuration/\n* https://github.com/raspberrypi/rpi-eeprom/blob/master/firmware/raspberry_pi4_network_boot_beta.md\n* https://github.com/raspberrypi/rpi-eeprom/blob/master/firmware/release-notes.md\n* https://github.com/raspberrypi/linux\n* https://github.com/pftf\n* https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt\n* https://github.com/RPi-Distro/pi-gen\n* [IEEE 802.1Q VLAN Tutorial](http://www.microhowto.info/tutorials/802.1q.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frgl%2Fpxe-raspberrypi-vagrant","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frgl%2Fpxe-raspberrypi-vagrant","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frgl%2Fpxe-raspberrypi-vagrant/lists"}