# Dockerfile.bastion -- PXE boot server (dnsmasq DHCP/TFTP + HTTP) # Requires host networking and NET_ADMIN/NET_RAW capabilities. # ── Stage 1: Build ─────────────────────────────────────────────── FROM node:22-alpine AS builder RUN corepack enable && corepack prepare pnpm@9.15.0 --activate WORKDIR /app # Copy workspace config and package manifests first (layer cache) COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json tsconfig.json ./ COPY src/shared/package.json src/shared/tsconfig.json src/shared/ COPY src/bastion/package.json src/bastion/tsconfig.json src/bastion/ COPY src/cli/package.json src/cli/tsconfig.json src/cli/ COPY src/modules/package.json src/modules/tsconfig.json src/modules/ # Install all dependencies (dev included -- needed for build) RUN pnpm install --frozen-lockfile # Copy source code COPY src/shared/src/ src/shared/src/ COPY src/bastion/src/ src/bastion/src/ COPY src/cli/src/ src/cli/src/ COPY src/modules/src/ src/modules/src/ COPY src/modules/modules/ src/modules/modules/ # Build TypeScript RUN pnpm build # ── Stage 1b: Build iPXE snp.efi (uses UEFI SNP protocol for ISO boot) ── FROM fedora:43 AS ipxe-builder RUN dnf install -y git gcc make perl-interpreter xz-devel gcc-aarch64-linux-gnu && dnf clean all RUN git clone --depth=1 https://github.com/ipxe/ipxe.git /tmp/ipxe RUN cd /tmp/ipxe/src && make bin-x86_64-efi/snp.efi && \ make CROSS_COMPILE=aarch64-linux-gnu- bin-arm64-efi/snp.efi # ── Stage 2: Production runtime (Fedora -- needs dnsmasq) ─────── FROM fedora:43 RUN dnf install -y \ dnsmasq \ ipxe-bootimgs-x86 \ ipxe-bootimgs-aarch64 \ iproute \ curl \ openssh-clients \ nodejs \ npm \ xorriso \ mtools \ && dnf clean all # iPXE snp.efi built from source (Fedora only ships snponly, which can't # boot from CD-ROM/USB -- it requires PXE chainloading) COPY --from=ipxe-builder /tmp/ipxe/src/bin-x86_64-efi/snp.efi /usr/share/ipxe/ipxe-snp-x86_64.efi COPY --from=ipxe-builder /tmp/ipxe/src/bin-arm64-efi/snp.efi /usr/share/ipxe/arm64-efi/ipxe-snp.efi # Install pnpm RUN npm install -g pnpm@9 WORKDIR /app # Copy workspace config and package manifests COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./ COPY src/shared/package.json src/shared/ COPY src/bastion/package.json src/bastion/ COPY src/cli/package.json src/cli/ COPY src/modules/package.json src/modules/ # Install production dependencies RUN pnpm install --frozen-lockfile --prod 2>/dev/null || pnpm install --prod # Copy built output from builder COPY --from=builder /app/src/shared/dist/ src/shared/dist/ COPY --from=builder /app/src/bastion/dist/ src/bastion/dist/ COPY --from=builder /app/src/cli/dist/ src/cli/dist/ COPY --from=builder /app/src/modules/dist/ src/modules/dist/ # Create data directories RUN mkdir -p /data/state /data/tftp /data/http ENV NODE_ENV=production ENV BASTION_DIR=/data ENV HTTP_PORT=8080 EXPOSE 8080/tcp EXPOSE 67/udp EXPOSE 69/udp EXPOSE 4011/udp ENTRYPOINT ["node", "src/cli/dist/index.js", "init", "bastion", "standalone", "start", "--foreground"]