# ------------------------------------------------------------------ # ██╗██████╗ ██╗ ██╗███████╗ Lightweight HTTP server # ██║██╔══██╗╚██╗██╔╝██╔════╝ for network booting. # ██║██████╔╝ ╚███╔╝ █████╗ # ██║██╔═══╝ ██╔██╗ ██╔══╝ Serves boot menus, kernels, and images # ██║██║ ██╔╝ ██╗███████╗ # ╚═╝╚═╝ ╚═╝ ╚═╝╚══════╝ Version 1.0.0 # ███████╗███████╗██████╗ ██╗ ██╗███████╗██████╗ # ██╔════╝██╔════╝██╔══██╗██║ ██║██╔════╝██╔══██╗ # ███████╗█████╗ ██████╔╝██║ ██║█████╗ ██████╔╝ # ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██╔══╝ ██╔══██╗ # ███████║███████╗██║ ██║ ╚████╔╝ ███████╗██║ ██║ # ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝ # Author: Kevin [+ Claude] # Created: 2025-02-02 # ------------------------------------------------------------------ FROM docker.io/library/alpine:3.21 AS base # Install runtime dependencies RUN apk add --no-cache \ nginx \ curl \ tzdata \ tini \ && rm -rf /var/cache/apk/* # Create ipxe user RUN addgroup -g 1000 ipxe && \ adduser -D -s /sbin/nologin -u 1000 -G ipxe ipxe # Create directory structure RUN mkdir -p \ /srv/boot \ /srv/menus \ /srv/images \ /srv/scripts \ /etc/ipxe \ /var/log/nginx \ /var/lib/nginx \ /run/nginx && \ chown -R ipxe:ipxe /srv /var/log/nginx /var/lib/nginx /run/nginx # nginx configuration for iPXE RUN cat > /etc/nginx/nginx.conf << 'EOF' worker_processes auto; error_log /var/log/nginx/error.log warn; pid /run/nginx/nginx.pid; events { worker_connections 256; use epoll; } http { include /etc/nginx/mime.types; default_type application/octet-stream; # Custom MIME types for iPXE types { application/octet-stream ipxe efi; text/plain ipxe menu; } log_format ipxe '$remote_addr - [$time_local] "$request" $status $body_bytes_sent ' '"$http_user_agent" rt=$request_time'; access_log /var/log/nginx/access.log ipxe; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; # Disable buffering for faster boot file delivery proxy_buffering off; server { listen 8080; server_name _; root /srv; # Boot files (kernels, initramfs, iPXE binaries) location /boot/ { alias /srv/boot/; autoindex on; autoindex_exact_size off; autoindex_localtime on; } # iPXE menus and scripts location /menus/ { alias /srv/menus/; autoindex on; default_type text/plain; } # ISO/squashfs images location /images/ { alias /srv/images/; autoindex on; autoindex_exact_size on; # Support range requests for large files add_header Accept-Ranges bytes; } # Dynamic menu endpoint (can be extended with scripts) location /menu { alias /srv/menus/boot.ipxe; default_type text/plain; } # Health check endpoint location /health { access_log off; return 200 'OK\n'; add_header Content-Type text/plain; } # Status page location /status { stub_status on; access_log off; } } } EOF # Health check script RUN cat > /usr/local/bin/healthcheck.sh << 'EOF' #!/bin/sh set -e curl -sf http://localhost:8080/health > /dev/null || exit 1 echo "iPXE server healthy" EOF RUN chmod +x /usr/local/bin/healthcheck.sh # Entrypoint script RUN cat > /usr/local/bin/entrypoint.sh << 'EOF' #!/bin/sh set -e echo "=== iPXE Boot Server ===" echo "Boot files: /srv/boot" echo "Menus: /srv/menus" echo "Images: /srv/images" echo "" # List available boot assets echo "Available boot files:" ls -la /srv/boot/ 2>/dev/null || echo " (none)" echo "" echo "Available menus:" ls -la /srv/menus/ 2>/dev/null || echo " (none)" echo "" # Validate nginx config nginx -t # Start nginx in foreground exec nginx -g 'daemon off;' EOF RUN chmod +x /usr/local/bin/entrypoint.sh # Default boot menu template RUN cat > /srv/menus/boot.ipxe << 'EOF' #!ipxe # iPXE Boot Menu - NUC Home Server # Served via Caddy reverse proxy set menu-timeout 30000 set menu-default local :start menu iPXE Boot Menu - nuc.lan item --gap -- -------- Boot Options -------- item local Boot from local disk item --gap -- -------- Network Boot -------- item fedora-live Fedora 42 Live (Minimal) item fedora-kiosk Fedora 42 Kiosk/PoS item fedora-rescue Fedora 42 Rescue item --gap -- -------- Utilities -------- item memtest Memtest86+ item shell iPXE Shell item reboot Reboot item exit Exit to BIOS choose --timeout ${menu-timeout} --default ${menu-default} selected || goto cancel goto ${selected} :cancel echo Boot cancelled goto start :local sanboot --no-describe --drive 0x80 || goto start :fedora-live echo Booting Fedora 42 Live (Minimal)... set base-url http://ipxe.nuc.lan/images/fedora-42 kernel ${base-url}/vmlinuz initrd=initrd.img root=live:${base-url}/squashfs.img rd.live.image rd.live.overlay.overlayfs=1 quiet initrd ${base-url}/initrd.img boot || goto start :fedora-kiosk echo Booting Fedora 42 Kiosk... set base-url http://ipxe.nuc.lan/images/fedora-42-kiosk kernel ${base-url}/vmlinuz initrd=initrd.img root=live:${base-url}/squashfs.img rd.live.image quiet initrd ${base-url}/initrd.img boot || goto start :fedora-rescue echo Booting Fedora 42 Rescue... set base-url http://ipxe.nuc.lan/images/fedora-42 kernel ${base-url}/vmlinuz initrd=initrd.img rescue quiet initrd ${base-url}/initrd.img boot || goto start :memtest echo Loading Memtest86+... kernel http://ipxe.nuc.lan/boot/memtest86+.bin boot || goto start :shell echo Dropping to iPXE shell... shell :reboot reboot :exit exit EOF EXPOSE 8080 USER ipxe WORKDIR /srv ENTRYPOINT ["/sbin/tini", "--"] CMD ["/usr/local/bin/entrypoint.sh"] LABEL maintainer="Kevin" \ version="1.0.0" \ description="iPXE boot server for network booting"