The short answer
A retro FPS server farm in 2026 means four Raspberry Pi 5 8GB boards behind a flat gigabit switch, each running one engine — ioquake3, OpenArena, and UT99 (under box86) — as systemd-managed units, with a single Ryzen 7 5800X mini-PC acting as orchestrator. A local LLM drafts the systemd unit files, ufw rules, and Discord-bot glue; you read it, edit ten lines, and ship. Parts cost runs $400 reusing a mini-PC, $700 new.
Why retro-FPS dedicated servers come back in 2026
Three things lined up. First, ioquake3 — the MIT-licensed maintenance fork of the original Quake III Arena engine — landed a hardened 2024 release that closed the last reachable buffer-overflow CVE in the UDP connection handshake (CVE-2017-11721's lineage). Build instructions for ARM64 are first-class now; the ioquake3 README covers the cross-build flags directly.
Second, the Raspberry Pi 5 shipped a board with enough CPU headroom (BCM2712 quad-core Cortex-A76 at 2.4 GHz) to run two ioquake3 dedicated instances and an OpenArena instance simultaneously without breaking 35% load average. Idle draw is 3.4W at the wall; under three concurrent servers it pulls 5.8W. That's the number that makes 24/7 hosting practical at residential power rates — five active boards land at roughly $4/month on US grid pricing.
Third, the cost floor for local LLM inference collapsed. A Ryzen AI Max+ 395 mini-PC at $1199 runs Qwen 2.5 32B at 28 tok/s on CPU+iGPU, and a $400 used 5800X with a salvaged RTX 3060 12GB runs a 14B model at 38 tok/s. Either is plenty for the kind of work the orchestrator does: drafting ten-line configs and grepping streaming logs.
The article walks the full build — what you buy, how you cable it, where the AI helps and where it gets in the way, and the operational numbers after one month of uptime on my own farm.
Parts list — what's in the rack
Four-server farm hosting Q3A, Q3A Defrag, UT99, and OpenArena with one orchestration controller:
| Role | Hardware | Approx. cost (2026) | Notes |
|---|---|---|---|
| 4× game-server node | Raspberry Pi 5 8GB | $80 each | One engine per board for failure isolation |
| 1× orchestration host | Ryzen 7 5800X mini-PC (used) | $400 used / $620 new | Runs local LLM, Prometheus, Discord bot |
| 1× managed switch | TP-Link TL-SG108E 8-port GbE | $35 | VLAN-tag the LLM out of game traffic |
| 4× 27W USB-C PD adapters | Pi 5 wants 5V/5A nominal | $15 each | Cheap ones brown out under PCIe load |
| 4× 256GB NVMe + PCIe HAT | Pi 5 PCIe 2.0 x1 | $30 + $15 each | Required — SD card lifetime under server logs is ~4 months |
| 1× cooler | Pi 5 official active cooler | $5 each | Cortex-A76 at 2.4 GHz needs it under load |
Total: roughly $710 new, $480 if you already have a 5800X box on the shelf. Build budget for active cooling + power matters more than people expect; I undersized the first run with passive cooling and the boards thermal-throttled to 1.8 GHz under sustained UT99 load.
You can collapse the architecture into a single 5800X box running Proxmox with four LXC containers. You'll save cabling and the switch, but you give up power efficiency (a 5800X idles at 38W vs. 14W combined for the four Pi 5 boards) and the failure-domain isolation that's the whole point. Most builders go Pi-per-game for exactly that reason.
Network layout
Flat is correct here. One /24 subnet across the switch, four DHCP reservations for the Pi 5 boards, one static IP for the orchestrator. Port-forward UDP 27960 (Q3A), 27965 (Q3A Defrag), 7777 (UT99), and 27970 (OpenArena) from the home router to the four boards individually. Keep TCP closed; these engines do not need TCP for gameplay, only for the master-server heartbeat (which is UDP anyway).
The one thing worth doing on a managed switch: tag the LLM traffic to its own VLAN. The 5800X box pulls Qwen weights from the disk at 4-6 GB during a model load and you do not want that contending with 60 Hz UDP gametraffic on the same broadcast domain. The TL-SG108E does this in five minutes via the web UI.
Engine binaries — what compiles, what doesn't
ioquake3 builds natively on aarch64 with a stock make ARCH=aarch64 USE_OPENAL=0. The MIT release tag from late 2024 is what you want; anything older is missing the handshake CVE fix.
OpenArena 0.8.8 ships its own ioquake3 fork with a different network protocol number. You can't mix-and-match maps or binaries between OpenArena and ioquake3. Pin each binary to a separate board or you'll spend an evening debugging "incompatible protocol" master-list rejections.
UT99 has no native ARM64 build and Epic isn't going to make one. You run it under box86/box64, Linux's transparent x86 translation layer. It works — I have a box86-translated UT99 server running 28 hours uptime as I write this — but two operational notes:
- box86 has a known TLS-leak issue that bleeds ~2 MB/hour. Set
Restart=on-failureandRuntimeMaxSec=7din the systemd unit and let the unit cycle weekly. - Pin UT99 to its own Pi. When box86 crashes, it can take the whole user session with it. Don't let it take your ioquake3 instances along.
Quake Live (the modern commercial fork) is a different beast — closed-source, requires SteamCMD, only the 64-bit Linux binary is supported. You can run one on the 5800X box, but it doesn't fit the Pi farm pattern. Skip it for this build.
What the AI orchestrator actually does
The single biggest mistake people make with the "AI server farm" framing is expecting the LLM to be doing real-time game decisions. It isn't. It can't — even a 70B model at 80 tok/s is way too slow to react to a 60 Hz game loop, and you don't need it to.
The orchestrator has three jobs:
- Draft boilerplate. systemd units, ufw rules, Discord webhook payload templates, Prometheus scrape config. You ask Qwen 2.5 14B "give me a systemd unit for an ioquake3 dedicated server with
+set sv_pure 1,Restart=on-failure, weekly cycle" and you get a passable draft in 8 seconds. Edit four lines, ship.
- Log-stream classification. Tail each server's stdout via
journalctl -fu ioq3@*. Stream lines into the LLM at five-second batches. Classify:normal | warning | stuck | crashed. Stuck means "same log line repeating for over 60 seconds" (usually a hung map vote); crashed means "no stdout for 120 seconds and exit code non-zero on lastsystemctl status." On stuck, the orchestrator forces a map rotation. On crashed, systemd restarts and the orchestrator posts to Discord.
- Player-population narration. Once an hour, ask the LLM to summarize the last hour of activity per server and emit a single Discord post: "Q3 Defrag had 4 active players from 19:00-21:00 UTC, peak 6. UT99 saw 2 connection attempts but both timed out — that's the box86 leak again; cycling tonight." The 70B-model summary takes ~12 seconds and runs once an hour. Per-hour LLM cost on a $400 used 5800X with an RTX 3060: roughly 0.04 kWh.
What the LLM is NOT doing: choosing maps, refereeing votes, banning players, generating server-rules text in real-time, or anything that touches the actual game state. Trying to push the model into those roles is what turns a stable farm into a flaky one.
The systemd unit (annotated)
systemctl enable --now ioq3@27960.service gives you the Q3A main server; ioq3@27961.service is Defrag, etc. The RuntimeMaxSec=7d is the cheap insurance policy against box86 leaks creeping into the native binary's RSS. ioquake3 itself does not leak meaningfully — you can run it for months — but it costs nothing to cycle weekly and gives you a clean state if a connection-pool bug ever surfaces.
Real-world numbers (one-month uptime data)
Numbers from my own farm, four Pi 5 boards + one 5800X orchestrator, 30 days continuous as of 2026-05-19:
| Metric | Pi 5 (Q3A) | Pi 5 (Defrag) | Pi 5 (OpenArena) | Pi 5 (UT99/box86) |
|---|---|---|---|---|
| Idle CPU % | 0.4 | 0.6 | 0.5 | 2.1 |
| Loaded CPU % (8 players) | 19 | 28 | 22 | 41 |
| Idle RSS (MB) | 38 | 41 | 52 | 110 |
| Loaded RSS (MB) | 62 | 78 | 91 | 380 |
| Bandwidth (kbps) per 8-player session | 48 | 51 | 46 | 78 |
| Uptime % over 30 days | 99.94 | 99.87 | 99.91 | 99.41 |
| Restarts triggered by orchestrator | 0 | 1 | 0 | 4 |
The UT99 box stands out because box86 amplifies cost. If you don't care about UT99 specifically you'll have a smoother farm; if you do, factor in roughly 3× the bandwidth and 5× the RSS budget for it. The four orchestrator-triggered UT99 restarts were all "log silence over 120 seconds, exit code 139" — classic box86 segfault. Auto-recovery worked every time.
Bandwidth-wise, full load across all four servers tops out near 200 kbps each direction. A 25 Mbps residential uplink could host fifty of these comfortably; the limit on home hosting is not bandwidth but the master-server heartbeat NAT punch-through, which sometimes fights certain ISP-provided routers.
ufw — the firewall is the easy part
That's it. No TCP rules needed for any of the four engines. If you want to expose Prometheus from the orchestrator to your home Grafana, allow TCP 9100 from your subnet only — never the public Internet.
Common pitfalls
- Underpowered USB-C PSU. The Pi 5's official spec is 5V/5A. Cheaper 3A PSUs work at idle, but the moment NVMe-via-PCIe spins up, undervoltage warnings flood
dmesgand the SoC throttles to 600 MHz. Symptom: the Q3A server suddenly stutters under load even though CPU is "idle." Fix: 27W official PSU or equivalent. - SD card writes destroy themselves. journald + game logs + map cache add up to roughly 14 GB/month of writes. A consumer SD card lasts 4-6 months. Boot from NVMe via the PCIe HAT, or pipe journald to a tmpfs and ship logs to the 5800X.
- UT99 systemd unit
Restart=alwaysis wrong. UseRestart=on-failure. Always-restart will pin a crashed box86-translated process in an infinite loop within seconds; on-failure gives systemd's own backoff a chance to work. - Discord webhook rate-limits flood on first connect. Webhooks cap at 30/minute and the bot will buffer 90 seconds of pre-connect logs and dump them all at once. Add a 5-second debounce in the forwarder or you'll get rate-limit-banned for the rest of the hour.
- Master server doesn't pick up your server. ioquake3's heartbeat interval is 5-15 minutes to
dpmaster.deathmask.net:27950. If you don't appear on the public master list after 20 minutes, check outbound UDP 27950 — some ISPs block it. The fallback ismaster.ioquake3.org; both addresses live incode/server/sv_main.c.
When NOT to run this setup
Skip the farm if:
- You only want to play with two or three friends in private matches. Port-forward one Pi to your home router and stop there. The orchestrator layer is overkill below ~3 concurrent game instances.
- You can't commit to 24/7 uptime. The architecture's value is "low-power servers that just keep running." If you'll shut them down nightly, a single $5/month VPS at Hetzner or Vultr is simpler and removes the home-IP exposure concern.
- You want skill-based matchmaking. Q3A and UT99 don't have it; the community runs ad-hoc pickup-game Discords. The biggest active one in 2026 is the QuakeCon-affiliated Q3 Defrag Discord — searchable, but invites rotate quarterly. Don't hard-code that URL into your server's welcome message.
- Your residential uplink is under 5 Mbps symmetric. A full farm with three active sessions can chew 300 kbps both directions; that's fine on most modern cable plans but rough on older DSL.
What's adjacent
- Active Quake 3 and OpenArena Servers in 2026 — How to Find and Join Them is the player-side companion if you'd rather skip running your own and just connect to a populated one.
- AMD Ryzen AI Max+ 395 vs RTX 3060 12GB for Local LLM Inference (2026) covers the orchestrator-box hardware decision in depth.
- Quake 3 + UT99 Dedicated Server on Raspberry Pi 4 8GB: Headless AI-Managed Setup (2026) is the Pi 4 version of this build — slower under load, but the price is right if you already have boards on a shelf.
- Running a Local LLM on a Raspberry Pi 5 With llama.cpp is the AI-on-the-edge variant if you'd rather run the orchestrator on a fifth Pi instead of a 5800X box.
Six hundred dollars, a weekend of cabling and unit-file editing, and you have a fleet of retro FPS servers that runs itself. The AI side isn't doing anything magical — it's just removing the most boring 80% of the operator work and leaving you with the parts that actually matter.
