outpost-media May 7, 2026
I went to the Miami Formula 1 Grand Prix and built a server for it. With the help of my OpenClaw agent Morgan, Claude Code, a concerning amount of White Monster, and approximately 2 evenings after already spending all day working on AI infrastructure at my job, I shipped something that realistically about two people used. Here is the story.
The Idea
The Turn 18 grandstand at the Miami International Autodrome is a great place to watch F1, and also a great place to sit for four hours with spotty cell service and nothing to do between sessions. My plan was simple: if the cell towers were going to be overwhelmed by 60,000 people, I'd just bring my own internet. A Pi running a captive portal, redirecting everyone on the WiFi to a local web app with movies, games, F1 info, a chat room, and a CTF. No internet required. No cloud. Just a battery-backed Linux computer in a clear backpack pretending to be infrastructure.
Verizon had quietly upgraded the network capacity for the event and the cell service was completely fine the entire weekend. I found this out approximately ten minutes after arriving.
Building the Thing
The build happened across two evenings. Morgan handled a lot of the scaffolding and architecture decisions while I was the one actually staring at error messages at 1am. Claude Code built the bulk of the application in one session (Flask, FlaskSocketIO, SQLAlchemy, flaskadmin, Alpine.js, VideoJS, a full CTF engine with leaderboard). I handled content aggregation, encoding, and the Pi setup. Getting driver data for some of the non F1 race series was surprisingly difficult... (I'm looking at you McLaren Trophy America)
Content aggregation was its own project. F1 driver profiles and race history got scraped and sanitized into static HTML. Movies got encoded on my MBP through ffmpeg at 720p H.264 with faststart flags so they'd seek instantly on VideoJS without buffering. The Kiwix offline Wikipedia snapshot took a while to filter down to something that fit on the SD card without being useless. EPUBs
for the library got sourced and organized. By the time I was done the content pipeline had taken almost as long as the application itself.
The Hardware Problem (There's Always a Hardware Problem)
I ordered a Raspberry Pi Zero 2 W. Quadcore ARM, 64-bit, exactly what the stack was designed for. What showed up was a Raspberry Pi Zero W, the original 2016 model (singlecore BCM2835, 32-bit only, roughly the compute power of a potato with ambitions). These look identical in the product photos. I discovered the mismatch at midnight the night before the race when my arm64 Pi OS image produced 7 blinks on boot, which means "kernel image not found" and which is not a great thing to see when you're supposed to leave in 8 hours.
Reflashed with armhf Pi OS Lite and everything came up fine. The Zero W is slower but for serving static files and a small Flask app to a handful of people (it turned out) it was never going to be the bottleneck.
The rest of the hardware: 256GB A1-rated SD card, PiSugar UPS HAT, Anker 737 24,000mAh battery. The UPS HAT was supposed to be the main battery I then decided to bring the Anker after doing some napkin math. In retrospect I was building for a load that never materialized, but the hardware held up perfectly.
The Stack
Caddy for the captive portal redirect and HTTPS (it has firstclass captive portal support, which is one of those features that seems niche until you need it). Flask plus FlaskSocketIO for the app. SQLite for persistence. Hostapd and dnsmasq for the access point and DNS wildcard redirect. The whole setup script configured the Pi from a fresh Raspbian install into a functioning captive portal in one run. No internet required on the Pi side after initial setup, which was the whole point.
The CTF
I built a sixchallenge CTF because I thought people would be bored and want something to do. F1-themed flags, covering web basics (viewing source, intercepting an API response), steganography hidden in a PNG, EXIF metadata in
a JPEG, a Caesar cipher, and a final metachallenge combining the first letters of each flag. First place prize was a Claude API token.
Nobody played it. I don't actually know with confidence that it works endtoend because it was never tested under real conditions. The unit tests pass. The leaderboard renders correctly. But as far as real human beings solving challenges and submitting flags: no data. The CTF remains in a state of theoretical correctness (maybe I'll play it if I get bored some day).
What Actually Happened
My girlfriend connected and watched some movies. She also spent some time on the F1 info pages reading about drivers and race history, which is genuinely the most wholesome possible use case. She then found out the snake game I had put in didn't work on mobile (that's what my dumbass gets for not regression testing). I connected, played some 2048, watched some movies between races, and got a decent amount of use out of the schedule (I immediately got they gave me wet). A handful of other people in the grandstand joined the WiFi at some point based on the DHCP leases, but none of them interacted with the portal in any meaningful way that I saw.
The Pi ran the full day without issues. The Pi Sugar battery lasted about half the race, then I just plugged it into the Anker power bank. The heatsink kept temperatures shockingly reasonable in the Florida heat. One video had a container format issue that required a quick re encode before the event but otherwise the content pipeline worked exactly as intended.
So: two actual users, zero CTF players, a completely unnecessary project given that Verizon had done their job, and a surprisingly enjoyable day regardless. Successful by any reasonable definition of the word (the reasonable definition being "it worked and nothing caught fire").
What's Next
The part that felt worth keeping was the architecture, not the Miami-specific content. Right now the repo has F1 info baked into the content layer in ways that don't generalize. I want to pull that apart into a proper content manifest system where you define an event, point it at a content directory, and the app configures itself. Something you could deploy for a camping trip, a conference, a concert, whatever situation involves a lot of people in one
place with bad cell service and time to kill.
The source is on GitHub if you want to see how it's put together (or run your own version, which I'd actually recommend against until I clean up the event-specific bits).
Leave a comment:
Comments: