FOG Project Image Capture on Raspberry Pi 4 (ARM64) via U-Boot
-
"Hi again! Great news regarding the new TFTP fallback mechanism.
I tested it manually by setting the IP addresses:
Plaintextsetenv ipaddr 192.168.203.50
setenv serverip 192.168.203.113
pxe getWhat happened:
U-Boot successfully found the correct path generated by FOG based on the MAC address (Retrieving file: pxelinux.cfg/01-88-a2-9e-53-34-c0). However, the download times out (Loading: T T T T T T) and results in a Retry count exceeded.For context: a deployment task was explicitly active and queued in the FOG web interface before running the test, so the file should be there.
Is there a specific TFTP block size or setting required in working-1.6 for U-Boot’s pxe get to successfully pull the file without timing out, or could it be related to firewall/TFTP service configuration on the server side?"
-
@Jeremy That’s real progress —
pxe getfindingpxelinux.cfg/01-88-a2-9e-53-34-c0by MAC means the naming convention and the file-generation side both work end to end. That’s the part I couldn’t test myself, so thank you for actually running it.On the timeout itself: “found the file, then hung mid-transfer” (
Retrieving file: ...succeeding, thenLoading: T T T T T T/Retry count exceeded) points at TFTP’s own connection model, not at FOG. TFTP’s initial request goes to port 69, but the server then hands the rest of that transfer off to a different, randomly chosen UDP port for the actual data — so if there’s a firewall between the Pi and your FOG server that only allows port 69 through, the request succeeds (that’s why U-Boot found the file) and every packet after it gets silently dropped. That matches your symptom closely enough that I’d check it first: either open the OS’s ephemeral UDP range to your TFTP daemon, or (simpler if this is on the same box) confirm nothing’s filtering loopback/LAN traffic to it at all. If you’ve got shell on the FOG server,tcpdump -ni <iface> port 69 or portrange 32768-60999while you retrypxe getshould show the request going out and then nothing coming back, which would confirm it.Separately — while looking into this I found a real gap on FOG’s side and fixed it regardless of whether it’s your actual cause: the file
pxe getdownloads wasn’t having its permissions set after upload, so if your TFTP daemon reads as a different user than the account FOG uploads over SFTP with, that alone could produce exactly this symptom (found the file, denied reading it). That fix is in the sameworking-1.6branch now, so another update will pick it up. Worth ruling both things out — they’re not mutually exclusive.On your scalability question: for 100–200 units, don’t script the SD card at all — the RPi 4’s own boot EEPROM supports network boot as the first boot mode, ahead of SD/USB, which is exactly what you want instead of the local-storage-timeout-then-BOOTP-fallback sequence you saw.
rpi-eeprom-config(or theraspi-configboot order menu) lets you set that once, and once it’s set it’s a firmware-level property of the board, not something FOG or an SD card image controls — one flash per unit, and after that every power-on goes straight to network boot, nobootcmdpersistence step needed on your end at all. I’d flash that as part of whatever imaging/provisioning process gets each Pi ready before it ever talks to FOG the first time, rather than trying to solve it per-deployment.I don’t have a Pi 4 here to confirm the exact EEPROM boot-order syntax for your firmware revision, so double-check against Raspberry Pi’s own EEPROM config docs before you commit to a fleet-wide flash — but the “make network boot the default at the firmware level” shape of the answer is what actually gets you out of typing anything at the prompt.
-
@Jeremy Correction on the firewall angle: if your server went through FOG’s own installer on ufw or firewalld, that’s actually less likely to be it than I made it sound — the installer already handles the exact “TFTP works for the request but the reply is on a random port” problem for both of those (a named
tftpservice on firewalld, andnf_conntrack_tftploaded for ufw), specifically because it’s bitten people before.So rather than “check your firewall” in general, four narrower things:
- Which firewall are you actually running —
ufw,firewalld, or plainiptables? The installer only auto-configures the first two; if it’s bare iptables, my original theory stands and you’d need to allow the ephemeral UDP range by hand. - If it’s ufw:
lsmod | grep tftp— the installer tries to loadnf_conntrack_tftpbut silently continues if that fails, so it’s worth confirming it’s actually loaded rather than assumed. - Is
BOOT_external_tftp_serverset to “yes” in your FOG settings? If so and your TFTP is actually running on the FOG box itself, firewalld would have skipped opening it for you. - Are the Pi and the FOG server on the same subnet/VLAN, or is there a router, switch ACL, or (if this is a VM/cloud box) a security group between them? None of the above touches anything outside this box.
If you’ve got shell on the FOG server,
tcpdump -ni <iface> port 69 or portrange 32768-60999while you retrypxe getis still the fastest way to see whether the request goes out and nothing comes back (firewall/network) versus the request itself failing (something else entirely). - Which firewall are you actually running —
-
Here is an update following our latest troubleshooting sessions and tests:
The !V@JL artifact: That part was indeed a leftover artifact from editing the file manually with nano. Once cleaned up, we hit a regression: the Raspberry Pi no longer downloads the 563-byte config file at all anymore. It now loops directly on BOOTP broadcast and times out without hitting the TFTP stage (Retrieving file... doesn't trigger anymore). Goal & Architecture: The target deployment must remain 100% cardless (no local storage, no SD card, no USB drive used during boot), relying purely on the RPi 4 network boot EEPROM + OPNsense DHCP + FOG/U-Boot. Regarding your earlier notes on TFTP/Firewall: We are running UFW on the FOG server, and we verified that nf_conntrack_tftp is active (lsmod | grep tftp confirmed). BOOT_external_tftp_server is not enabled (TFTP runs locally on the FOG box). The Pi and FOG server are on the same subnet, with no intermediate restrictive ACLs on that local segment. The permission fix: We noted your mention about the file permissions fix for downloaded files not being set properly after upload in the working-1.6 branch. Could this regression (dropping back to infinite BOOTP loops instead of attempting the TFTP fetch) be tied to how the file is currently served or indexed, or is there a specific way U-Boot expects the handoff after DHCP?
-
@Jeremy Good — that rules out the firewall/permissions angle cleanly, thanks for actually checking rather than taking my word for it.
The new symptom is a different failure than before, and it’s outside anything FOG serves: looping on BOOTP with no attempt at
Retrieving file...means it’s failing at DHCP/BOOTP negotiation, a step beforepxe getwould ever run. FOG can’t see that far back — the board never gets far enough to ask FOG anything.You’ve also moved to a materially different boot path than what we’d been testing: cardless, via the Pi’s own network-boot EEPROM, rather than typing commands by hand at the U-Boot prompt. That matters here, because the EEPROM’s automatic network-boot flow runs its own boot sequence, built into that U-Boot, not necessarily the
dhcp/pxe get/pxe bootlines from earlier in this thread — those were for a manually-typedbootcmd. If the EEPROM path usesbootpinstead ofdhcp, or expects OPNsense to hand it specific DHCP options, that’s a different thing to get right than what we tested manually.Two things I’d need to actually say anything useful here, since I can’t see either from where I’m sitting:
- What’s the board actually running right now — did the
nanoedit touch a persistedbootcmd(printenv bootcmd), or is this the EEPROM’s own default network-boot sequence with nothing custom in the loop at all? - In OPNsense’s DHCP config for that subnet, what are options 66 (
next-server) and 67 (filename/bootfile-name) set to? The EEPROM’s PXE client needs those to know where to send its own request in the first place — if they’re pointing at the wrong place, or missing, U-Boot never gets the chance to see FOG at all, and that would produce exactly a BOOTP loop with nothing after it.
That’ll tell us whether this is a boot-script problem (fixable on your end) or a DHCP-options problem (fixable in OPNsense) — right now I genuinely can’t tell which from here.
- What’s the board actually running right now — did the
-
Hi, I’m sending you the two screenshots—one from OPNsense and the other from the Raspberry Pi.


-
@Jeremy Thanks for the screenshots — they changed my read of this quite a bit, and I owe you a correction first.
Correction: earlier I said
pxe get“finding”pxelinux.cfg/01-88-a2-9e-53-34-c0proved the file-generation side worked. It didn’t. U-Boot printsRetrieving file: ...before it sends the request, and theLoading: T T T Tthat follows means the server never answered at all. A file that really is missing gives youTFTP error: 'File not found', not timeouts. So the file-side was never proven, and it turns out it was broken on my side of the fence.The FOG bug, now fixed: FOG was writing the
01-<mac>file under the directory it keeps the HTTP-served kernels in (/var/www/html/fog/service/ipxe/), not under/tftpboot. The TFTP daemon runs chrooted to/tftpboot, so the file existed but TFTP could never see it. That’s fixed inworking-1.6(PR #1664) with a new setting,FOG Settings → TFTP Server → FOG_TFTP_ROOT_DIR, which the installer sets to the real TFTP root. Run the updater once it’s merged and check that setting reads/tftpboot; after that, queue a task for the Pi and you should see/tftpboot/pxelinux.cfg/01-88-a2-9e-53-34-c0appear on the server. Please confirm that file is there before the next boot test — it’s the one thing I can check in code but not on your box.Your current boot loop is a different, earlier step. From the console shot: U-Boot itself loaded cardless, which means the Pi’s EEPROM network boot already pulled the firmware and
u-boot.binfrom/tftpbootover TFTP. That proves the OPNsensenext-server, the FOG TFTP service and the firewall are all fine for this client — so ignore my earlier firewall angle. What’s looping isbootcmd=bootflow scan: that’s U-Boot’s standard-boot sequence, which tries mmc, usb, then ethernet, and the ethernet step starts with U-Boot’s own DHCP request (BOOTP broadcast 1, 2, 3...). That DHCP never succeeds, and it’s never been shown to work in this thread — your earlier manual test setipaddr/serveripby hand and skipped DHCP entirely. The empty per-architecture filenames in OPNsense are fine, by the way: thepxeboot method doesn’t need a bootfile name at all. (Side note, unrelated to the Pi: the iPXE-class filename in OPNsense is what gets handed to a client that is already running iPXE, and FOG expectsdefault.ipxethere, notipxe.efi— withipxe.efiyour x86 UEFI clients will reload iPXE forever. Worth a look when you’re back on those.)Two things to try at the U-Boot prompt, and please paste the exact text rather than a screenshot if you can:
dhcpon its own. If it also loops on BOOTP, then U-Boot’s network driver isn’t getting a lease and we look at OPNsense’s DHCP log for that MAC (does the request even arrive, does it offer). If it does get an address, then:
pxe get pxe bootonce the FOG update above is in and the
01-...file is confirmed on disk. If that works by hand,setenv bootcmd 'dhcp; pxe get; pxe boot'andsaveenvgets you the automated path —bootflow scanshould get there too, but the manual sequence tells us which step is at fault when it doesn’t. -
I do have the filename you requested.

When U-Boot starts, DHCP doesn’t work; it spends 8 seconds searching. Sometimes, when rebooting the Raspberry Pi, it manages to obtain an IP address, successfully detects the server’s IP, and downloads pxelinux, but then stops.

What I don’t understand is why U-Boot sometimes manages to get an IP address and sometimes doesn’t.
-
@Jeremy Do you happen to have STP on your network?
-
@Jeremy Good — the file being there confirms the
/tftpbootfix landed. Two separate things in your report, and one of them was mine again.“Downloads pxelinux, but then stops” — partly expected, partly another FOG bug, now fixed.
- If there was no task queued for the Pi at that moment, the file FOG writes says
localboot 0, which tells U-Boot “nothing to do, carry on to local disk”. That’s by design: no task, no imaging. So “stops” after a successfulpxe getis correct behavior unless you’d queued a capture first. - If there was a task queued, it would still have stopped, and that one is on me: the file named the kernel and init as
http://…URLs, which is what boards withwgetuse. Your U-Boot’spxecode can’t follow a URL — I checked U-Boot’s source (boot/pxe_utils.c
every kernelandinitrdline is fetched over TFTP, relative to wherever the config came from, sokernel http://…became a TFTP request for a file literally called that. Fixed inworking-1.6(PR #1679): the file now sayskernel arm_Image/initrd arm_init.cpio.gz, and FOG copies those two files into/tftpbootitself the first time a task is queued for an ARM host, and again whenever the kernel is updated. Run the updater once more, queue a capture for the Pi, then on the server check that/tftpboot/pxelinux.cfg/01-88-a2-9e-53-34-c0containskernel arm_Imageand that/tftpboot/arm_Imageand/tftpboot/arm_init.cpio.gzexist.
The intermittent DHCP is a network-timing problem, not a FOG one, and Tom’s STP question is the right first suspect. On a switch port running classic spanning tree, the port doesn’t forward traffic for roughly 30 seconds after link-up (listening, then learning). U-Boot brings the link up and sends its DHCP discover immediately, retries for a few seconds, and gives up — that’s the “8 seconds searching”. The times it works are the times the port happened to already be forwarding. The Pi’s EEPROM boot succeeds because it retries for much longer. Two fixes, and I’d do both:
- On the switch: enable PortFast / edge-port (or RSTP) on the ports the Pis plug into. That’s the real fix and it helps every PXE client, not just the Pis.
- In U-Boot, so a slow port doesn’t kill the boot anyway:
setenv autoload no setenv netretry yes setenv bootcmd 'dhcp; pxe get; pxe boot' saveenvautoload nostopsdhcpfrom also trying to TFTP a bootfile it was never given (that’s an extra timeout and a spurious failure in your sequence).netretry yesmakes U-Boot keep retrying DHCP instead of giving up after a few seconds — the right call for a headless board that has nothing else to do, but be aware it means a Pi with no DHCP server on the wire will sit there retrying rather than dropping to the prompt.If DHCP still fails after that, the next read is OPNsense’s DHCP log for that MAC: whether the discover even arrives, and what it offers. And as before, pasted text beats a screenshot — the exact lines around
pxe bootare the ones I need next. - If there was no task queued for the Pi at that moment, the file FOG writes says