docs(compose): simplify root docker-compose to one pull-based service

The root compose was scratch-built and carried both a prod and a dev
service plus a local build stanza. Replace it with a single
deployment-focused service that pulls
gitea.milesward.dev/mward4/openpxe:latest (matching the Unraid
template and the homelab flow):

- drop the openpxe-dev service and the build: context (deploy, not build)
- HTTP on 4200 so it clears an Unraid webGUI / reverse proxy on :80
- host networking (DHCPDISCOVER is broadcast — bridges don't forward it)
- cap_add NET_BIND_SERVICE instead of privileged; the binary already
  carries cap_net_bind_service as a file capability
- OPENPXE_PUBLIC_IP stays a required, fail-fast variable
- isos + work bind mounts (SMB dir omitted — Windows boots via HTTP
  sanboot since v0.5.8, no SMB server needed)

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Miles Ward
2026-06-14 08:15:43 -04:00
co-authored by Claude Opus 4.8
parent 1ded291c7b
commit 27703c437a
+27 -51
View File
@@ -1,66 +1,42 @@
# docker-compose for local / homelab deployment.
# OpenPXE — single-host / homelab deployment.
#
# Two usage patterns:
# One container: DHCP proxy + TFTP + iPXE chainload + HTTP (web UI, boot
# scripts, and ISO range streaming).
#
# 1. Local MVP test — host network, proxy-DHCP off (don't fight your
# existing DHCP server on the LAN), TFTP + HTTP exposed on the host:
# OPENPXE_PUBLIC_IP=192.168.1.49 docker compose up -d
#
# docker compose up openpxe-dev
# (or put OPENPXE_PUBLIC_IP in a .env file beside this one). That's this
# host's LAN IP, advertised to PXE clients so the iPXE URLs resolve —
# OpenPXE refuses to start rather than advertise an address clients can't
# reach, so compose errors out below if it's unset.
#
# 2. Real PXE deployment — host network, proxy-DHCP on, runs on a box
# plugged into the PXE network:
# Host networking is REQUIRED: DHCPDISCOVER is a broadcast, and Docker
# bridges / CNI overlays don't forward it into containers. In host mode
# the container binds these ports directly on the host:
#
# # First set OPENPXE_PUBLIC_IP to this host's LAN address in .env
# docker compose up openpxe
# udp/67 DHCP proxy udp/4011 PXE Boot Server
# udp/69 TFTP tcp/4200 web UI + HTTP boot assets
#
# On Linux hosts, `network_mode: host` gives the container direct access to
# the physical NIC — required for DHCP proxy because CNI overlays and Docker
# bridges do not forward DHCPDISCOVER broadcasts into containers.
#
# On macOS / Windows hosts, `network_mode: host` is limited — the daemon
# runs in a Linux VM (Colima/Docker Desktop) so the "host" network is the
# VM, not your Mac. Proxy-DHCP is not feasible on macOS; use `openpxe-dev`
# with published ports and set DHCP-MODE=disabled.
# Web UI: http://<this-host>:4200/
services:
# Real PXE deployment (Linux hosts).
openpxe:
image: openpxe:0.1.0
build:
context: .
dockerfile: deploy/docker/Dockerfile
image: gitea.milesward.dev/mward4/openpxe:latest
container_name: openpxe
restart: unless-stopped
network_mode: host
# The binary carries cap_net_bind_service as a file capability, so it
# binds the low DHCP/TFTP ports as a non-root user — no privileged mode.
cap_add:
- NET_BIND_SERVICE
environment:
# REQUIRED on multi-homed hosts. Set to this machine's LAN IP so the
# advertised iPXE URLs actually resolve from the PXE clients. Without
# this, OpenPXE will refuse to start rather than advertise a
# loopback address that can't be reached.
OPENPXE_PUBLIC_IP: ${OPENPXE_PUBLIC_IP:?set this to the host LAN IP}
OPENPXE_PUBLIC_IP: ${OPENPXE_PUBLIC_IP:?set this to the host LAN IP, e.g. 192.168.1.49}
# Web UI + HTTP boot assets. 4200 keeps clear of anything on :80
# (an Unraid webGUI, a reverse proxy, …).
OPENPXE_HTTP_PORT: "4200"
# proxy = coexist with the LAN's existing DHCP server (recommended).
OPENPXE_DHCP_MODE: proxy
OPENPXE_LOG: info
volumes:
- ./data/isos:/var/lib/openpxe/isos
- ./data/work:/var/lib/openpxe/work
# Dev / MVP container: published ports, DHCP disabled, HTTP on 8080.
# Use this on laptops where you want to curl the API or UI without
# running an actual PXE chain.
openpxe-dev:
image: openpxe:0.1.0
build:
context: .
dockerfile: deploy/docker/Dockerfile
environment:
OPENPXE_PUBLIC_IP: ${OPENPXE_PUBLIC_IP:-127.0.0.1}
OPENPXE_DHCP_MODE: disabled
OPENPXE_HTTP_PORT: "8080"
OPENPXE_TFTP_PORT: "6969"
OPENPXE_DHCP_PORT: "6767"
OPENPXE_LOG: info,openpxe=debug
ports:
- "8080:8080/tcp"
- "6969:6969/udp"
volumes:
- ./data/isos:/var/lib/openpxe/isos
- ./data/work:/var/lib/openpxe/work
- ./data/isos:/var/lib/openpxe/isos # uploaded / seeded .iso files
- ./data/work:/var/lib/openpxe/work # settings, share state, scratch