Files
OpenPXE/deploy/unraid/README.md
T
2026-05-06 14:13:38 -04:00

5.1 KiB

OpenPXE on Unraid

Three paths from "I have an Unraid box with Gitea on it" to "PXE clients boot from OpenPXE". Pick the one that matches what you have.

Path A — build on Unraid, push to Gitea registry, pull by tag

Recommended once you've done it once. Image is published to gitea.milesward.dev/mward4/openpxe:0.1.0 (or your equivalent) and every Unraid template / docker-compose just references the tag.

Pre-flight:

  • Gitea has the Container Registry enabled (Site Admin → Configuration → set [packages] ENABLED = true in app.ini; default-on in Gitea ≥ 1.18).
  • You have a Gitea personal access token with write:package scope (User → Settings → Applications → Generate New Token, check package read+write).

Run on the Unraid host (Settings → Terminal, or ssh root@unraid):

# Pull just the build script straight from Gitea (no clone needed first):
GITEA_TOKEN=<your-token>
curl -fsSL \
  -H "Authorization: token $GITEA_TOKEN" \
  http://localhost:3000/mward4/OpenPXE/raw/branch/main/scripts/build-and-publish-unraid.sh \
  -o /tmp/openpxe-publish.sh

# Run it. ~6 min on Unraid hardware (native amd64, no QEMU).
chmod +x /tmp/openpxe-publish.sh
GITEA_TOKEN=$GITEA_TOKEN /tmp/openpxe-publish.sh

What it does:

  1. Shallow-clones the repo from local Gitea (no Cloudflare, no LAN issues).
  2. Runs scripts/fetch-ipxe.sh to grab the iPXE binaries from the official release URLs.
  3. docker build against deploy/docker/Dockerfile.
  4. docker login gitea.milesward.dev:3000 using a temp DOCKER_CONFIG so the credential never lands in your real ~/.docker/config.json.
  5. docker push both :0.1.0 and :latest.
  6. Logout, scrub the temp config, delete the workspace.

After it finishes, in Unraid → Docker → Add Container, set:

Field Value
Repository gitea.milesward.dev/mward4/openpxe:0.1.0
Network host
Extra args --cap-add=NET_BIND_SERVICE

Volume mounts (paths inside container in bold):

  • /var/lib/openpxe/isos/mnt/user/appdata/openpxe/isos
  • /var/lib/openpxe/work/mnt/user/appdata/openpxe/work
  • /var/lib/openpxe/smb/mnt/user/appdata/openpxe/smb

Or skip the manual UI by dropping openpxe.xml (in this directory) into /boot/config/plugins/dockerMan/templates-user/ and Unraid will list it as a one-click template.

Web UI: http://<unraid-ip>/.

Path B — docker-compose up directly from cloned repo

Skip the registry entirely. Useful for "hack on it locally" iterations.

ssh root@unraid
cd /mnt/user/appdata
git clone http://localhost:3000/mward4/OpenPXE.git openpxe-src
cd openpxe-src
bash scripts/fetch-ipxe.sh
docker compose -f docker-compose.yml up -d --build openpxe

The bundled docker-compose.yml already wires host networking, the right cap_add, and bind-mounts to ./data/. Edit those bind-mount paths if you want them under /mnt/user/appdata/openpxe/.

Path C — docker load from a tarball I built off-box

For when the build host can reach Unraid but Unraid can't reach the internet. Build the image somewhere with a cargo + buildx environment, then:

# On the build host
docker save openpxe:0.1.0 | gzip > openpxe-0.1.0.tar.gz

# Transfer (rsync / scp / SMB / ZFS-replicate / sneakernet)
scp openpxe-0.1.0.tar.gz root@unraid:/tmp/

# On Unraid
gunzip -c /tmp/openpxe-0.1.0.tar.gz | docker load
docker tag openpxe:0.1.0 gitea.milesward.dev/mward4/openpxe:0.1.0

If you want it pullable by tag from other Unraid templates, push to Gitea afterward (path A's last step).

Verifying it works

Once the container is up, from any LAN host:

# Should return 'ok'
curl -s http://<unraid-ip>/healthz
# Should return 'ready' if iPXE binaries are bundled
curl -s http://<unraid-ip>/readyz

Web UI: http://<unraid-ip>/. The Dashboard's top-bar pill should read ● ready. Upload an ISO, boot a test machine PXE → it should show up in the Dashboard's "Recent connections" table within seconds.

Common gotchas

  • DHCP collision. Don't run two PXE proxies on the same broadcast domain. OpenPXE runs in proxy mode and never offers IP leases, so it coexists with whatever DHCP server is already on the network — but two proxies racing each other will whichever-wins at random.
  • Host networking only. Bridge mode containers don't see broadcast DHCP. There's no working bridge-mode config for a PXE server.
  • Permissions on /mnt/user/appdata/openpxe. The container runs as uid 10001 by default. The entrypoint chowns the bind mounts to 10001 on first start, but only if the container itself has root — --user=root isn't needed; the multi-stage Dockerfile starts as root, fixes perms, then drops to openpxe via gosu.
  • NFS mounts in the Storage tab. Mounting NFS inside the container needs CAP_SYS_ADMIN. To enable, add --cap-add=SYS_ADMIN to the Unraid template's "Extra args" — but understand that's a meaningful capability, comparable to --privileged. Skip it if you only need uploads.