PXE (Preboot Execution Environment)
PXE(Preboot Execution Environment)는 네트워크를 통해 운영체제를 부팅하는 업계 표준 기술입니다. 이 문서에서는 PXE의 역사와 스펙 구조부터 DHCP/BOOTP 프로토콜 상세, TFTP/HTTP 파일 전송, PXE ROM과 UNDI 드라이버, NBP(Network Bootstrap Program) 체인로딩, iPXE 고급 스크립팅, UEFI PXE/HTTP Boot, PXELINUX/GRUB 네트워크 부트로더, iSCSI/NFS 루트 파일시스템, 대규모 프로비저닝(Cobbler/MAAS/Foreman/FOG), Secure PXE Boot, 리눅스 커널 네트워크 부팅 파라미터, 디스크리스(diskless) 부팅 구성, 그리고 트러블슈팅까지 네트워크 부팅의 모든 것을 심층 분석합니다.
핵심 요약
- PXE — Intel이 1999년에 제정한 네트워크 부팅 표준. 펌웨어(BIOS/UEFI)에 내장된 PXE ROM이 DHCP+TFTP로 부트 파일을 받아 실행합니다.
- DHCP Option 66/67 — 실무에서 많이 쓰는 TFTP 서버/부트 파일 전달 수단입니다. 다만 장애 분석 시에는
siaddr,file, Option 66/67, ProxyDHCP 응답을 함께 봐야 합니다. - NBP — Network Bootstrap Program. PXELINUX, GRUB, iPXE 등 네트워크를 통해 전달되는 1차 부트로더입니다.
- iPXE — 오픈소스 PXE 구현. HTTP/HTTPS, iSCSI, Wi-Fi, 스크립팅 등 레거시 PXE의 한계를 넘는 기능을 제공합니다.
- UEFI HTTP Boot — UEFI가 정의한 현대적 네트워크 부팅 경로입니다. TFTP 대신 HTTP/HTTPS URI로 EFI 이미지를 전달합니다.
단계별 이해
- 펌웨어가 NIC를 깨운다
BIOS는 PXE Option ROM과 UNDI를, UEFI는 SNP/MNP와 PXE Base Code 또는 HTTP Boot 스택을 사용해 네트워크를 초기화합니다. - DHCP로 "어디서 무엇을 받을지" 묻는다
클라이언트는 IP 주소만 받는 것이 아니라, 부트 파일 이름, 다음 서버, 아키텍처 코드, 벤더 클래스까지 함께 협상합니다. - 첫 번째 로더(NBP)를 가져온다
레거시 PXE는 주로 TFTP로pxelinux.0같은 NBP를 가져오고, UEFI HTTP Boot는 HTTP URI로shimx64.efi나grubx64.efi를 받습니다. - NBP가 커널과 initrd를 로드한다
PXELINUX, GRUB, iPXE가 커널 파라미터를 조합하고, 필요하면 HTTP, iSCSI, NFS 같은 더 고급 프로토콜로 2차 리소스를 가져옵니다. - 진짜 난이도는 rootfs부터 시작된다
네트워크 부팅 성공은 1차 로더 전달로 끝나지 않습니다. initramfs 안의 NIC 드라이버, NFS/iSCSI 재연결, Secure Boot 체인, 자동 설치 스크립트가 최종 성공을 좌우합니다.
실무 선택 가이드
현장에서 "PXE"라는 말을 넓게 쓰는 경우가 많지만, 실제로는 Legacy PXE, UEFI PXE, UEFI HTTP Boot, iPXE 체인로딩이 서로 다른 설계 선택지입니다. 무엇을 고를지는 펌웨어 모드, Secure Boot 요구사항, 이미지 크기, 운영 자동화 수준, 루트 파일시스템 방식에 따라 달라집니다.
| 환경 | 우선 선택 | 이유 | 주의점 |
|---|---|---|---|
| 구형 서버, BIOS 전용 | PXELINUX 또는 undionly.kpxe | 가장 폭넓은 호환성. 기존 PXE ROM이 바로 이해 가능 | TFTP 성능이 낮고, Secure Boot 개념이 없음 |
| BIOS지만 대형 이미지, 동적 메뉴, iSCSI 필요 | iPXE 체인로딩 | 첫 단계만 TFTP, 이후는 HTTP/HTTPS/iSCSI로 전환 가능 | DHCP에서 iPXE 무한 루프를 반드시 차단해야 함 |
| UEFI + 표준 네트워크 부팅만 필요 | UEFI PXE | 펌웨어 기본 기능만으로 구현 가능 | 여전히 TFTP 중심이라 대규모 동시 부팅에는 비효율적 |
| UEFI + 큰 EFI 이미지 + 빠른 전송 | UEFI HTTP Boot | Boot URI를 직접 전달하므로 웹 서버 인프라 활용이 쉬움 | 펌웨어별 HTTP/HTTPS/TLS 구현 편차가 큼 |
| UEFI + Secure Boot 필수 | shim + GRUB 또는 서명된 iPXE | 서명 검증 체인과 배포판 기본 신뢰 체계를 재사용 가능 | 서명되지 않은 ipxe.efi는 기본적으로 거부될 수 있음 |
| 호스트별 분기, API 연동, 메타데이터 기반 부팅 | iPXE 스크립트 | MAC/UUID/Serial/Platform 기반 동적 정책 구현에 가장 유연 | DHCP보다 HTTP API 계층의 가용성과 인증이 더 중요해짐 |
| 진짜 디스크리스 운영 | PXE/iPXE + NFS root 또는 iSCSI SAN boot | 로컬 디스크 없이 운영체제 유지 가능 | 부팅보다 initramfs, 드라이버 내장, rootfs 재연결이 더 어렵다 |
| BIOS/UEFI 혼재 환경 | Option 93 분기 + iPXE 혼합 | 하나의 DHCP 정책에서 아키텍처별 NBP를 정교하게 나눌 수 있음 | IANA 아키텍처 코드와 HTTP Boot 코드를 정확히 관리해야 함 |
PXE 역사와 스펙 진화
역사적 타임라인
| 연도 | 기술 | 설명 |
|---|---|---|
| 1981 | BOOTP (RFC 951) | 최초의 네트워크 부팅 프로토콜. UDP 67/68 포트 사용. 정적 매핑 기반 |
| 1985 | RARP (RFC 903) | Reverse ARP. MAC→IP 역변환. 간단하지만 라우터 통과 불가 |
| 1993 | DHCP (RFC 1531) | BOOTP 확장. 동적 IP 할당, 옵션 확장 가능 |
| 1997 | DHCP Options (RFC 2132) | Option 66(TFTP server), 67(bootfile) 등 부팅 관련 옵션 표준화 |
| 1999 | PXE 2.1 (Intel) | Intel이 제정한 업계 표준. UNDI API, PXE Base Code, ProxyDHCP 정의 |
| 2006 | gPXE | Etherboot 후속. HTTP, iSCSI, DNS 지원 추가 |
| 2010 | iPXE | gPXE 포크. HTTPS, Wi-Fi, 스크립팅, SAN boot 등 현대적 기능 |
| 2015 | UEFI HTTP Boot | UEFI 2.5 스펙에 HTTP(S) 부팅 공식 포함 |
| 2020+ | UEFI HTTPS Boot + Redfish | HTTPS 기반 부팅과 BMC/Redfish 자동화가 결합된 운영 패턴 확산 |
PXE 2.1 스펙 구조
Intel PXE 스펙 2.1은 다음 컴포넌트로 구성됩니다:
| 컴포넌트 | 역할 | 상세 |
|---|---|---|
| PXE Base Code | 핵심 프로토콜 엔진 | DHCP/TFTP/UDP/IP 스택. BIOS에서는 16비트 리얼모드 API |
| UNDI | Universal Network Driver Interface | NIC 하드웨어 추상화. PXE API가 NIC를 제어하는 표준 인터페이스 |
| PXE Boot Server | 부팅 서버 프로토콜 | Boot Server Discovery Protocol. 여러 부팅 서버 중 선택 |
| ProxyDHCP | DHCP 보조 서버 | 기존 DHCP 변경 없이 PXE 옵션만 추가 전달 |
| BIS | Boot Integrity Services | 부팅 파일 무결성 검증 (실무에서는 거의 미사용) |
PXE 부팅 전체 흐름
4단계 부팅 과정
PXE 부팅은 크게 4단계로 진행됩니다: (1) DHCP 디스커버리 → (2) NBP 다운로드 → (3) 커널/initrd 로드 → (4) OS 부팅
상세 단계별 분석
Step 1: 전원 투입 → PXE ROM 실행
- BIOS POST 완료 후 부팅 장치 순회
- NIC의 Option ROM(PXE ROM) 발견 → 시그니처
0x55AA확인 - PXE ROM이 메모리에 로드되어
INT 19h부팅 벡터 설정 - PXE Base Code 초기화: UNDI 드라이버 로드 → NIC 활성화
Step 2: DHCP 4-Way Handshake (DORA)
Client Server
| |
|--- DHCPDISCOVER (broadcast) --| src: 0.0.0.0:68 → 255.255.255.255:67
| Option 60: PXEClient:Arch | Option 93: Client System Architecture
| Option 94: Client NDI | Option 97: Client Machine Identifier (UUID)
| |
|------ DHCPOFFER --------------| 서버 → 클라이언트 (unicast 또는 broadcast)
| yiaddr: 192.168.1.100 | 할당할 IP 주소
| siaddr: 192.168.1.1 | TFTP 서버 주소 (next-server)
| file: "pxelinux.0" | 부트 파일명
| |
|--- DHCPREQUEST ---------------| 선택한 서버에 IP 요청 확인
| |
|------ DHCPACK ----------------| IP 할당 확정 + 모든 옵션 전달
| |
Step 3: NBP 다운로드 및 실행
- PXE Base Code가 TFTP 클라이언트를 실행
siaddr(next-server)에서file(filename) 다운로드- NBP를 메모리
0x7C00(리얼모드) 또는 지정 주소에 로드 - PXE API 테이블 포인터를 레지스터에 설정한 후 NBP로 점프
Step 4: NBP가 커널 로드
- NBP(PXELINUX 등)가 PXE API를 통해 설정 파일 요청
- 설정 파일에 지정된 커널(
vmlinuz)과 initrd 다운로드 - 커널 커맨드 라인 설정 (예:
root=/dev/nfs nfsroot=...) - Protected Mode 전환 후 커널 엔트리 포인트로 점프
DHCP/BOOTP 프로토콜 심화
DHCP 패킷 구조
DHCP는 BOOTP(RFC 951)를 기반으로 확장된 프로토콜(RFC 2131)입니다. PXE 부팅에서 핵심적인 패킷 구조:
/* DHCP/BOOTP 패킷 구조 (RFC 2131) */
struct dhcp_packet {
uint8_t op; /* 1=BOOTREQUEST, 2=BOOTREPLY */
uint8_t htype; /* 하드웨어 타입: 1=Ethernet */
uint8_t hlen; /* 하드웨어 주소 길이: 6 (MAC) */
uint8_t hops; /* 릴레이 에이전트 홉 수 */
uint32_t xid; /* 트랜잭션 ID */
uint16_t secs; /* 클라이언트 시작 후 경과 시간 */
uint16_t flags; /* bit0=Broadcast flag */
uint32_t ciaddr; /* Client IP (이미 할당된 경우) */
uint32_t yiaddr; /* Your IP (서버가 할당하는 IP) */
uint32_t siaddr; /* Server IP (next-server = TFTP 서버) */
uint32_t giaddr; /* Gateway IP (릴레이 에이전트) */
uint8_t chaddr[16]; /* Client hardware address (MAC) */
char sname[64]; /* Server host name (옵션) */
char file[128]; /* Boot file name (NBP 경로) */
uint8_t options[]; /* DHCP 옵션 (magic cookie 0x63825363 시작) */
}; /* 최소 크기: 300 bytes, 일반적으로 576 bytes */
PXE 관련 핵심 DHCP 옵션
| 옵션 번호 | 이름 | 용도 | 예시 값 |
|---|---|---|---|
| 60 | Vendor Class Identifier | PXE 클라이언트 식별 | "PXEClient:Arch:00000:UNDI:002001" |
| 66 | TFTP Server Name | TFTP 서버 호스트명/IP | "192.168.1.1" |
| 67 | Bootfile Name | NBP 파일 경로 | "pxelinux.0" 또는 "grubx64.efi" |
| 93 | Client System Architecture | 클라이언트 아키텍처 | 0x0000(x86 BIOS), 0x0007(x64 UEFI), 0x000B(ARM64 UEFI) |
| 94 | Client Network Interface | UNDI 버전 정보 | UNDI:003:010 (v3.10) |
| 97 | Client Machine Identifier | UUID/GUID | SMBIOS에서 가져온 시스템 UUID |
| 128-135 | PXE Vendor Options | 벤더별 확장 | 멀티캐스트 부팅, 자격 증명 등 |
| 175 | iPXE Encapsulated | iPXE 전용 옵션 | iPXE 스크립트 URL 등 |
| 209 | PXELINUX Config | 설정 파일 경로 | "pxelinux.cfg/default" |
| 210 | PXELINUX Pathprefix | TFTP 경로 접두사 | "/tftpboot/linux/" |
DHCP 필드 우선순위와 해석
실무에서 가장 많이 헷갈리는 부분은 "부트 파일 정보가 정확히 어디에 들어가느냐"입니다. RFC 2132 관점에서 Option 66/67은 sname/file 필드를 다른 용도로 오버로드했을 때의 보조 수단이지만, 실제 PXE/UEFI 펌웨어는 BOOTP 헤더와 DHCP 옵션을 함께 해석합니다.
| 위치 | 일반적 의미 | 실무 포인트 |
|---|---|---|
siaddr | next-server, 부트 서버 주소 | 레거시 PXE에서 가장 먼저 확인할 필드 중 하나입니다. |
file 헤더 필드 | NBP 이름 또는 Boot URI | UEFI HTTP Boot에서는 여기 자체에 http://... URI가 들어갈 수 있습니다. |
| Option 66 | TFTP Server Name | sname를 다른 목적으로 쓸 때 보조적으로 전달됩니다. 일부 서버는 관행적으로 항상 같이 보냅니다. |
| Option 67 | Bootfile Name | file 필드를 대체하거나 보완합니다. HTTP Boot에서는 URI를 담는 구현도 흔합니다. |
| Option 60 | Vendor Class | PXEClient와 HTTPClient를 구분해 BIOS/UEFI/HTTP Boot 정책을 나눕니다. |
| ProxyDHCP 응답 | PXE 전용 부가 정보 | 동일한 DORA 흐름처럼 보이지만, 실제로는 DHCP 서버 응답과 합쳐서 해석됩니다. |
siaddr, file, Option 66/67, ProxyDHCP(4011) 응답을 모두 캡처해서 비교해야 정확합니다.
아키텍처 자동 감지와 부트파일 분기
DHCP Option 93을 사용하여 클라이언트 아키텍처를 감지하고, 적절한 부트 파일을 제공합니다. 아래 값은 현장에서 자주 보게 되는 대표값이며, 최종 권위는 RFC 4578의 초기 표보다 IANA Processor Architecture Types 레지스트리에 있습니다.
| Option 93 값 | 아키텍처 | 권장 부트파일 |
|---|---|---|
0x0000 (0) | x86 BIOS (IA-32) | pxelinux.0 또는 undionly.kpxe |
0x0006 (6) | x86 UEFI (32-bit) | syslinux.efi32 또는 grubia32.efi |
0x0007 (7) | x64 UEFI (64-bit) | grubx64.efi 또는 shimx64.efi |
0x0009 (9) | EFI Byte Code (EBC) | ipxe.efi 또는 EBC 지원 EFI 애플리케이션 |
0x000A (10) | ARM 32-bit UEFI | grubarm.efi |
0x000B (11) | ARM64 UEFI (AArch64) | grubaa64.efi |
0x000F (15) | x86 UEFI HTTP Boot | http://server/boot/bootia32.efi |
0x0010 (16) | x64 UEFI HTTP Boot | http://server/boot/shimx64.efi |
0x0013 (19) | ARM64 UEFI HTTP Boot | http://server/boot/shimaa64.efi |
0x0019 (25) | RISC-V 32-bit UEFI | grubriscv32.efi |
0x001B (27) | RISC-V 64-bit UEFI | grubriscv64.efi |
Option 93=0x0010 같은 HTTP Boot 코드와 함께 Vendor Class가 HTTPClient인지도 확인해야, TFTP용 .efi와 HTTP URI를 잘못 섞는 사고를 막을 수 있습니다.
ISC DHCP 서버 PXE 설정 예제
# /etc/dhcp/dhcpd.conf - PXE 부팅을 위한 ISC DHCP 설정
# 전역 옵션
option arch-type code 93 = unsigned integer 16;
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.100 192.168.1.200;
option routers 192.168.1.1;
option domain-name-servers 8.8.8.8;
next-server 192.168.1.10; # TFTP 서버 주소
# 아키텍처별 부트파일 분기
if option arch-type = 00:07 {
# x64 UEFI 클라이언트
filename "grubx64.efi";
} elsif option arch-type = 00:0B {
# ARM64 UEFI 클라이언트
filename "grubaa64.efi";
} elsif option arch-type = 00:00 {
# Legacy BIOS 클라이언트
filename "pxelinux.0";
}
# 특정 MAC 주소에 고정 IP 할당
host server01 {
hardware ethernet 00:11:22:33:44:55;
fixed-address 192.168.1.50;
filename "pxelinux.0";
}
}
dnsmasq PXE 설정 예제
# /etc/dnsmasq.conf - dnsmasq PXE 부팅 설정 (DHCP + TFTP 통합)
# DHCP 범위
dhcp-range=192.168.1.100,192.168.1.200,255.255.255.0,12h
# 내장 TFTP 서버 활성화
enable-tftp
tftp-root=/var/lib/tftpboot
# PXE 아키텍처별 부트파일 분기
# tag:x86PC = BIOS (arch 0)
# tag:EFI_x64 = UEFI x64 (arch 7)
# tag:EFI_AA64 = UEFI ARM64 (arch 11)
dhcp-match=set:x86PC,option:client-arch,0
dhcp-match=set:EFI_x64,option:client-arch,7
dhcp-match=set:EFI_AA64,option:client-arch,11
dhcp-boot=tag:x86PC,pxelinux.0
dhcp-boot=tag:EFI_x64,grubx64.efi
dhcp-boot=tag:EFI_AA64,grubaa64.efi
# ProxyDHCP 모드 (기존 DHCP 서버가 있을 때)
# dhcp-range=192.168.1.0,proxy
# pxe-service=x86PC,"PXE Boot",pxelinux
# pxe-service=X86-64_EFI,"PXE Boot UEFI",grubx64.efi
# iPXE 체인로딩: 일반 PXE는 iPXE를 로드, iPXE는 스크립트를 로드
dhcp-match=set:ipxe,175 # iPXE sends option 175
dhcp-boot=tag:!ipxe,undionly.kpxe
dhcp-boot=tag:ipxe,http://192.168.1.10/boot.ipxe
# DHCP 로깅
log-dhcp
ProxyDHCP 메커니즘
ProxyDHCP 핵심 포인트:
- 기존 DHCP 서버의 IP 할당을 방해하지 않음
- ProxyDHCP는 yiaddr=0.0.0.0으로 응답 (IP를 할당하지 않음)
- PXE 클라이언트는 두 응답을 모두 수신하여 병합
- ProxyDHCP는 port 67 (broadcast) 또는 port 4011 (unicast) 사용
- dnsmasq의 dhcp-range=...,proxy 옵션으로 간단히 구성 가능
DHCP 옵션 바이너리 인코딩
DHCP 옵션은 TLV(Type-Length-Value) 형식으로 인코딩됩니다. PXE 관련 옵션의 실제 바이트 구조를 이해하면 패킷 분석과 트러블슈팅에 도움됩니다.
BOOTP vs DHCP vs PXE 패킷 비교
세 프로토콜은 동일한 패킷 구조를 공유하지만, 사용하는 필드와 옵션이 다릅니다:
| 필드/기능 | BOOTP (RFC 951) | DHCP (RFC 2131) | PXE (Intel 2.1) |
|---|---|---|---|
| 패킷 구조 | 300 bytes 고정 | 576+ bytes (옵션 확장) | DHCP + 벤더 확장 |
op 필드 | 1(req)/2(reply) | 동일 | 동일 |
siaddr | 부팅 서버 IP | next-server | TFTP 서버 (Option 66 우선) |
file (128B) | 부트 파일명 | 부트 파일명 | NBP 경로 (Option 67 우선) |
| IP 할당 | 정적 매핑만 | 동적 풀 + 정적 | DHCP 방식 사용 |
| 옵션 영역 | 64 bytes (vendor) | 가변 (magic cookie 이후) | DHCP + PXE 전용 옵션 |
| Magic Cookie | 없음 | 0x63825363 | 동일 |
| 메시지 타입 | 없음 | Option 53 | 동일 |
| 아키텍처 감지 | 불가 | 불가 (표준) | Option 93 (arch type) |
| UUID 전달 | 불가 | 불가 (표준) | Option 97 (UUID) |
| ProxyDHCP | 불가 | 불가 | port 4011 유니캐스트 |
| 재시도 | 단순 타임아웃 | 지수 백오프 | DHCP 방식 + PXE 타임아웃 |
/* BOOTP와 DHCP의 옵션 영역 차이 */
/* BOOTP: 64바이트 vendor-specific 영역 (RFC 951) */
struct bootp_packet {
/* ... 공통 필드 ... */
uint8_t vend[64]; /* vendor-specific area */
};
/* 매우 제한적: 서브넷 마스크, 게이트웨이 정도만 전달 가능 */
/* DHCP: 가변 길이 옵션 영역 (RFC 2131) */
struct dhcp_packet {
/* ... 공통 필드 (BOOTP와 동일) ... */
uint8_t options[]; /* 가변 길이, magic cookie 0x63825363로 시작 */
};
/* Magic Cookie 다음에 TLV 형식 옵션이 이어짐:
* [Type:1B][Length:1B][Value:N bytes] ...
* 마지막에 0xFF(End) 옵션
*
* PXE 확장:
* - Option 60: "PXEClient:Arch:NNNNN:UNDI:MMMMMM"
* - Option 93: 2바이트 아키텍처 코드 (0=BIOS, 7=x64UEFI, 11=ARM64)
* - Option 94: UNDI 버전 (major.minor)
* - Option 97: 1바이트 타입 + 16바이트 UUID (SMBIOS)
* - Option 175: iPXE 캡슐화 옵션
*/
TFTP 프로토콜 심화
TFTP 개요
TFTP(Trivial File Transfer Protocol, RFC 1350)는 PXE의 기본 파일 전송 프로토콜입니다. UDP 기반으로 매우 단순하지만, 그만큼 한계가 있습니다.
| 특성 | TFTP | FTP | HTTP |
|---|---|---|---|
| 전송 계층 | UDP (포트 69) | TCP (포트 20/21) | TCP (포트 80/443) |
| 인증 | 없음 | 사용자/비밀번호 | 다양 (Basic, Token, ...) |
| 블록 크기 | 512B (기본), 최대 65464B | 가변 | 가변 |
| 최대 파일 크기 | ~32MB (512B블록), ~4GB (확장) | 무제한 | 무제한 |
| 디렉토리 목록 | 불가 | 가능 | 가능 |
| 보안 | 없음 | TLS (FTPS) | TLS (HTTPS) |
| PXE 지원 | 모든 PXE ROM | 미지원 | iPXE, UEFI HTTP Boot |
TFTP 패킷 타입
/* TFTP 패킷 타입 (RFC 1350) */
#define TFTP_RRQ 1 /* Read Request - 파일 읽기 요청 */
#define TFTP_WRQ 2 /* Write Request - 파일 쓰기 요청 (PXE에서 미사용) */
#define TFTP_DATA 3 /* Data - 데이터 블록 전송 */
#define TFTP_ACK 4 /* Acknowledgment - 데이터 수신 확인 */
#define TFTP_ERROR 5 /* Error - 오류 메시지 */
#define TFTP_OACK 6 /* Option ACK - 옵션 협상 응답 (RFC 2347) */
/* RRQ/WRQ 패킷 구조 */
struct tftp_rrq {
uint16_t opcode; /* 1 (RRQ) */
char filename[]; /* NUL 종료 문자열, 예: "pxelinux.0\0" */
char mode[]; /* "octet\0" (바이너리 모드) */
/* 이하 옵션들 (RFC 2347): "blksize\0" "1468\0" "tsize\0" "0\0" */
};
/* DATA 패킷 구조 */
struct tftp_data {
uint16_t opcode; /* 3 (DATA) */
uint16_t block; /* 블록 번호 (1부터 시작) */
uint8_t data[]; /* 데이터 (최대 blksize 바이트) */
};
/* 마지막 블록: data 길이 < blksize → 전송 완료 */
TFTP 확장 옵션 (RFC 2347-2349)
| 옵션 | RFC | 설명 | 기본값 | 권장값 |
|---|---|---|---|---|
blksize | RFC 2348 | 블록 크기 (8-65464) | 512 | 1468 (MTU 최적화) |
tsize | RFC 2349 | 전송 크기 (바이트) | 미지원 | 요청: 0 → 응답: 실제 크기 |
timeout | RFC 2349 | 재전송 타임아웃 (초) | 미정의 | 1-5 |
windowsize | RFC 7440 | 윈도우 크기 (블록 수) | 1 | 4-64 (성능 향상) |
blksize=1468과 windowsize=64를 설정하면 전송 효율이 큰 폭으로 개선됩니다. 대규모 환경에서는 HTTP 기반 부팅(iPXE/UEFI HTTP Boot)을 권장합니다.
TFTP 서버 구성
# tftpd-hpa 설치 및 설정 (Debian/Ubuntu)
sudo apt install tftpd-hpa
# /etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/var/lib/tftpboot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="--secure --create --verbose --blocksize 1468"
# 디렉토리 구조
/var/lib/tftpboot/
├── pxelinux.0 # BIOS NBP (SYSLINUX 패키지)
├── lpxelinux.0 # BIOS NBP + HTTP 지원
├── ldlinux.c32 # SYSLINUX 필수 모듈
├── libutil.c32 # SYSLINUX 유틸리티
├── menu.c32 # 텍스트 메뉴 모듈
├── vesamenu.c32 # 그래픽 메뉴 모듈
├── libcom32.c32 # COM32 라이브러리
├── grubx64.efi # UEFI x64 NBP
├── grubaa64.efi # UEFI ARM64 NBP
├── shimx64.efi # Secure Boot shim
├── undionly.kpxe # iPXE chainload 이미지
├── ipxe.efi # iPXE UEFI 이미지
├── pxelinux.cfg/ # PXELINUX 설정 디렉토리
│ ├── default # 기본 설정 파일
│ ├── C0A80164 # IP 기반 (192.168.1.100 = C0A80164)
│ └── 01-00-11-22-33-44-55 # MAC 기반 설정
├── grub/ # GRUB 네트워크 설정
│ └── grub.cfg
├── vmlinuz # Linux 커널
├── initrd.img # initramfs
└── images/ # OS 설치 이미지
├── ubuntu/
├── rhel/
└── debian/
# TFTP 서비스 시작
sudo systemctl enable --now tftpd-hpa
# 방화벽 설정
sudo firewall-cmd --add-service=tftp --permanent
sudo firewall-cmd --reload
TFTP 윈도우 크기별 전송 비교
RFC 7440의 windowsize 옵션은 TFTP 성능에 극적인 영향을 줍니다. 윈도우 크기가 1(기본)이면 매 블록마다 ACK를 기다려야 하지만, 윈도우 크기를 늘리면 여러 블록을 연속 전송할 수 있습니다.
# TFTP 서버별 windowsize 설정
# tftpd-hpa: windowsize 직접 지원 안함 (blksize만 가능)
# → 대안: atftpd 또는 dnsmasq 사용
# atftpd: windowsize 및 멀티캐스트 지원
sudo apt install atftpd
# /etc/default/atftpd
OPTIONS="--daemon --port 69 --tftpd-timeout 300 \
--retry-timeout 5 --maxthread 100 \
--bind-address 0.0.0.0 \
--logfile /var/log/atftpd.log \
--windowsize 64 --blksize 1468 \
/var/lib/tftpboot"
# dnsmasq: TFTP windowsize 지원 (v2.87+)
# /etc/dnsmasq.d/tftp.conf
enable-tftp
tftp-root=/var/lib/tftpboot
# blksize는 지원하지만 windowsize는 클라이언트 협상에 의존
# iPXE 클라이언트의 TFTP 옵션 협상
# iPXE는 자동으로 blksize=1468, windowsize를 협상
# PXE ROM은 보통 blksize=512, windowsize=1만 지원
# 성능 측정 방법
# 서버에서 전송 속도 모니터링
sudo tcpdump -i eth0 -c 100 port 69 -w /tmp/tftp.pcap
# Wireshark에서 Statistics → I/O Graphs로 처리량 확인
UNDI 드라이버와 PXE ROM
UNDI 개요
UNDI(Universal Network Driver Interface)는 PXE 스펙에서 정의한 NIC 하드웨어 추상화 계층입니다. NBP가 특정 NIC 드라이버 없이도 네트워크 I/O를 수행할 수 있게 합니다.
| UNDI API 함수 | 설명 |
|---|---|
PXENV_UNDI_STARTUP | UNDI 드라이버 초기화 |
PXENV_UNDI_CLEANUP | UNDI 드라이버 정리 |
PXENV_UNDI_INITIALIZE | NIC 하드웨어 초기화 |
PXENV_UNDI_OPEN | NIC 열기 (패킷 수신 시작) |
PXENV_UNDI_CLOSE | NIC 닫기 |
PXENV_UNDI_TRANSMIT | 패킷 전송 |
PXENV_UNDI_SET_PACKET_FILTER | 수신 필터 설정 |
PXENV_UNDI_GET_INFORMATION | NIC 정보 조회 (MAC, IRQ, ...) |
PXENV_UNDI_GET_STATISTICS | 전송/수신 통계 |
PXENV_UNDI_ISR | 인터럽트 서비스 루틴 |
PXENV_UNDI_GET_NIC_TYPE | NIC 타입 (PCI vendor/device ID) |
PXENV_UNDI_GET_IFACE_INFO | 인터페이스 정보 (속도, 이름) |
PXE Option ROM 구조
/* PCI Option ROM 헤더 (BIOS) */
struct option_rom_header {
uint16_t signature; /* 0x55AA - ROM 시그니처 */
uint8_t rom_size; /* ROM 크기 (512바이트 단위) */
uint8_t init_entry[4]; /* 초기화 엔트리 포인트 (JMP 명령) */
uint8_t reserved[17]; /* 예약 */
uint16_t pci_data_ptr; /* PCI Data Structure 오프셋 */
uint16_t pnp_header_ptr;/* PnP Expansion Header 오프셋 */
};
/* PXE ROM 초기화 흐름 (16-bit Real Mode):
*
* 1. BIOS가 PCI 버스를 스캔하여 NIC의 Option ROM BAR 발견
* 2. ROM을 메모리 C000h-DFFFFh 영역에 매핑
* 3. signature 0x55AA 확인 후 init_entry 호출
* 4. PXE ROM이 UNDI 드라이버 설치
* 5. INT 1Ah (PCI BIOS) 연결, INT 18h/19h 부팅 벡터 후킹
* 6. BIOS 부팅 순서에서 네트워크 부팅 선택 시:
* → PXE Base Code 시작 → DHCP → TFTP → NBP 실행
*/
PXE API 호출 메커니즘
; NBP에서 PXE API 호출 예제 (16-bit Real Mode Assembly)
; PXE API는 !PXE 또는 PXENV+ 구조체를 통해 호출
; !PXE 구조체 찾기 (ES:BX에 전달됨)
; BX = !PXE 구조체의 오프셋
; PXENV_TFTP_READ_FILE 호출 예제
mov bx, PXENV_TFTP_READ_FILE ; 함수 번호: 0x0023
mov di, tftp_read_params ; 파라미터 구조체 오프셋
push ds
push di
push bx
call far [pxe_entry_point] ; !PXE EntryPointSP
add sp, 6
; AX = 반환값 (0 = 성공)
; 파라미터 구조체
tftp_read_params:
.status: dw 0 ; 반환 상태
.filename: times 128 db 0 ; 파일명
.buffersize: dd 0 ; 버퍼 크기
.bufferaddr: dd 0 ; 버퍼 세그먼트:오프셋
.serverip: dd 0 ; 서버 IP
.gatewayip: dd 0 ; 게이트웨이 IP
.mcastip: dd 0 ; 멀티캐스트 IP
.tftpport: dw 69 ; TFTP 포트
.tftpblksize: dw 512 ; 블록 크기
PXE 리얼 모드 메모리 맵
BIOS PXE 부팅 시 16-bit 리얼 모드의 메모리 레이아웃은 NBP 개발과 트러블슈팅에 핵심적인 정보입니다. PXE ROM, UNDI 드라이버, NBP 각각이 특정 메모리 영역을 사용합니다.
/* !PXE 구조체 (PXE 2.1 Spec) - NBP가 PXE API에 접근하는 핵심 */
struct pxe_t {
uint8_t Signature[4]; /* "!PXE" */
uint8_t StructLength; /* 구조체 크기 */
uint8_t StructCksum; /* 체크섬 (전체 합=0) */
uint8_t StructRev; /* 구조체 리비전 */
uint8_t reserved1;
SEGOFF16 UNDIROMID; /* UNDI ROM ID 구조체 포인터 */
SEGOFF16 BaseROMID; /* BC ROM ID 구조체 포인터 */
SEGOFF16 EntryPointSP; /* API 진입점 (스택 파라미터) */
SEGOFF16 EntryPointESP; /* API 진입점 (확장 스택) */
SEGOFF16 StatusCallout; /* 콜아웃 함수 포인터 */
uint8_t reserved2;
uint8_t SegDescCnt; /* 세그먼트 디스크립터 수 */
SEGSEL FirstSelector; /* UNDI 코드/데이터 세그먼트 */
/* ... 세그먼트 디스크립터들 ... */
};
/* PXENV+ 구조체 (하위 호환용, PXE 2.0 이전) */
struct pxenv_plus {
uint8_t Signature[6]; /* "PXENV+" */
uint16_t Version; /* PXE 버전 (예: 0x0201) */
uint8_t Length;
uint8_t Checksum;
SEGOFF16 RMEntry; /* 리얼 모드 API 진입점 */
uint32_t PMOffset; /* 프로텍티드 모드 오프셋 */
uint16_t PMSelector; /* 프로텍티드 모드 셀렉터 */
uint16_t StackSeg; /* 스택 세그먼트 */
uint16_t StackSize; /* 스택 크기 */
/* ... */
};
/* NBP에서 !PXE 구조체 탐색 순서:
* 1. ES:BX 레지스터 확인 (BIOS가 전달)
* 2. "!PXE" 시그니처 검증
* 3. 실패 시 "PXENV+" 탐색 (0x9FC00~0xA0000)
* 4. 체크섬 검증 (전체 바이트 합 = 0)
*/
PXELINUX 부트로더
PXELINUX 개요
PXELINUX는 SYSLINUX 프로젝트의 일부로, PXE 환경에서 가장 널리 사용되는 NBP입니다.
| 변종 | 파일 | 특징 |
|---|---|---|
| pxelinux.0 | ~40KB | 기본 BIOS PXE 부트로더. TFTP만 지원 |
| lpxelinux.0 | ~90KB | HTTP, FTP, TFTP 지원. DNS 해석 가능 |
| syslinux.efi | ~200KB | UEFI 모드 PXE 부트로더 |
설정 파일 탐색 순서
PXELINUX는 다음 순서로 설정 파일을 탐색합니다 (첫 번째 발견 파일 사용):
클라이언트 정보:
UUID: b8945908-d6a6-41a9-611d-74a6ab80b83d
MAC: 01-88-99-aa-bb-cc-dd
IP: 192.168.1.100 (hex: C0A80164)
PXELINUX 설정 파일 탐색 순서:
1. pxelinux.cfg/b8945908-d6a6-41a9-611d-74a6ab80b83d ← UUID
2. pxelinux.cfg/01-88-99-aa-bb-cc-dd ← MAC (01- 접두사)
3. pxelinux.cfg/C0A80164 ← 전체 IP (hex)
4. pxelinux.cfg/C0A8016 ← IP 앞 7자리
5. pxelinux.cfg/C0A801 ← IP 앞 6자리
6. pxelinux.cfg/C0A80 ← IP 앞 5자리
7. pxelinux.cfg/C0A8 ← 서브넷 (Class B)
8. pxelinux.cfg/C0A ← 앞 3자리
9. pxelinux.cfg/C0 ← 앞 2자리
10. pxelinux.cfg/C ← 앞 1자리
11. pxelinux.cfg/default ← 기본 설정
→ 이 메커니즘으로 호스트별/서브넷별/전체 기본 설정을 계층적으로 관리할 수 있습니다.
PXELINUX 설정 파일 예제
# /var/lib/tftpboot/pxelinux.cfg/default
# 전역 설정
DEFAULT vesamenu.c32 # 그래픽 메뉴 사용
PROMPT 0 # 자동 메뉴 진입
TIMEOUT 300 # 30초 타임아웃 (1/10초 단위)
ONTIMEOUT local # 타임아웃 시 로컬 부팅
# 메뉴 테마
MENU TITLE PXE Boot Menu
MENU BACKGROUND pxelinux.cfg/splash.png
MENU COLOR border 30;44 #40ffffff #a0000000 std
MENU COLOR title 1;36;44 #9033ccff #a0000000 std
MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
# 로컬 디스크 부팅
LABEL local
MENU LABEL Boot from ^Local Disk
MENU DEFAULT
LOCALBOOT 0
# Ubuntu 24.04 LTS 설치
LABEL ubuntu2404
MENU LABEL ^Ubuntu 24.04 LTS Install
KERNEL images/ubuntu/vmlinuz
INITRD images/ubuntu/initrd
APPEND root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url=http://192.168.1.10/ubuntu-24.04-live-server-amd64.iso autoinstall ds=nocloud-net;s=http://192.168.1.10/autoinstall/
# RHEL 10 계열 설치 (Kickstart)
LABEL rhel10
MENU LABEL ^RHEL 10 Kickstart Install
KERNEL images/rhel/vmlinuz
INITRD images/rhel/initrd.img
APPEND inst.repo=http://192.168.1.10/rhel10/ inst.ks=http://192.168.1.10/ks/rhel10.cfg ip=dhcp
# Debian 13 설치 (Preseed)
LABEL debian13
MENU LABEL ^Debian 13 Trixie Netinstall
KERNEL images/debian/linux
INITRD images/debian/initrd.gz
APPEND auto=true priority=critical url=http://192.168.1.10/preseed/debian13.cfg interface=auto vga=788
# 디스크리스 리눅스 (NFS Root)
LABEL diskless
MENU LABEL ^Diskless Linux (NFS Root)
KERNEL vmlinuz-diskless
INITRD initrd-diskless.img
APPEND root=/dev/nfs nfsroot=192.168.1.10:/exports/diskless,vers=4,tcp ip=dhcp rw
# Memtest86+
LABEL memtest
MENU LABEL ^Memtest86+
KERNEL memtest86+
# iPXE 체인로딩
LABEL ipxe
MENU LABEL ^iPXE Advanced Boot
KERNEL ipxe.lkrn
APPEND dhcp && chain http://192.168.1.10/boot.ipxe
PXELINUX COM32 모듈
| 모듈 | 용도 |
|---|---|
menu.c32 | 텍스트 기반 부팅 메뉴 |
vesamenu.c32 | VESA 그래픽 부팅 메뉴 (배경 이미지 지원) |
chain.c32 | 디스크/파티션 체인로딩 |
memdisk | ISO/플로피/하드 디스크 이미지를 RAM에서 부팅 |
pxechn.c32 | 다른 PXE 서버로 체인로딩 |
reboot.c32 | 시스템 재부팅 |
poweroff.c32 | 시스템 종료 (APM/ACPI) |
hdt.c32 | 하드웨어 정보 표시 |
ifcpu64.c32 | CPU 아키텍처(32/64비트) 감지 분기 |
linux.c32 | Linux 커널 직접 로드 |
GRUB 네트워크 부팅
GRUB PXE 개요
GRUB2는 UEFI 환경에서 가장 널리 사용되는 네트워크 부트로더입니다. PXELINUX보다 기능이 풍부하고 UEFI Secure Boot를 지원합니다.
GRUB 네트워크 설정
# /var/lib/tftpboot/grub/grub.cfg - GRUB 네트워크 부팅 설정
set default=0
set timeout=30
# 변수 설정
set pxe_server="192.168.1.10"
set nfs_server="192.168.1.10"
# 메뉴 테마
loadfont unicode
set gfxmode=auto
insmod all_video
insmod gfxterm
terminal_output gfxterm
menuentry "Boot from Local Disk" {
exit
}
menuentry "Ubuntu 24.04 LTS Install" {
linux (tftp)/$pxe_server/images/ubuntu/vmlinuz \
ip=dhcp \
url=http://$pxe_server/ubuntu-24.04-live-server-amd64.iso \
autoinstall ds=nocloud-net\;s=http://$pxe_server/autoinstall/
initrd (tftp)/$pxe_server/images/ubuntu/initrd
}
menuentry "RHEL 10 Kickstart Install" {
linuxefi (tftp)/images/rhel/vmlinuz \
inst.repo=http://$pxe_server/rhel10/ \
inst.ks=http://$pxe_server/ks/rhel10.cfg \
ip=dhcp
initrdefi (tftp)/images/rhel/initrd.img
}
menuentry "Diskless Linux (NFS Root)" {
linux (tftp)/vmlinuz-diskless \
root=/dev/nfs \
nfsroot=$nfs_server:/exports/diskless,vers=4,tcp \
ip=dhcp rw
initrd (tftp)/initrd-diskless.img
}
menuentry "iPXE Chainload" {
chainloader (tftp)/ipxe.efi
}
GRUB EFI 네트워크 이미지 빌드
# GRUB UEFI 네트워크 부트 이미지 생성
# 필요한 모듈을 포함한 standalone EFI 이미지
# x86_64 UEFI
grub-mknetdir --net-directory=/var/lib/tftpboot --subdir=/grub
# 또는 수동으로 standalone 이미지 생성
grub-mkimage -O x86_64-efi \
-o grubx64.efi \
-p '(tftp)/grub' \
-d /usr/lib/grub/x86_64-efi \
efinet tftp http net normal linux linuxefi \
all_video boot configfile echo part_gpt part_msdos \
search search_fs_uuid search_label reboot halt
# ARM64 UEFI
grub-mkimage -O arm64-efi \
-o grubaa64.efi \
-p '(tftp)/grub' \
-d /usr/lib/grub/arm64-efi \
efinet tftp http net normal linux \
all_video boot configfile echo
# Secure Boot을 사용할 경우 shim 체인로딩
# shimx64.efi → grubx64.efi 순서로 로드
cp /usr/lib/shim/shimx64.efi.signed /var/lib/tftpboot/shimx64.efi
cp /usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed /var/lib/tftpboot/grubx64.efi
iPXE 고급 부팅
iPXE 개요
iPXE는 gPXE의 후속 프로젝트로, 레거시 PXE의 한계를 극복한 오픈소스 네트워크 부트 펌웨어입니다.
| 기능 | 레거시 PXE | iPXE |
|---|---|---|
| 프로토콜 | TFTP만 | HTTP, HTTPS, iSCSI, AoE, FCoE, TFTP, FTP, NFS |
| DNS | 미지원 | 지원 |
| 스크립팅 | 없음 | 내장 스크립트 언어 |
| Wi-Fi | 미지원 | WPA2 지원 (실험적) |
| VLAN | 일부 NIC만 | 완전 지원 |
| SAN Boot | 미지원 | iSCSI, AoE, FCoE, Infiniband SRP |
| 암호화 | 없음 | HTTPS/TLS 지원 (공식 문서 기준 TLSv1.0-1.2) |
| 인증 | 없음 | HTTP Basic/Digest, 클라이언트 인증서 |
| Embedded Script | 없음 | ROM에 스크립트 내장 가능 |
| 무선 네트워크 | 미지원 | 802.11 지원 (일부 칩셋) |
iPXE 체인로딩 전략
체인로딩 바이너리 선택
| 펌웨어 | 권장 이미지 | 의미 | 언제 바꾸는가 |
|---|---|---|---|
| Legacy BIOS | undionly.kpxe | 펌웨어가 제공한 UNDI 드라이버를 재사용 | 기본 PXE ROM 호환성을 최대화하고 싶을 때 |
| Legacy BIOS | ipxe.pxe | iPXE가 자체 NIC 드라이버 사용 | 펌웨어 UNDI 구현이 불안정하거나 기능이 부족할 때 |
| UEFI | ipxe.efi | 일반적인 UEFI 체인로딩용 EFI 애플리케이션 | 가장 보편적인 UEFI iPXE 진입점 |
| UEFI | snponly.efi | UEFI SNP 드라이버를 재사용 | 펌웨어 NIC 드라이버는 안정적이지만 iPXE 내장 드라이버 충돌을 피하고 싶을 때 |
undionly.kpxe, UEFI 환경에서 ipxe.efi를 기본 체인로딩 대상으로 제시합니다. UEFI에서 특정 NIC 드라이버 문제가 있으면 snponly.efi가 더 잘 맞는 경우가 있습니다.
iPXE 스크립트 예제
#!ipxe
# boot.ipxe - iPXE 메인 부팅 스크립트
# 변수 설정
set boot-server http://192.168.1.10
set menu-timeout 30000
set submenu-timeout ${menu-timeout}
# 네트워크 초기화
dhcp || goto netboot_failed
echo IP: ${ip} / Gateway: ${gateway} / DNS: ${dns}
# 아키텍처 감지
iseq ${platform} efi && goto efi_boot ||
goto bios_boot
:efi_boot
set boot-prefix ${boot-server}/efi
goto start
:bios_boot
set boot-prefix ${boot-server}/bios
goto start
:start
menu iPXE Boot Menu - ${ip}
item --gap -- -- OS Installation --
item ubuntu Ubuntu 24.04 LTS
item rhel RHEL 10 계열
item debian Debian 13 Trixie
item --gap -- -- Utilities --
item diskless Diskless Linux (NFS)
item iscsi iSCSI SAN Boot
item memtest Memtest86+
item --gap -- -- Other --
item shell iPXE Shell
item reboot Reboot
item exit Exit to BIOS/UEFI
choose --default ubuntu --timeout ${menu-timeout} selected
goto ${selected}
:ubuntu
kernel ${boot-server}/images/ubuntu/vmlinuz
initrd ${boot-server}/images/ubuntu/initrd
imgargs vmlinuz ip=dhcp url=${boot-server}/iso/ubuntu-24.04.iso autoinstall ds=nocloud-net;s=${boot-server}/autoinstall/
boot || goto failed
:rhel
kernel ${boot-server}/images/rhel/vmlinuz
initrd ${boot-server}/images/rhel/initrd.img
imgargs vmlinuz inst.repo=${boot-server}/rhel10/ inst.ks=${boot-server}/ks/rhel10.cfg ip=dhcp
boot || goto failed
:debian
kernel ${boot-server}/images/debian/linux
initrd ${boot-server}/images/debian/initrd.gz
imgargs linux auto=true priority=critical url=${boot-server}/preseed/debian13.cfg interface=auto
boot || goto failed
:diskless
kernel ${boot-server}/vmlinuz-diskless
initrd ${boot-server}/initrd-diskless.img
imgargs vmlinuz-diskless root=/dev/nfs nfsroot=192.168.1.10:/exports/diskless,vers=4 ip=dhcp rw
boot || goto failed
:iscsi
# iSCSI SAN 부팅
set iscsi-server 192.168.1.20
set iscsi-target iqn.2024-01.com.example:storage.lun0
sanhook iscsi:${iscsi-server}::::${iscsi-target} || goto failed
# iSCSI LUN에서 부팅
sanboot iscsi:${iscsi-server}::::${iscsi-target} || goto failed
:memtest
chain ${boot-server}/memtest86+.bin || goto failed
:shell
echo iPXE Shell. Type 'exit' to return to menu.
shell
goto start
:reboot
reboot
:exit
exit
:failed
echo Boot failed. Retrying in 5 seconds...
sleep 5
goto start
:netboot_failed
echo Network initialization failed!
echo Falling back to local boot...
sleep 3
exit 1
iPXE 고급 스크립팅
#!ipxe
# advanced-boot.ipxe - 고급 기능 데모
# === 환경 변수 활용 ===
echo Platform: ${platform} # pcbios 또는 efi
echo BuildArch: ${buildarch} # i386 또는 x86_64 또는 arm64
echo MAC: ${mac} # xx:xx:xx:xx:xx:xx
echo Serial: ${serial} # 시리얼 번호
echo UUID: ${uuid} # SMBIOS UUID
echo Manufacturer: ${manufacturer}
echo Product: ${product}
echo Chip: ${chip} # NIC 칩셋
# === 조건 분기 ===
# MAC 주소 기반 분기
iseq ${mac} 00:11:22:33:44:55 && goto special_host ||
# 서브넷 기반 분기
isset ${netX/gateway} && goto has_gateway || goto no_gateway
# 제조사 기반 분기
iseq ${manufacturer} "Dell Inc." && set vendor dell ||
iseq ${manufacturer} "HP" && set vendor hp ||
iseq ${manufacturer} "Lenovo" && set vendor lenovo ||
set vendor generic
# === HTTPS + 인증 ===
set cert-server https://pxe.example.com
# 클라이언트 인증서 (빌드 시 내장)
# imgfetch ${cert-server}/cert/${uuid}.pem
# === 동적 메뉴 (서버에서 생성) ===
# 서버가 MAC/UUID/arch에 따라 동적 스크립트 생성
chain ${cert-server}/api/boot?mac=${mac:hexhyp}&arch=${buildarch}&uuid=${uuid}&platform=${platform} ||
echo Dynamic menu failed, falling back...
# === VLAN 태깅 ===
# vcreate --tag 100 net0
# dhcp net0-100
# === 루프와 재시도 ===
set retry-count 0
:retry_loop
inc retry-count
iseq ${retry-count} 5 && goto give_up ||
echo Attempt ${retry-count} of 5...
dhcp && goto dhcp_ok ||
sleep 2
goto retry_loop
:dhcp_ok
echo DHCP succeeded on attempt ${retry-count}
:give_up
echo All retry attempts exhausted.
iPXE 빌드와 커스터마이징
# iPXE 소스 빌드
# 의존성 설치
sudo apt install build-essential liblzma-dev isolinux \
mtools mkisofs syslinux perl
# 소스 클론
git clone https://github.com/ipxe/ipxe.git
cd ipxe/src
# === 기본 빌드 ===
# BIOS용 PXE chainload 이미지 (UNDI 재사용)
make bin/undionly.kpxe
# BIOS용 standalone 이미지 (내장 드라이버 사용)
make bin/ipxe.pxe
# UEFI용 이미지
make bin-x86_64-efi/ipxe.efi
# ARM64 UEFI용
make bin-arm64-efi/ipxe.efi
# === 내장 스크립트와 함께 빌드 ===
cat > embed.ipxe << 'SCRIPT'
#!ipxe
dhcp
chain http://192.168.1.10/boot.ipxe
SCRIPT
make bin/undionly.kpxe EMBED=embed.ipxe
# === 빌드 옵션 커스터마이징 ===
# config/general.h 에서 기능 활성화/비활성화
# DOWNLOAD_PROTO_HTTPS - HTTPS 지원
# DOWNLOAD_PROTO_NFS - NFS 지원
# IMAGE_SCRIPT - 스크립트 지원
# NET_PROTO_IPV6 - IPv6 지원
# CONSOLE_CMD - 콘솔 명령
# VLAN_CMD - VLAN 명령
# NSLOOKUP_CMD - DNS 조회 명령
# PING_CMD - 핑 명령
# HTTPS 활성화 빌드
cat > custom_config.h << 'EOF'
#define DOWNLOAD_PROTO_HTTPS
#define IMAGE_TRUST_CMD
#define CERT_CMD
#define CONSOLE_CMD
#define NSLOOKUP_CMD
#define PING_CMD
#define VLAN_CMD
EOF
make bin/undionly.kpxe EMBED=embed.ipxe CONFIG=custom_config
# === USB/ISO 이미지 생성 ===
make bin/ipxe.usb # USB 부팅 이미지
make bin/ipxe.iso # CD/DVD ISO 이미지
make bin/ipxe.lkrn # Linux 커널 형식 (GRUB/PXELINUX에서 로드 가능)
Etherboot → gPXE → iPXE 계보
iPXE의 역사를 이해하면 다양한 레거시 환경에서 만나는 네트워크 부팅 소프트웨어의 관계를 파악할 수 있습니다.
| 프로젝트 | 시기 | 주요 특징 | 상태 |
|---|---|---|---|
| Etherboot | 1995-2006 | 최초의 오픈소스 네트워크 부팅. NIC별 드라이버 바이너리. Tagged image format | 종료 (gPXE로 전환) |
| gPXE | 2006-2010 | Etherboot 후속. HTTP, iSCSI, DNS 지원 추가. UNDI 호환 모드. GPL v2 | 종료 (iPXE로 포크) |
| iPXE | 2010-현재 | gPXE 포크. HTTPS, Wi-Fi, 스크립팅, 확장된 SAN boot, UEFI 지원. 공식 암호화 문서 기준 TLSv1.0-1.2 지원. GPL v2 | 활발한 개발 중 |
Netboot.xyz — iPXE 기반 인터넷 부팅
# Netboot.xyz 설정 (가장 간단한 PXE 구성법)
# 1. Netboot.xyz 이미지 다운로드
wget https://boot.netboot.xyz/ipxe/netboot.xyz.kpxe # BIOS용
wget https://boot.netboot.xyz/ipxe/netboot.xyz.efi # UEFI용
# TFTP에 배치
cp netboot.xyz.kpxe /var/lib/tftpboot/
cp netboot.xyz.efi /var/lib/tftpboot/
# 2. dnsmasq 설정
dhcp-match=set:bios,option:client-arch,0
dhcp-match=set:efi64,option:client-arch,7
dhcp-boot=tag:bios,netboot.xyz.kpxe
dhcp-boot=tag:efi64,netboot.xyz.efi
# 이것만으로 Ubuntu, Debian, CentOS, Fedora, Arch, FreeBSD,
# Windows PE, Memtest86+, SystemRescue, DBAN 등
# 수십 가지 OS를 네트워크에서 직접 설치 가능!
# 3. 자체 호스팅 Netboot.xyz (Docker)
docker run -d --name netbootxyz \
-p 3000:3000 \ # 웹 관리 인터페이스
-p 69:69/udp \ # TFTP
-p 8080:80 \ # HTTP 부팅 파일
-v /data/netboot:/config \
ghcr.io/netbootxyz/netbootxyz
UEFI PXE & HTTP Boot
UEFI PXE vs Legacy PXE
| 항목 | Legacy BIOS PXE | UEFI PXE | UEFI HTTP Boot |
|---|---|---|---|
| 실행 환경 | 16-bit Real Mode | Native (32/64-bit) | Native (32/64-bit) |
| 드라이버 | UNDI (Option ROM) | EFI SNP/MNP 드라이버 | EFI HTTP 프로토콜 |
| 부트 파일 | .0 (COM 바이너리) | .efi (PE32+ 바이너리) | .efi (PE32+ 바이너리) |
| 전송 프로토콜 | TFTP | TFTP | HTTP/HTTPS |
| 파일 크기 제한 | ~32MB (blksize 미확장) | 없음 | 없음 |
| Secure Boot | 불가 | 지원 | 지원 (HTTPS 시 TLS) |
| IPv6 | 미지원 | 지원 | 지원 |
| 속도 | 느림 (TFTP) | 느림 (TFTP) | 빠름 (HTTP/TCP) |
UEFI HTTP Boot 설정
# UEFI HTTP Boot를 위한 DHCP 설정 (ISC DHCPd)
# DHCP Option 60에 "HTTPClient"가 포함된 요청 처리
class "httpclients" {
match if substring (option vendor-class-identifier, 0, 10) = "HTTPClient";
# HTTP Boot URI를 BOOTP file 필드로 전달
if option client-arch = 00:10 {
# x64 UEFI HTTP Boot
filename "http://192.168.1.10/boot/shimx64.efi";
} elsif option client-arch = 00:13 {
# ARM64 UEFI HTTP Boot
filename "http://192.168.1.10/boot/shimaa64.efi";
}
}
# dnsmasq 설정
# HTTP Boot 클라이언트에 HTTP URL 제공
dhcp-match=set:HTTPClient,option:vendor-class,HTTPClient
dhcp-boot=tag:HTTPClient,"http://192.168.1.10/boot/shimx64.efi"
# === nginx HTTP Boot 서버 ===
# /etc/nginx/sites-available/pxe
server {
listen 80;
server_name pxe.example.com;
root /var/www/pxeboot;
autoindex on;
# EFI 바이너리 MIME 타입
types {
application/efi efi;
}
location /boot/ {
alias /var/lib/tftpboot/;
}
location /images/ {
alias /var/www/pxeboot/images/;
}
location /iso/ {
alias /var/www/pxeboot/iso/;
}
# iPXE 동적 스크립트 (PHP/Python 백엔드)
location /api/boot {
proxy_pass http://127.0.0.1:8080;
}
}
# === HTTPS HTTP Boot (TLS) ===
server {
listen 443 ssl;
server_name pxe.example.com;
ssl_certificate /etc/ssl/certs/pxe.crt;
ssl_certificate_key /etc/ssl/private/pxe.key;
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www/pxeboot;
# ... (동일한 location 설정)
}
HTTP Boot의 DHCP 규칙
UEFI 2.11 기준으로 HTTP Boot 클라이언트는 PXEClient가 아니라 HTTPClient라는 Vendor Class를 사용합니다. DHCPv4에서는 Boot URI를 file 필드나 Option 67로 받을 수 있고, DHCPv6에서는 RFC 5970의 OPTION_BOOTFILE_URL(59)을 사용합니다.
| 항목 | DHCPv4 | DHCPv6 |
|---|---|---|
| 클라이언트 식별 | Option 60 = HTTPClient:Arch:.... | Option 16 Vendor Class = HTTPClient:Arch:.... |
| 부트 대상 전달 | file 필드 또는 Option 67에 URI 저장 | Option 59 BOOTFILE_URL |
| 아키텍처 전달 | Option 93 | Option 61 CLIENT_ARCH_TYPE |
| NIC 인터페이스 정보 | Option 94 | Option 62 NII |
| 추가 파라미터 | 벤더 옵션 또는 NBP 내부 처리 | Option 60 BOOTFILE_PARAM |
UEFI PXE Vendor Class 식별
| DHCP Option 60 (Vendor Class) | 의미 | 부트 파일 형식 |
|---|---|---|
PXEClient:Arch:00000:UNDI:... | BIOS PXE | 16-bit .0/.com |
PXEClient:Arch:00006:UNDI:... | UEFI x86 PXE | PE32 .efi |
PXEClient:Arch:00007:UNDI:... | UEFI x64 PXE | PE32+ .efi |
PXEClient:Arch:00011:UNDI:... | UEFI ARM64 PXE | PE32+ .efi |
HTTPClient:Arch:00015:UNDI:... | UEFI x86 HTTP Boot | PE32 .efi (HTTP/HTTPS URI) |
HTTPClient:Arch:00016:UNDI:... | UEFI x64 HTTP Boot | PE32+ .efi (HTTP URL) |
HTTPClient:Arch:00017:UNDI:... | UEFI EBC HTTP Boot | EBC EFI 애플리케이션 |
HTTPClient:Arch:00019:UNDI:... | UEFI ARM64 HTTP Boot | PE32+ .efi (HTTP URL) |
리눅스 커널 네트워크 부팅 파라미터
ip= 파라미터
커널이 부팅 시 네트워크를 설정하는 핵심 파라미터입니다. initramfs 안의 네트워크 설정과는 별개로, 커널 자체에 내장된 네트워크 초기화 코드(net/ipv4/ipconfig.c)가 처리합니다.
ip= 파라미터 형식:
ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>:<ntp0-ip>
예시:
ip=dhcp # 모든 NIC에서 DHCP
ip=192.168.1.100::192.168.1.1:255.255.255.0:myhost:eth0:off
ip=::::myhost:eth0:dhcp # eth0에서 DHCP, 호스트명 지정
ip=192.168.1.100::192.168.1.1:255.255.255.0::eth0:off:8.8.8.8:8.8.4.4
autoconf 값:
dhcp - DHCP만 사용
bootp - BOOTP만 사용
rarp - RARP만 사용
both - BOOTP와 RARP 모두 시도
on - DHCP, BOOTP, RARP 모두 시도
off - 정적 설정 (나머지 필드에서 IP 가져옴)
any - 사용 가능한 모든 프로토콜 시도
nfsroot= 파라미터
nfsroot= 파라미터 형식:
nfsroot=[server-ip:]root-dir[,nfs-options]
예시:
nfsroot=192.168.1.10:/exports/diskless,vers=4,tcp
nfsroot=/exports/diskless,nfsvers=3,rsize=8192,wsize=8192
nfsroot=192.168.1.10:/exports/diskless,nolock,tcp
주요 NFS 마운트 옵션:
vers=4 / nfsvers=3 - NFS 버전 지정
tcp / udp - 전송 프로토콜
rsize=N / wsize=N - 읽기/쓰기 버퍼 크기
nolock - NLM 락 비활성화 (diskless에서 권장)
ro / rw - 읽기 전용/읽기 쓰기
네트워크 부팅 관련 전체 커널 파라미터
| 파라미터 | 설명 | 예시 |
|---|---|---|
ip= | 커널 수준 네트워크 설정 | ip=dhcp |
nfsroot= | NFS 루트 파일시스템 | nfsroot=10.0.0.1:/nfs/root |
root= | 루트 장치/프로토콜 | root=/dev/nfs, root=iscsi:... |
netboot=nfs | NFS 네트워크 부팅 명시 | netboot=nfs |
BOOTIF= | PXE가 설정한 부팅 인터페이스 MAC | BOOTIF=01-00-11-22-33-44-55 |
rd.neednet=1 | dracut: initrd에서 네트워크 활성화 | rd.neednet=1 |
rd.iscsi.initiator= | dracut: iSCSI initiator 이름 | rd.iscsi.initiator=iqn.2024... |
rd.iscsi.target.name= | dracut: iSCSI target 이름 | rd.iscsi.target.name=iqn.2024... |
rd.iscsi.target.ip= | dracut: iSCSI target IP | rd.iscsi.target.ip=10.0.0.1 |
iscsi_target_name= | initramfs-tools: iSCSI target | iscsi_target_name=iqn.2024... |
rd.live.image | dracut: Live 이미지 부팅 | rd.live.image |
fetch= | casper: HTTP/NFS에서 squashfs 가져오기 | fetch=http://server/fs.squashfs |
커널 소스: net/ipv4/ipconfig.c
/* net/ipv4/ipconfig.c - 커널 네트워크 자동 설정 핵심 코드 */
/* ip= 파라미터 파싱 */
static int __init ic_proto_name(char *name)
{
if (!strcmp(name, "on") || !strcmp(name, "any"))
return IC_BOOTP | IC_RARP;
if (!strcmp(name, "off") || !strcmp(name, "none"))
return 0;
if (!strcmp(name, "dhcp"))
return IC_BOOTP | IC_USE_DHCP;
if (!strcmp(name, "bootp"))
return IC_BOOTP;
if (!strcmp(name, "rarp"))
return IC_RARP;
if (!strcmp(name, "both"))
return IC_BOOTP | IC_RARP;
return IC_BOOTP | IC_RARP;
}
/* DHCP/BOOTP 패킷 수신 처리 */
static void __init ic_bootp_recv(struct sk_buff *skb,
struct net_device *dev)
{
struct bootp_pkt *b = (struct bootp_pkt *)skb->data;
/* 트랜잭션 ID 확인 */
if (b->xid != ic_dev_xid)
goto drop;
/* IP 주소 할당 */
ic_myaddr = b->your_ip; /* yiaddr → 클라이언트 IP */
ic_servaddr = b->server_ip; /* siaddr → TFTP 서버 */
ic_gateway = b->relay_ip; /* giaddr → 게이트웨이 */
/* DHCP 옵션 파싱 */
ic_do_bootp_ext(b->exten, skb->len - sizeof(*b));
/* ... rootpath, hostname, DNS 등 추출 ... */
}
/* NFS 루트 마운트 (fs/nfs/nfsroot.c) */
static int __init nfs_root_setup(char *line)
{
/* nfsroot=server:/path,options 파싱 */
ROOT_DEV = Root_NFS; /* root=/dev/nfs 효과 */
/* ... */
}
NFS Root 디스크리스 부팅
디스크리스 부팅 개요
디스크리스(diskless) 부팅은 로컬 디스크 없이 네트워크 파일시스템을 루트로 사용하는 부팅 방식입니다. 씬 클라이언트, 클러스터 노드, 임베디드 시스템에서 널리 사용됩니다.
NFS 서버 설정
# NFS 서버 설정 (Ubuntu/Debian)
sudo apt install nfs-kernel-server
# 디스크리스 루트 파일시스템 준비
sudo mkdir -p /exports/diskless
# debootstrap으로 최소 rootfs 생성 (Debian stable: trixie)
sudo debootstrap --arch=amd64 trixie /exports/diskless \
http://deb.debian.org/debian
# 또는 기존 시스템 복사
# sudo rsync -axHAX --exclude='/proc/*' --exclude='/sys/*' \
# --exclude='/dev/*' --exclude='/tmp/*' / /exports/diskless/
# NFS 내보내기 설정
# /etc/exports
/exports/diskless 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
/exports/base 192.168.1.0/24(ro,sync,no_subtree_check)
/exports/overlay 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
# NFS 서비스 재시작
sudo exportfs -arv
sudo systemctl restart nfs-kernel-server
# 방화벽 (NFS v4: TCP 2049만 필요)
sudo firewall-cmd --add-service=nfs --permanent
sudo firewall-cmd --reload
디스크리스 클라이언트 rootfs 설정
# /exports/diskless/etc/fstab - 디스크리스 클라이언트용
# NFS root는 커널이 자동 마운트하므로 여기서는 추가 마운트만
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
tmpfs /run tmpfs defaults 0 0
tmpfs /var/log tmpfs defaults 0 0
# /exports/diskless/etc/network/interfaces
auto lo
iface lo inet loopback
# DHCP (커널 ip=dhcp로 이미 설정되지만, 사용자 공간에서도 필요)
auto eth0
iface eth0 inet dhcp
# 커널 및 initramfs 생성 (NFS root 지원 포함)
# chroot /exports/diskless
# apt install linux-image-amd64 initramfs-tools
# /exports/diskless/etc/initramfs-tools/initramfs.conf
MODULES=netboot
BOOT=nfs
# initramfs 재생성
# update-initramfs -u
# TFTP에 커널/initrd 복사
sudo cp /exports/diskless/boot/vmlinuz-* /var/lib/tftpboot/vmlinuz-diskless
sudo cp /exports/diskless/boot/initrd.img-* /var/lib/tftpboot/initrd-diskless.img
OverlayFS 디스크리스 구성
# initramfs 안에서 OverlayFS 설정하는 스크립트
# /exports/diskless/etc/initramfs-tools/scripts/init-bottom/overlay
#!/bin/sh
# NFS를 lower로, tmpfs를 upper로 사용하는 OverlayFS
# 재부팅 시 모든 변경 사항 초기화됨
PREREQ=""
prereqs() { echo "$PREREQ"; }
case $1 in prereqs) prereqs; exit 0;; esac
. /scripts/functions
# tmpfs 생성 (writable layer)
mkdir -p /overlay
mount -t tmpfs tmpfs /overlay -o size=2G
mkdir -p /overlay/upper /overlay/work
# OverlayFS 마운트
# ${rootmnt}는 NFS로 마운트된 read-only rootfs
mkdir -p /overlay/merged
mount -t overlay overlay /overlay/merged \
-o lowerdir=${rootmnt},upperdir=/overlay/upper,workdir=/overlay/work
# rootfs 교체
mkdir -p /overlay/merged/nfs-root
mount --move ${rootmnt} /overlay/merged/nfs-root
mount --move /overlay/merged ${rootmnt}
exit 0
iSCSI SAN 부팅
iSCSI 부팅 개요
iSCSI(Internet Small Computer Systems Interface)는 SCSI 명령을 TCP/IP로 전달하는 프로토콜입니다. PXE/iPXE로 초기 부팅 후 iSCSI LUN을 루트 디바이스로 사용하면, 로컬 디스크와 거의 동일한 블록 레벨 I/O 성능을 얻을 수 있습니다.
iSCSI Target 서버 설정
# targetcli를 사용한 iSCSI target 설정 (Linux LIO)
sudo apt install targetcli-fb
# LVM 또는 파일 기반 LUN 생성
sudo lvcreate -L 50G -n client-A vg0
# 또는: dd if=/dev/zero of=/var/lib/iscsi/client-A.img bs=1M count=51200
sudo targetcli
# targetcli 내부 명령:
/> backstores/block create client-A /dev/vg0/client-A
/> iscsi/ create iqn.2024-01.com.example:storage
/> iscsi/iqn.2024-01.com.example:storage/tpg1/luns/ create /backstores/block/client-A
/> iscsi/iqn.2024-01.com.example:storage/tpg1/acls/ create iqn.2024-01.com.example:client-A
# CHAP 인증 설정
/> iscsi/iqn.2024-01.com.example:storage/tpg1/acls/iqn.2024-01.com.example:client-A/ set auth userid=client-A
/> iscsi/iqn.2024-01.com.example:storage/tpg1/acls/iqn.2024-01.com.example:client-A/ set auth password=secret123
# 포털 설정 (기본 0.0.0.0:3260)
/> iscsi/iqn.2024-01.com.example:storage/tpg1/portals/ create 10.0.0.1
/> saveconfig
/> exit
iPXE iSCSI 부팅 스크립트
#!ipxe
# iscsi-boot.ipxe
dhcp
set iscsi-server 10.0.0.1
set iscsi-port 3260
set iscsi-target iqn.2024-01.com.example:storage
set iscsi-initiator iqn.2024-01.com.example:${mac:hexhyp}
# iSCSI 연결 및 SAN 부팅
set root-path iscsi:${iscsi-server}::${iscsi-port}:1:${iscsi-target}
sanhook ${root-path} || goto failed
sanboot ${root-path} || goto failed
:failed
echo iSCSI boot failed!
shell
대규모 프로비저닝 시스템
프로비저닝 도구 비교
| 도구 | 개발사 | 특징 | 규모 | 자동 설치 |
|---|---|---|---|---|
| Cobbler | 커뮤니티 | DHCP/DNS/TFTP 통합 관리, 프로파일 시스템 | 중-대 | Kickstart, Preseed |
| MAAS | Canonical | "Metal as a Service", 베어메탈 클라우드 | 대 | cloud-init, Curtin |
| Foreman | Theforeman | 라이프사이클 관리, Puppet/Ansible 통합 | 대 | Kickstart, Preseed |
| FOG Project | 커뮤니티 | 이미지 기반 배포, 디스크 클로닝 | 소-중 | 이미지 복원 |
| Tinkerbell | Equinix | 클라우드 네이티브, 워크플로 기반 | 대 | Workflow Actions |
| Ironic | OpenStack | OpenStack 베어메탈 프로비저닝 | 대 | IPA (Ironic Python Agent) |
| Razor | Puppet | 정책 기반 프로비저닝 | 중 | Kickstart, Preseed |
| Matchbox | CoreOS/Red Hat | CoreOS/Flatcar 전용, iPXE 통합 | 중-대 | Ignition |
| Netboot.xyz | 커뮤니티 | 인터넷 기반 멀티 OS 부팅 메뉴 | 소 | 다양 |
Kickstart 자동 설치 예제 (RHEL 10 계열)
# /var/www/pxeboot/ks/rhel10.cfg - Kickstart 파일
# RHEL 10 계열 무인 설치
# 설치 소스
url --url="http://192.168.1.10/rhel10/"
repo --name="AppStream" --baseurl="http://192.168.1.10/rhel10/AppStream/"
# 시스템 설정
text
lang en_US.UTF-8
keyboard us
timezone Asia/Seoul --utc
rootpw --iscrypted $6$rounds=656000$salt$hash...
selinux --enforcing
firewall --enabled --ssh
services --enabled=sshd
# 네트워크
network --bootproto=dhcp --device=link --activate --hostname=server01.example.com
# 디스크 파티셔닝
zerombr
clearpart --all --initlabel
autopart --type=lvm --fstype=xfs
# BIOS/UEFI 공용 예시: 위치를 MBR로 고정하지 않음
bootloader --append="crashkernel=auto"
# 패키지
%packages
@^minimal-environment
vim-enhanced
tmux
open-iscsi
nfs-utils
%end
# 설치 후 스크립트
%post --log=/root/ks-post.log
# SSH 키 배포
mkdir -p /root/.ssh
curl -o /root/.ssh/authorized_keys http://192.168.1.10/keys/admin.pub
chmod 600 /root/.ssh/authorized_keys
# 설치 상태 등록
primary_ip=$(hostname -I | awk '{print $1}')
curl -X POST http://192.168.1.10/api/register \
-d "hostname=$(hostname)&ip=${primary_ip}"
%end
# 설치 완료 후 재부팅
reboot
inst.ks=를 같은 방식으로 커널 인자에 추가하는 구성을 제시합니다. 혼합 BIOS/UEFI 환경 문서라면 BIOS 전용 표현인 --location=mbr를 기본 예제로 두기보다, 범용적인 bootloader --append=... 형태를 먼저 보여 주는 편이 안전합니다. Kickstart 파일은 배포 전에 ksvalidator -v RHEL10로 문법을 먼저 점검하는 편이 좋습니다.
cloud-init / Autoinstall 예제 (Ubuntu)
# /var/www/pxeboot/autoinstall/user-data
# Ubuntu 24.04 LTS Autoinstall 설정
#cloud-config
autoinstall:
version: 1
locale: en_US.UTF-8
keyboard:
layout: us
network:
version: 2
ethernets:
id0:
match:
driver: e1000*
dhcp4: true
storage:
layout:
name: lvm
identity:
hostname: ubuntu-server
username: admin
password: "$6$rounds=656000$..."
ssh:
install-server: true
authorized-keys:
- ssh-ed25519 AAAA... admin@example.com
packages:
- vim
- tmux
- nfs-common
- open-iscsi
late-commands:
# 첫 부팅 시 로컬 디스크에서 부팅하도록 설정
- curtin in-target --target=/target -- efibootmgr -o 0001
# 설치 후 알림
- "curl -X POST http://192.168.1.10/api/installed?host=$(hostname)"
autoinstall ds=nocloud-net;s=http://...를 넣고, HTTP 루트에 user-data와 meta-data를 함께 제공하는 패턴이 가장 일반적입니다. Ubuntu 24.04부터는 cloud-config를 사용할 때 최상위 autoinstall: 구조와 스키마 검증이 더 엄격해졌으므로, 예전의 느슨한 YAML을 그대로 재사용하면 설치 초반에 중단될 수 있습니다.
배포판별 자동설치 실무 메모
| 배포판 | 현재 문서 기준 | 권장 전달 방식 | 실무에서 자주 틀리는 지점 |
|---|---|---|---|
| RHEL 10 계열 | Kickstart + Anaconda | inst.repo= + inst.ks=, PXE 또는 UEFI HTTP Boot | BIOS 전용 --location=mbr 고정, 배포 전 ksvalidator 미실행 |
| Ubuntu 24.04 LTS | Subiquity + cloud-init Autoinstall | autoinstall ds=nocloud-net;s=... + HTTP user-data/meta-data | #cloud-config 헤더 누락, 최상위 autoinstall: 키 누락, 오래된 스키마 재사용 |
| Debian 13 stable (trixie) | Debian Installer + Preseed | auto=true priority=critical url=... | UEFI 환경에서 GPT/EFI 관련 partman 옵션 누락, interface=auto 미지정 |
Secure PXE Boot
PXE 보안 위협과 대응
| 위협 | 설명 | 대응 |
|---|---|---|
| Rogue DHCP | 악성 DHCP 서버가 잘못된 부팅 서버로 유도 | DHCP Snooping, 802.1X, VLAN 분리 |
| TFTP 탈취 | NBP/커널 파일을 악성으로 교체 | HTTPS 전송 (iPXE/UEFI HTTP Boot) |
| MITM 공격 | 네트워크 중간에서 부팅 트래픽 변조 | TLS/HTTPS, IPSec, 802.1X |
| 악성 NBP | 서명되지 않은 부트로더 실행 | UEFI Secure Boot + Shim |
| 부팅 이미지 변조 | 커널/initrd 무결성 훼손 | IMA/EVM, dm-verity, 서명 검증 |
| 인증 없는 접근 | 아무 기기나 PXE 부팅 가능 | MAC 필터링, 802.1X NAC, CHAP |
Secure PXE Boot Chain
Secure PXE Boot 구성 절차
# 1. MOK (Machine Owner Key) 생성
openssl req -new -x509 -newkey rsa:2048 -keyout MOK.key -out MOK.crt \
-days 3650 -nodes -subj "/CN=PXE Boot Signing Key"
# 2. GRUB EFI 서명
sbsign --key MOK.key --cert MOK.crt --output grubx64.efi.signed grubx64.efi
# 3. 커널 서명
sbsign --key MOK.key --cert MOK.crt --output vmlinuz.signed vmlinuz
# 4. Shim에 MOK 등록 (각 클라이언트에서 1회)
# shimx64.efi가 처음 부팅 시 MokManager로 진입
# → MOK.cer(DER 형식) 등록
openssl x509 -in MOK.crt -outform der -out MOK.cer
# 5. TFTP에 배치
cp shimx64.efi.signed /var/lib/tftpboot/shimx64.efi
cp grubx64.efi.signed /var/lib/tftpboot/grubx64.efi
cp vmlinuz.signed /var/lib/tftpboot/vmlinuz
# 6. iPXE HTTPS 빌드 (CA 인증서 내장)
cd ipxe/src
make bin-x86_64-efi/ipxe.efi EMBED=boot.ipxe \
TRUST=/etc/ssl/certs/ca-certificates.crt \
CERT=client.crt PRIVKEY=client.key
# 7. 네트워크 보안
# 802.1X RADIUS 인증 (PXE 전 네트워크 접근 제어)
# DHCP Snooping: 신뢰할 수 있는 포트만 DHCP 응답 허용
# Dynamic ARP Inspection: ARP 스푸핑 방지
IPv6 PXE 부팅
IPv6 PXE 개요
IPv6에서는 BOOTP의 siaddr/file 모델보다 URL 기반 전달이 더 중요해집니다. UEFI는 IPv6 환경에서 netboot6(PXE over DHCPv6 + MTFTP)와 HTTP Boot를 모두 정의하며, DHCPv6 옵션 집합(RFC 5970)을 통해 부트 URI와 아키텍처 정보를 전달합니다.
| 항목 | IPv4 PXE | IPv6 PXE |
|---|---|---|
| 주소 할당 | DHCPv4 | DHCPv6, RA, 필요 시 SLAAC 병행 |
| 부트 위치 전달 | siaddr, file, Option 66/67 | Option 59 BOOTFILE_URL |
| 아키텍처 정보 | Option 93 | Option 61 CLIENT_ARCH_TYPE |
| NIC 인터페이스 식별 | Option 94 | Option 62 NII |
| 부트파일 예시 | filename "pxelinux.0" | tftp://[2001:db8::1]/grubx64.efi 또는 https://boot.example.com/shimx64.efi |
| 다음 서버 지정 | next-server 또는 siaddr | URI 안에 서버와 경로를 모두 포함 |
| 멀티캐스트 | 제한적 | 네이티브 지원 |
| BIOS 지원 | 지원 | 미지원 (UEFI만) |
DHCPv6 부트 옵션 세트
| RFC 5970 옵션 | 이름 | 역할 | 예시 |
|---|---|---|---|
| 59 | BOOTFILE_URL | 부트 이미지의 전체 URI 전달 | http://[2001:db8::10]/boot/shimx64.efi |
| 60 | BOOTFILE_PARAM | 부트 이미지에 전달할 부가 파라미터 | root=/dev/nfs, ip=dhcp |
| 61 | CLIENT_ARCH_TYPE | 클라이언트 아키텍처 전달 | x64 UEFI, ARM64 UEFI, HTTP Boot 등 |
| 62 | NII | Network Interface Identifier | UNDI/SNP 인터페이스 버전, 타입 |
# ISC DHCPv6 PXE 설정
# /etc/dhcp/dhcpd6.conf
subnet6 2001:db8::/64 {
range6 2001:db8::100 2001:db8::200;
# PXE 부트파일 URL (DHCPv6 Option 59)
option dhcp6.bootfile-url "tftp://[2001:db8::1]/grubx64.efi";
# HTTP Boot
# option dhcp6.bootfile-url "http://[2001:db8::1]/boot/shimx64.efi";
}
# dnsmasq IPv6 PXE
dhcp-range=::100,::200,constructor:eth0,ra-names,slaac,64,12h
dhcp-option=option6:bootfile-url,"tftp://[2001:db8::1]/grubx64.efi"
멀티캐스트 부팅과 성능 최적화
멀티캐스트 TFTP
동일한 이미지를 수백 대의 서버에 동시에 전송해야 할 때, 유니캐스트 TFTP는 심각한 병목이 됩니다. 멀티캐스트를 사용하면 네트워크 대역폭을 절약하면서 대규모 동시 배포가 가능합니다.
| 방식 | 도구 | 장점 | 단점 |
|---|---|---|---|
| 유니캐스트 TFTP | tftpd-hpa | 간단, 호환성 최고 | 노드 수 × 대역폭 |
| 멀티캐스트 TFTP | atftpd (mtftp) | 1:N 동시 전송 | PXE ROM 지원 필요 |
| UDPcast | udp-sender/receiver | 대규모 이미지 배포 | 커스텀 리시버 필요 |
| HTTP | nginx/Apache | TCP 신뢰성, 빠른 속도 | iPXE 또는 UEFI HTTP Boot 필요 |
| BitTorrent | Murder, opentracker | P2P, 대규모에 최적 | 초기 시드 필요, 복잡성 |
전송 프로토콜별 성능 비교
테스트 환경: 100MB vmlinuz + 50MB initrd, 1Gbps 네트워크
┌──────────────────────┬──────────────┬─────────────────┬──────────────────┐
│ 프로토콜 │ 단일 클라이언트│ 10대 동시 │ 100대 동시 │
├──────────────────────┼──────────────┼─────────────────┼──────────────────┤
│ TFTP (512B blk) │ ~120초 │ ~1200초 (직렬) │ 사실상 불가 │
│ TFTP (1468B blk) │ ~25초 │ ~250초 │ ~2500초 │
│ TFTP (1468B, win=64) │ ~8초 │ ~80초 │ ~800초 │
│ HTTP (nginx) │ ~2초 │ ~3초 │ ~15초 │
│ HTTPS (nginx) │ ~3초 │ ~5초 │ ~20초 │
│ 멀티캐스트 TFTP │ ~25초 │ ~30초 │ ~40초 │
│ UDPcast │ ~3초 │ ~5초 │ ~10초 │
└──────────────────────┴──────────────┴─────────────────┴──────────────────┘
* 실제 성능은 네트워크 환경, 서버 성능에 따라 크게 다를 수 있음
nginx PXE 서버 최적화
# /etc/nginx/conf.d/pxe-optimized.conf
server {
listen 80;
server_name pxe.example.com;
root /var/www/pxeboot;
# 동시 접속 최적화
keepalive_timeout 30;
keepalive_requests 100;
# sendfile + tcp_nopush로 커널 수준 최적화
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 대용량 파일 전송 최적화
directio 4m; # 4MB 이상 파일은 DirectIO
aio threads; # 비동기 I/O
output_buffers 2 1m; # 출력 버퍼
# 바이트 범위 요청 (iPXE가 사용)
max_ranges 1;
# 캐싱 헤더
location ~* \.(efi|img|vmlinuz|iso)$ {
expires 1h;
add_header Cache-Control "public, no-transform";
}
# 접속 제한 (DoS 방지)
limit_conn_zone $binary_remote_addr zone=pxe:10m;
limit_conn pxe 10;
}
UDPcast 멀티캐스트 배포
UDPcast는 대규모 동시 이미지 배포에 최적화된 멀티캐스트/브로드캐스트 도구입니다. PXE + iPXE와 결합하여 수백 대의 서버에 동시에 디스크 이미지를 전송할 수 있습니다.
# UDPcast 설치 및 사용
# 서버 설치 (Debian/Ubuntu)
sudo apt install udpcast
# === 1. 디스크 이미지 멀티캐스트 전송 ===
# 송신측 (서버): 디스크 이미지 전송
udp-sender --file /images/ubuntu-golden.img \
--mcast-addr 239.1.1.1 \
--portbase 9000 \
--min-receivers 10 \ # 최소 10대 수신 대기 후 시작
--max-wait 60 \ # 최대 60초 대기
--blocksize 1456 \ # 블록 크기 (MTU 최적화)
--fec 8x8/64 \ # Forward Error Correction
--autostart 30 \ # 30초 후 자동 시작
--log /var/log/udpcast.log
# 수신측 (클라이언트): initrd 안에서 실행
udp-receiver --mcast-addr 239.1.1.1 \
--portbase 9000 \
--file /dev/sda \ # 직접 디스크에 기록
--nosync # 완료 시 sync 생략 (빠른 재부팅)
# === 2. 파이프를 통한 실시간 압축 전송 ===
# 송신측
lz4 -c /dev/sda | udp-sender --pipe "cat" \
--mcast-addr 239.1.1.1 --portbase 9000 --min-receivers 5
# 수신측
udp-receiver --pipe "lz4 -d > /dev/sda" \
--mcast-addr 239.1.1.1 --portbase 9000
# === 3. iPXE 스크립트에서 UDPcast 연동 ===
# initrd에 udp-receiver를 포함시키고, 커널 파라미터로 멀티캐스트 주소 전달
# imgargs vmlinuz ip=dhcp udpcast_addr=239.1.1.1 udpcast_port=9000
atftpd 멀티캐스트 TFTP
# atftpd: 멀티캐스트 TFTP 서버 (RFC 2090)
sudo apt install atftpd
# /etc/default/atftpd 설정
USE_INETD=false
OPTIONS="--daemon --port 69 \
--tftpd-timeout 300 \
--retry-timeout 5 \
--maxthread 200 \
--bind-address 0.0.0.0 \
--verbose 5 \
--logfile /var/log/atftpd.log \
--mtftp 239.1.1.1,1758 \
--mtftp-port 1758 \
/var/lib/tftpboot"
# 멀티캐스트 TFTP 동작 원리:
# 1. 첫 번째 클라이언트가 RRQ 전송
# 2. 서버가 멀티캐스트 그룹으로 DATA 전송 시작
# 3. 이후 클라이언트들은 진행 중인 멀티캐스트 스트림에 합류
# 4. 놓친 블록은 유니캐스트로 재요청
# 주의: PXE ROM이 MTFTP를 지원해야 함 (많은 ROM이 미지원)
sudo systemctl restart atftpd
DHCP 릴레이와 다중 서브넷
DHCP 릴레이 개요
PXE 클라이언트의 DHCPDISCOVER는 브로드캐스트이므로, 라우터를 넘어갈 수 없습니다. 다중 서브넷 환경에서는 DHCP 릴레이 에이전트(ip helper-address)가 필요합니다.
# Cisco/Juniper 라우터 DHCP Relay 설정
# Cisco IOS
interface GigabitEthernet0/1
description Subnet-A
ip address 192.168.1.1 255.255.255.0
ip helper-address 10.0.0.1
interface GigabitEthernet0/2
description Subnet-B
ip address 192.168.2.1 255.255.255.0
ip helper-address 10.0.0.1
# Linux DHCP Relay Agent
sudo apt install isc-dhcp-relay
# /etc/default/isc-dhcp-relay
SERVERS="10.0.0.1"
INTERFACES="eth1 eth2"
OPTIONS="-a" # Agent Information (Option 82) 추가
sudo systemctl enable --now isc-dhcp-relay
# ISC DHCP 서버: 서브넷별 설정
# giaddr로 클라이언트 서브넷 식별
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.100 192.168.1.200;
option routers 192.168.1.1;
next-server 10.0.0.1;
filename "pxelinux.0";
}
subnet 192.168.2.0 netmask 255.255.255.0 {
range 192.168.2.100 192.168.2.200;
option routers 192.168.2.1;
next-server 10.0.0.1;
filename "pxelinux.0";
}
DHCP Option 82 (Relay Agent Information)
DHCP Option 82(RFC 3046)는 릴레이 에이전트가 DHCP 패킷에 추가하는 정보로, 클라이언트가 연결된 물리적 위치(스위치 포트, VLAN)를 DHCP 서버에 알려줍니다. 대규모 PXE 환경에서 자동 프로비저닝에 핵심적입니다.
DHCP Option 82 구조 (RFC 3046):
┌──────────────────────────────────────────────────────┐
│ Option 82 (Relay Agent Information) │
│ Type: 82 (0x52), Length: variable │
│ │
│ Sub-option 1: Circuit ID (물리적 포트 식별) │
│ - 스위치명 + 포트 번호 │
│ - 예: "Gi0/1" (GigabitEthernet 0/1) │
│ - 예: "Ethernet1/0/24" (스택 스위치) │
│ │
│ Sub-option 2: Remote ID (원격 장비 식별) │
│ - 릴레이 에이전트(스위치)의 MAC 또는 식별자 │
│ - 예: "00:1A:2B:3C:4D:5E" (스위치 MAC) │
│ │
│ Sub-option 5: Link Selection (선택적) │
│ - DHCP 서버가 사용할 서브넷 지정 │
│ Sub-option 6: Subscriber ID (선택적) │
│ - 가입자 식별 (ISP 환경) │
└──────────────────────────────────────────────────────┘
활용 시나리오:
- 스위치 포트 기반 자동 프로비저닝: "Gi0/1에 연결된 서버 → Web 프로파일"
- 랙/위치 기반 IP 할당: 포트 정보로 물리적 위치 파악
- 보안 감사: 어떤 포트에서 DHCP 요청이 왔는지 추적
# ISC DHCP에서 Option 82 활용 예제
# Option 82 서브옵션 정의
option agent.circuit-id code 1 = text;
option agent.remote-id code 2 = text;
# Circuit ID 기반 PXE 프로파일 자동 할당
class "rack1-servers" {
# 랙1의 스위치 포트 Gi0/1~Gi0/24에서 온 요청
match if substring(option agent.circuit-id, 0, 4) = "Gi0/";
}
# 클래스별 다른 부트 파일/OS 프로파일 할당
pool {
allow members of "rack1-servers";
range 192.168.1.100 192.168.1.124;
next-server 10.0.0.1;
filename "profiles/rack1/pxelinux.0";
}
# Cisco 스위치에서 Option 82 설정
# ip dhcp snooping
# ip dhcp snooping vlan 100
# ip dhcp snooping information option ← Option 82 삽입 활성화
# interface GigabitEthernet0/1
# ip dhcp snooping trust ← DHCP 서버 쪽 포트
트러블슈팅
일반적인 문제와 해결
| 증상 | 원인 | 해결 |
|---|---|---|
| PXE-E51: No DHCP or proxyDHCP offers were received | DHCP 서버 미응답 | DHCP 서비스 확인, 방화벽 UDP 67/68 열기, VLAN/포트 확인 |
| PXE-E53: No boot filename received | DHCP에 filename 미설정 | filename 또는 Option 67 설정 확인 |
| PXE-E32: TFTP open timeout | TFTP 서버 접근 불가 | TFTP 서비스 확인, 방화벽 UDP 69 열기, next-server IP 확인 |
| PXE-E36: Error received from TFTP server | 파일 없음 또는 권한 오류 | 파일 경로/권한 확인: ls -la /var/lib/tftpboot/ |
| PXE-E3B: TFTP Error - File not found | 부트파일 경로 오류 | 정확한 파일명 확인, 대소문자 주의 |
| PXE-E61: Media test failure, check cable | 네트워크 물리적 문제 | 케이블, 스위치 포트, 링크 상태 확인 |
| NBP 로드 후 검은 화면 | 아키텍처 불일치 | BIOS→.0 파일, UEFI→.efi 파일 확인 |
| GRUB: error: no suitable video mode found | 그래픽 모드 문제 | terminal_output console 사용 |
| "Booting from ROM" 후 멈춤 | PXE ROM 비활성화 | BIOS에서 NIC PXE/Network Boot 활성화 |
| UEFI HTTP Boot 실패 | HTTP 서버 문제 | URL 접근 가능 확인, Content-Type 헤더 확인 |
디버깅 도구와 명령어
# === DHCP 트래픽 캡처 ===
# tcpdump로 DHCP 패킷 모니터링
sudo tcpdump -i eth0 -vvv port 67 or port 68 or port 4011
# Wireshark 필터
# bootp || dhcp || tftp
# === TFTP 테스트 ===
# TFTP 클라이언트로 직접 파일 요청
tftp 192.168.1.10
tftp> get pxelinux.0
tftp> quit
# curl로 TFTP 테스트
curl tftp://192.168.1.10/pxelinux.0 -o /tmp/pxelinux.0
# === DHCP 서버 로그 ===
# ISC DHCP
sudo journalctl -u isc-dhcp-server -f
# dnsmasq
sudo journalctl -u dnsmasq -f
# 또는 dnsmasq --log-dhcp 옵션
# === TFTP 서버 로그 ===
sudo journalctl -u tftpd-hpa -f
# === iPXE 디버깅 ===
# iPXE 쉘에서 직접 디버깅
iPXE> dhcp net0
iPXE> show net0/ip
iPXE> show net0/netmask
iPXE> show net0/gateway
iPXE> show net0/dns
iPXE> nslookup pxe.example.com
iPXE> ping 192.168.1.10
iPXE> imgfetch tftp://192.168.1.10/pxelinux.0
iPXE> chain http://192.168.1.10/boot.ipxe
# === NFS 디버깅 ===
# NFS 마운트 테스트
sudo mount -t nfs 192.168.1.10:/exports/diskless /mnt -o vers=4,tcp
ls /mnt/
# NFS 서버 내보내기 확인
showmount -e 192.168.1.10
# rpcinfo (NFS v3)
rpcinfo -p 192.168.1.10
# === iSCSI 디버깅 ===
# iSCSI target 탐색
iscsiadm -m discovery -t sendtargets -p 10.0.0.1:3260
# iSCSI 로그인
iscsiadm -m node -T iqn.2024-01.com.example:storage -p 10.0.0.1 --login
# 세션 확인
iscsiadm -m session -P 3
# === 커널 네트워크 부팅 디버깅 ===
# 커널 커맨드 라인에 추가:
# ip=dhcp debug loglevel=7
# 시리얼 콘솔로 부팅 로그 확인:
# console=ttyS0,115200n8
PXE 패킷 분석 예제
# tcpdump 출력 예제: 정상적인 PXE 부팅 시퀀스
# 1. DHCPDISCOVER
12:00:00.001 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request
Client-Ethernet-Address 00:11:22:33:44:55
Vendor-Class: PXEClient:Arch:00000:UNDI:002001
Parameter-Request: Subnet-Mask(1), Router(3), DNS(6), Domain(15),
TFTP-Server(66), Boot-File(67), Vendor-Class(60), Client-Arch(93)
# 2. DHCPOFFER
12:00:00.005 IP 192.168.1.1.67 > 192.168.1.100.68: BOOTP/DHCP, Reply
Your-IP: 192.168.1.100
Server-IP: 192.168.1.10 ← TFTP 서버
Boot-File: pxelinux.0 ← NBP 파일명
# 3. DHCPREQUEST + DHCPACK (생략)
# 4. TFTP RRQ
12:00:00.050 IP 192.168.1.100.2070 > 192.168.1.10.69: TFTP, RRQ "pxelinux.0"
octet blksize 1468 tsize 0
# 5. TFTP OACK + DATA
12:00:00.051 IP 192.168.1.10.41234 > 192.168.1.100.2070: TFTP, OACK
blksize=1468 tsize=42780
12:00:00.052 IP 192.168.1.100.2070 > 192.168.1.10.41234: TFTP, ACK block 0
12:00:00.053 IP 192.168.1.10.41234 > 192.168.1.100.2070: TFTP, DATA block 1
... (29 더 많은 DATA 블록) ...
# 6. PXELINUX가 설정 파일 요청
12:00:01.100 IP 192.168.1.100.2071 > 192.168.1.10.69: TFTP, RRQ
"pxelinux.cfg/01-00-11-22-33-44-55" ← MAC 기반 설정 시도
12:00:01.101 IP 192.168.1.10.69 > 192.168.1.100.2071: TFTP, ERROR
code=1 File not found ← 없으면 다음 시도
12:00:01.102 IP 192.168.1.100.2072 > 192.168.1.10.69: TFTP, RRQ
"pxelinux.cfg/C0A80164" ← IP 기반 시도
12:00:01.103 IP 192.168.1.10.69 > 192.168.1.100.2072: TFTP, ERROR
code=1 File not found
12:00:01.104 IP 192.168.1.100.2073 > 192.168.1.10.69: TFTP, RRQ
"pxelinux.cfg/default" ← 기본 설정
12:00:01.105 IP 192.168.1.10.41235 > 192.168.1.100.2073: TFTP, DATA block 1
... (설정 파일 전송) ...
# 7. 커널 + initrd 다운로드
12:00:02.000 IP 192.168.1.100.2074 > 192.168.1.10.69: TFTP, RRQ "vmlinuz"
... (대용량 전송) ...
12:00:10.000 IP 192.168.1.100.2075 > 192.168.1.10.69: TFTP, RRQ "initrd.img"
... (대용량 전송) ...
실전 구성 예제
최소 PXE 서버 구성 (5분 설정)
#!/bin/bash
# minimal-pxe-setup.sh - dnsmasq 기반 최소 PXE 서버 설정
set -e
PXE_IFACE="eth0"
PXE_IP="192.168.1.10"
PXE_RANGE="192.168.1.100,192.168.1.200"
TFTP_ROOT="/var/lib/tftpboot"
# 1. 패키지 설치
sudo apt update
sudo apt install -y dnsmasq pxelinux syslinux-common
# 2. TFTP 디렉토리 구성
sudo mkdir -p ${TFTP_ROOT}/pxelinux.cfg
# SYSLINUX 파일 복사
sudo cp /usr/lib/PXELINUX/pxelinux.0 ${TFTP_ROOT}/
sudo cp /usr/lib/syslinux/modules/bios/{ldlinux.c32,menu.c32,libutil.c32,vesamenu.c32,libcom32.c32} ${TFTP_ROOT}/
# 3. dnsmasq 설정
sudo tee /etc/dnsmasq.d/pxe.conf << EOF
# PXE 서버 설정
interface=${PXE_IFACE}
bind-interfaces
# DHCP
dhcp-range=${PXE_RANGE},255.255.255.0,12h
dhcp-option=option:router,${PXE_IP}
dhcp-option=option:dns-server,8.8.8.8
# TFTP
enable-tftp
tftp-root=${TFTP_ROOT}
# PXE
dhcp-boot=pxelinux.0
# 로깅
log-dhcp
log-facility=/var/log/dnsmasq-pxe.log
EOF
# 4. 기본 메뉴 설정
sudo tee ${TFTP_ROOT}/pxelinux.cfg/default << 'EOF'
DEFAULT menu.c32
PROMPT 0
TIMEOUT 300
MENU TITLE PXE Boot Menu
LABEL local
MENU LABEL Boot from Local Disk
MENU DEFAULT
LOCALBOOT 0
EOF
# 5. 서비스 시작
sudo systemctl disable --now systemd-resolved 2>/dev/null || true
sudo systemctl enable --now dnsmasq
echo "PXE 서버 준비 완료!"
echo "커널/initrd를 ${TFTP_ROOT}/에 복사하고 pxelinux.cfg/default를 편집하세요."
전체 스택 구성 (DHCP + TFTP + HTTP + NFS)
#!/bin/bash
# full-pxe-stack.sh - 프로덕션급 PXE 서버 전체 스택
# === 1. dnsmasq (DHCP + TFTP + ProxyDHCP) ===
sudo tee /etc/dnsmasq.d/pxe-full.conf << 'EOF'
# DHCP
dhcp-range=192.168.1.100,192.168.1.200,255.255.255.0,12h
dhcp-option=option:router,192.168.1.1
dhcp-option=option:dns-server,8.8.8.8,8.8.4.4
# TFTP
enable-tftp
tftp-root=/var/lib/tftpboot
# 아키텍처별 자동 분기
dhcp-match=set:bios,option:client-arch,0
dhcp-match=set:efi64,option:client-arch,7
dhcp-match=set:efiaa64,option:client-arch,11
dhcp-match=set:ipxe,175
# iPXE 체인로딩
dhcp-boot=tag:bios,tag:!ipxe,undionly.kpxe
dhcp-boot=tag:efi64,tag:!ipxe,ipxe.efi
dhcp-boot=tag:efiaa64,tag:!ipxe,ipxe-arm64.efi
dhcp-boot=tag:ipxe,http://192.168.1.10/boot.ipxe
log-dhcp
EOF
# === 2. nginx (HTTP 부팅 서버) ===
sudo tee /etc/nginx/sites-available/pxe << 'EOF'
server {
listen 80;
server_name pxe.example.com 192.168.1.10;
root /var/www/pxeboot;
autoindex on;
sendfile on;
tcp_nopush on;
location /boot/ {
alias /var/lib/tftpboot/;
}
}
EOF
sudo ln -sf /etc/nginx/sites-available/pxe /etc/nginx/sites-enabled/
sudo systemctl reload nginx
# === 3. NFS 서버 ===
echo "/exports/diskless 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)" \
| sudo tee -a /etc/exports
sudo exportfs -arv
# === 4. iPXE 메인 스크립트 ===
sudo tee /var/www/pxeboot/boot.ipxe << 'IPXE'
#!ipxe
set boot-url http://192.168.1.10
menu Network Boot Menu
item ubuntu Ubuntu 24.04 LTS Install
item diskless Diskless Linux
item local Local Boot
choose --default local --timeout 30000 target && goto ${target} || goto local
:ubuntu
kernel ${boot-url}/images/ubuntu/vmlinuz ip=dhcp autoinstall ds=nocloud-net;s=${boot-url}/autoinstall/
initrd ${boot-url}/images/ubuntu/initrd
boot
:diskless
kernel ${boot-url}/vmlinuz-diskless root=/dev/nfs nfsroot=192.168.1.10:/exports/diskless,vers=4 ip=dhcp rw
initrd ${boot-url}/initrd-diskless.img
boot
:local
exit
IPXE
QEMU/KVM PXE 테스트 환경
QEMU/KVM을 사용하면 물리 서버 없이도 PXE 부팅을 테스트할 수 있습니다. QEMU에는 iPXE ROM이 내장되어 있어 별도 설치 없이 네트워크 부팅이 가능합니다.
# === 1. 기본 QEMU PXE 부팅 (가장 간단) ===
# QEMU의 내장 iPXE ROM으로 PXE 부팅
# -boot n: 네트워크 부팅 우선
qemu-system-x86_64 \
-m 2048 \
-boot n \
-nic user,tftp=/var/lib/tftpboot,bootfile=pxelinux.0 \
-nographic # 시리얼 콘솔 모드
# === 2. 브리지 네트워크 + 실제 PXE 서버 ===
# 실제 네트워크의 DHCP/PXE 서버에 연결
sudo qemu-system-x86_64 \
-m 4096 \
-cpu host -enable-kvm \
-boot order=n \
-device virtio-net-pci,netdev=br0,mac=52:54:00:12:34:56 \
-netdev bridge,id=br0,br=virbr0 \
-drive file=test-disk.qcow2,format=qcow2,if=virtio \
-vnc :1
# === 3. UEFI PXE 부팅 테스트 ===
# OVMF (Open Virtual Machine Firmware) 사용
sudo apt install ovmf
qemu-system-x86_64 \
-m 4096 \
-cpu host -enable-kvm \
-bios /usr/share/OVMF/OVMF_CODE.fd \
-boot order=n \
-device virtio-net-pci,netdev=net0 \
-netdev bridge,id=net0,br=virbr0 \
-drive file=test-uefi.qcow2,format=qcow2,if=virtio
# === 4. iPXE ROM 커스텀 빌드로 교체 ===
# 커스텀 iPXE ROM을 QEMU에서 사용
cd ipxe/src
make bin/8086100e.rom EMBED=embed.ipxe # Intel e1000 ROM
qemu-system-x86_64 \
-m 2048 \
-boot n \
-device e1000,netdev=net0,romfile=bin/8086100e.rom \
-netdev bridge,id=net0,br=virbr0
# === 5. 내부 DHCP 없이 테스트 (user 모드) ===
# QEMU user-mode 네트워킹으로 간단 테스트
qemu-system-x86_64 \
-m 2048 \
-boot n \
-nic user,model=virtio-net-pci,\
tftp=/var/lib/tftpboot,\
bootfile=pxelinux.0,\
dhcpstart=10.0.2.100
# === 6. libvirt/virsh로 PXE VM 생성 ===
virt-install \
--name pxe-test \
--ram 4096 \
--vcpus 2 \
--disk size=20,format=qcow2 \
--network bridge=virbr0,model=virtio \
--pxe \
--boot network,hd \
--os-variant ubuntu24.04 \
--graphics vnc
# === 7. 디버깅: QEMU 모니터에서 네트워크 확인 ===
# Ctrl+Alt+2 로 QEMU 모니터 진입
# (qemu) info network # 네트워크 장치 목록
# (qemu) info pci # PCI 장치 (NIC 확인)
# (qemu) hostfwd_add tcp::5555-:22 # SSH 포트 포워딩
romfile= 옵션으로 직접 빌드한 iPXE ROM을 사용하세요. virtio-net-pci 드라이버가 성능이 가장 좋고, iPXE도 virtio 드라이버를 내장하고 있습니다.
Preseed 자동 설치 예제 (Debian 13)
# /var/www/pxeboot/preseed/debian13.cfg
# Debian 13 Trixie 무인 설치 (Preseed)
# 로케일 및 키보드
d-i debian-installer/locale string en_US.UTF-8
d-i keyboard-configuration/xkb-keymap select us
# 네트워크
d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string debian-server
d-i netcfg/get_domain string example.com
# 미러 (로컬 미러 사용 시)
d-i mirror/country string manual
d-i mirror/http/hostname string 192.168.1.10
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string
# 시간대
d-i time/zone string Asia/Seoul
d-i clock-setup/utc boolean true
d-i clock-setup/ntp boolean true
# 파티셔닝 (UEFI + GPT, 전체 디스크 LVM)
d-i partman-efi/non_efi_system boolean true
d-i partman-partitioning/choose_label select gpt
d-i partman-partitioning/default_label string gpt
d-i partman-auto/method string lvm
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-auto/choose_recipe select atomic
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
# 루트 비밀번호 (해시)
d-i passwd/root-password-crypted password $6$rounds=656000$...
# 사용자 계정
d-i passwd/user-fullname string Admin User
d-i passwd/username string admin
d-i passwd/user-password-crypted password $6$rounds=656000$...
# 패키지
d-i pkgsel/include string openssh-server vim tmux nfs-common open-iscsi
tasksel tasksel/first multiselect standard, ssh-server
d-i pkgsel/upgrade select full-upgrade
popularity-contest popularity-contest/participate boolean false
# 부트로더 (GRUB)
d-i grub-installer/only_debian boolean true
d-i grub-installer/bootdev string default
# 설치 완료 후
d-i finish-install/reboot_in_progress note
d-i preseed/late_command string \
mkdir -p /target/root/.ssh; \
wget -O /target/root/.ssh/authorized_keys http://192.168.1.10/keys/admin.pub; \
chmod 600 /target/root/.ssh/authorized_keys; \
in-target systemctl enable ssh
preseed/url 또는 그 축약형 url=을 사용합니다. UEFI 서버를 기본 대상으로 둘 때는 partman-efi/non_efi_system과 GPT 라벨 선택을 같이 넣어 두는 편이 BIOS/UEFI 혼합 환경에서 덜 헷갈립니다.
Raspberry Pi 네트워크 부팅
# Raspberry Pi 4는 UEFI가 아닌 자체 네트워크 부팅 메커니즘 사용
# BCM2711 SoC의 부트 ROM이 직접 DHCP + TFTP 수행
# 1. Raspberry Pi의 시리얼 번호 확인
# Pi에서: cat /proc/cpuinfo | grep Serial
# 예: Serial : 00000000abcd1234 → 마지막 8자리: abcd1234
# 2. TFTP 디렉토리 구조 (시리얼 번호 기반)
/var/lib/tftpboot/
├── abcd1234/ # Pi 시리얼 번호
│ ├── start4.elf # GPU 펌웨어
│ ├── fixup4.dat # GPU 메모리 수정
│ ├── bcm2711-rpi-4-b.dtb
│ ├── config.txt # 부팅 설정
│ ├── cmdline.txt # 커널 커맨드 라인
│ └── kernel8.img # ARM64 커널
└── overlays/ # DT 오버레이
# 3. config.txt (네트워크 루트)
cat > /var/lib/tftpboot/abcd1234/config.txt << 'EOF'
arm_64bit=1
kernel=kernel8.img
initramfs initrd.img followkernel
EOF
# 4. cmdline.txt
echo "console=serial0,115200 console=tty1 root=/dev/nfs \
nfsroot=192.168.1.10:/exports/pi-root,vers=4,tcp ip=dhcp rw \
rootwait" > /var/lib/tftpboot/abcd1234/cmdline.txt
# 5. dnsmasq 설정 (Pi 전용)
# Pi는 Vendor Class를 보내지 않으므로, MAC 또는 태그로 분기
dhcp-host=dc:a6:32:xx:xx:xx,set:rpi
dhcp-boot=tag:rpi,abcd1234/start4.elf
pxe-service=0,"Raspberry Pi Boot"
Windows WDS/MDT 참고
Windows 배포 서비스 (WDS)
Windows Deployment Services(WDS)는 Microsoft의 PXE 기반 OS 배포 솔루션입니다. 리눅스 PXE 환경과의 호환성을 이해하는 것이 중요합니다.
| 항목 | Linux PXE | Windows WDS |
|---|---|---|
| DHCP | ISC DHCP / dnsmasq | Windows DHCP Server |
| TFTP | tftpd-hpa / dnsmasq | WDS TFTP 내장 |
| BIOS NBP | pxelinux.0 | wdsnbp.com → pxeboot.com |
| UEFI NBP | grubx64.efi | wdsmgfw.efi → bootmgfw.efi |
| 이미지 형식 | vmlinuz + initrd | WIM (Windows Imaging) |
| 자동 설치 | Kickstart/Preseed | unattend.xml |
| 멀티캐스트 | atftpd/UDPcast | WDS 멀티캐스트 내장 |
Linux + Windows 듀얼 PXE 환경
# iPXE 스크립트로 Linux/Windows 선택
#!ipxe
menu Dual Boot PXE Menu
item linux Linux Installation
item windows Windows Installation (WDS)
choose --default linux --timeout 20000 target && goto ${target}
:linux
chain http://192.168.1.10/linux-boot.ipxe
:windows
# WDS 서버로 체인로딩
# iPXE가 WDS의 wdsnbp.com을 로드하여 Windows 설치 시작
set next-server 192.168.1.20 # WDS 서버
chain tftp://${next-server}/boot/x64/wdsnbp.com
리눅스 커널 소스 분석
네트워크 부팅 관련 커널 소스 파일
| 파일 | 역할 |
|---|---|
net/ipv4/ipconfig.c | 커널 IP 자동 설정 (DHCP/BOOTP/RARP). ip= 파라미터 처리 |
fs/nfs/nfsroot.c | NFS 루트 마운트. nfsroot= 파라미터 처리 |
init/do_mounts.c | 루트 파일시스템 마운트 (root=/dev/nfs 감지) |
drivers/firmware/efi/libstub/ | EFI Stub: UEFI에서 직접 커널 부팅 |
drivers/net/ethernet/ | 이더넷 드라이버 (부팅 시 네트워크 초기화) |
include/linux/nfs_fs.h | NFS 클라이언트 헤더 |
drivers/scsi/iscsi_tcp.c | iSCSI TCP 트랜스포트 |
drivers/infiniband/ulp/iser/ | iSCSI over RDMA (iSER) |
네트워크 부팅 관련 커널 설정
# make menuconfig에서 네트워크 부팅에 필요한 옵션
# Networking → Networking options
CONFIG_IP_PNP=y # IP: kernel level autoconfiguration
CONFIG_IP_PNP_DHCP=y # IP: DHCP support
CONFIG_IP_PNP_BOOTP=y # IP: BOOTP support
CONFIG_IP_PNP_RARP=y # IP: RARP support
# File systems → Network File Systems
CONFIG_NFS_FS=y # NFS client support (built-in, NOT module!)
CONFIG_NFS_V3=y # NFS client support for NFS version 3
CONFIG_NFS_V4=y # NFS client support for NFS version 4
CONFIG_ROOT_NFS=y # Root file system on NFS
# Block devices → Network block devices
CONFIG_BLK_DEV_NBD=m # Network Block Device
CONFIG_ISCSI_TCP=m # iSCSI Initiator over TCP/IP
# 네트워크 드라이버 (부팅에 사용하는 NIC는 built-in 필수!)
CONFIG_E1000E=y # Intel(R) PRO/1000 PCI-Express
CONFIG_IGB=y # Intel(R) 82575/82576 PCI-Express
CONFIG_IXGBE=y # Intel(R) 10GbE PCI Express
CONFIG_MLX5_CORE=y # Mellanox ConnectX
CONFIG_R8169=y # Realtek RTL8169
CONFIG_BNX2X=y # Broadcom NetXtreme II 10Gb
# initramfs 사용 시 NFS/iSCSI를 모듈로 컴파일해도 됨
# 단, initramfs에 해당 모듈을 포함해야 함
커널 IP 자동 설정 흐름
/* net/ipv4/ipconfig.c - 커널 네트워크 자동 설정 전체 흐름 */
/*
* 호출 순서:
* start_kernel()
* → kernel_init()
* → kernel_init_freeable()
* → do_basic_setup()
* → prepare_namespace()
* → ip_auto_config() ← ip= 파라미터 처리
* → mount_root() ← root= 파라미터 처리
* → nfs_root_setup() ← root=/dev/nfs 시
*/
static int __init ip_auto_config(void)
{
/* 1. 네트워크 인터페이스 탐색 */
ic_open_devs(); /* 모든 이더넷 디바이스 열기 */
/* 2. DHCP/BOOTP/RARP 중 활성화된 프로토콜로 IP 설정 */
if (ic_enable) {
/* DHCP 패킷 송신 */
ic_bootp_init();
/* 응답 대기 (최대 ~60초) */
ic_dynamic();
/* IP, 게이트웨이, DNS, NFS root path 등 설정 */
ic_setup_if(); /* 인터페이스 IP 설정 */
ic_setup_routes(); /* 라우팅 테이블 설정 */
}
/* 3. 결과 출력 */
pr_info("IP-Config: Complete:\n");
pr_info(" device=%s, hwaddr=%pM, ipaddr=%pI4, "
"mask=%pI4, gw=%pI4\n",
ic_dev->name, ic_dev->dev_addr,
&ic_myaddr, &ic_netmask, &ic_gateway);
pr_info(" host=%s, domain=%s, nis-domain=%s\n",
utsname()->nodename, ic_domain, utsname()->domainname);
pr_info(" bootserver=%pI4, rootserver=%pI4, rootpath=%s\n",
&ic_servaddr, &root_server_addr, root_server_path);
return 0;
}
클라우드 & 베어메탈 PXE 패턴
클라우드 환경의 PXE 부팅
퍼블릭 클라우드의 베어메탈 서비스와 프라이빗 클라우드 인프라에서 PXE는 서버 프로비저닝의 핵심 메커니즘입니다.
| 플랫폼 | PXE 방식 | 자동화 | 특징 |
|---|---|---|---|
| Equinix Metal | iPXE + Custom OS | API + iPXE 스크립트 | 사용자 iPXE 스크립트 URL 지정 가능. 커스텀 OS 부팅 지원 |
| AWS Outposts | PXE + EC2 이미지 | SSM + CloudFormation | 온프레미스 AWS 인프라에서 PXE 부팅 |
| Oracle BM | iPXE | OCI API | 베어메탈 인스턴스에 iPXE 스크립트 제공 |
| Hetzner | DHCP + iPXE | Robot API | rescue 시스템 + installimage 스크립트 |
| OpenStack Ironic | PXE/iPXE + IPA | Nova API | Ironic Python Agent로 디스크 기록 |
| MAAS (Canonical) | PXE + cloud-init | REST API + CLI | 자동 발견 → commissioning → 배포 |
| Tinkerbell (Equinix) | iPXE + Workflow | gRPC API | 클라우드 네이티브, Kubernetes 기반 |
클라우드 베어메탈 iPXE 커스텀 부팅 예제
# Equinix Metal 스타일: 사용자 제공 iPXE 스크립트로 커스텀 OS 부팅
#!ipxe
# 서버의 메타데이터 조회 (클라우드 API에서 제공)
# Equinix Metal은 metadata.packet.net 제공
# chain https://metadata.packet.net/ipxe?uuid=${uuid}&mac=${mac}
# 또는 직접 스크립트 작성:
set base-url https://my-pxe-server.example.com
# 호스트 메타데이터 기반 분기
chain ${base-url}/api/v1/boot?uuid=${uuid}&serial=${serial}&mac=${mac:hexhyp} || goto fallback
:fallback
# Flatcar Container Linux 부팅 (CoreOS 후속)
set coreos-url https://stable.release.flatcar-linux.net/amd64-usr/current
kernel ${coreos-url}/flatcar_production_pxe.vmlinuz \
flatcar.first_boot=1 \
flatcar.config.url=${base-url}/ignition/${uuid}.json \
ip=dhcp
initrd ${coreos-url}/flatcar_production_pxe_image.cpio.gz
boot
// Ignition 설정 예제 (Flatcar/CoreOS 자동 프로비저닝)
// /var/www/pxeboot/ignition/default.json
{
"ignition": { "version": "3.4.0" },
"storage": {
"filesystems": [{
"device": "/dev/sda1",
"format": "ext4",
"path": "/",
"wipeFilesystem": true
}]
},
"systemd": {
"units": [{
"name": "docker.service",
"enabled": true
}]
},
"passwd": {
"users": [{
"name": "core",
"sshAuthorizedKeys": ["ssh-ed25519 AAAA... admin@example.com"],
"groups": ["docker", "sudo"]
}]
}
}
OpenStack Ironic PXE 배포 흐름
# OpenStack Ironic 베어메탈 노드 등록 및 배포
# 1. 노드 등록
openstack baremetal node create \
--driver ipmi \
--driver-info ipmi_address=10.0.0.100 \
--driver-info ipmi_username=admin \
--driver-info ipmi_password=secret \
--driver-info deploy_kernel=file:///var/lib/ironic/ipa-kernel \
--driver-info deploy_ramdisk=file:///var/lib/ironic/ipa-ramdisk \
--property cpus=32 --property memory_mb=65536 \
--property local_gb=500
# 2. 포트(NIC) 등록
openstack baremetal port create \
--node \
00:11:22:33:44:55 # PXE 부팅용 MAC 주소
# 3. 이미지 기반 배포
openstack baremetal node deploy \
--instance-info image_source= \
--instance-info root_gb=50
# Ironic이 자동으로:
# 1) IPMI로 서버 전원 ON
# 2) PXE 부팅 → IPA 로드
# 3) IPA가 이미지 다운로드 → 디스크 기록
# 4) PXE에서 로컬 부팅으로 전환
# 5) 서버 재부팅 → OS 가동
흔한 실수
BIOS 모드 클라이언트에 EFI 바이너리(
.efi)를, UEFI 클라이언트에 BIOS 바이너리(.0)를 제공하면 부팅 실패합니다.
DHCP Option 93을 확인하여 올바른 바이너리를 제공하세요.
TFTP는
tftp-root를 기준으로 경로를 해석합니다. 절대 경로(/var/lib/tftpboot/pxelinux.0)가 아니라 상대 경로(pxelinux.0)를 사용해야 합니다.
PXE에 필요한 포트: UDP 67/68(DHCP), UDP 69(TFTP), UDP 4011(ProxyDHCP), TCP 2049(NFS v4), TCP 3260(iSCSI), TCP 80/443(HTTP/HTTPS). 특히 TFTP는 데이터 전송 시 랜덤 고번호 포트를 사용하므로 conntrack 모듈이 필요합니다:
modprobe nf_conntrack_tftp
NFS 루트 부팅 시 NIC 드라이버와 NFS 클라이언트가 커널에 built-in(
=y)이거나, initramfs에 모듈이 포함되어야 합니다. 모듈(=m)만 있고 initramfs에 없으면 네트워크를 활성화할 수 없어 루트를 마운트할 수 없습니다.
iPXE 체인로딩 설정에서 iPXE와 일반 PXE를 구분하지 않으면 무한 루프가 발생합니다. ISC dhcpd 예제는 보통
user-class = "iPXE"를, dnsmasq 예제는 Option 175를 자주 사용합니다. 어느 방식을 쓰든 "이미 iPXE에 들어온 클라이언트"를 한 번만 식별해 HTTP 스크립트로 넘겨야 합니다.
PXELINUX를 사용할 때
ldlinux.c32, libutil.c32, libcom32.c32 등 필수 COM32 모듈을 TFTP 루트에 복사하지 않으면 메뉴가 표시되지 않습니다. SYSLINUX 버전과 모듈 버전이 일치해야 합니다.
표준 및 공식 문서
PXE는 구현 편차가 큰 분야라서 블로그 글보다 표준 문서와 공식 구현 문서를 같이 보는 편이 안전합니다. 아래 문서들은 이 페이지를 보강하면서 직접 대조한 기준 자료입니다.
- RFC 2131 — DHCP 본체 사양
- RFC 2132 — DHCP Options and BOOTP Vendor Extensions. Option 66/67 해석 근거
- RFC 4578 — PXE 관련 DHCP 옵션(Option 93/94/97) 정의
- RFC 5970 — DHCPv6 부트 옵션(59/60/61/62) 정의
- RFC 7440 — TFTP windowsize 옵션
- IANA Processor Architecture Types — 최신 아키텍처 코드 레지스트리
- UEFI 2.11: Network Protocols — PXE Base Code, netboot6, HTTP Boot 규정
- iPXE 공식 DHCP 가이드 — BIOS/UEFI 체인로딩 패턴
- iPXE 공식 Chainloading 가이드 —
undionly.kpxe,ipxe.efi,snponly.efi선택 기준 - iPXE Crypto 문서 — HTTPS/TLS, 인증서, 암호 알고리즘 지원 범위
- Linux kernel nfsroot 문서 —
root=/dev/nfs,nfsroot=,ip=구문 - RHEL 10 Kickstart 문서 — PXE / UEFI HTTP Boot에서
inst.ks=사용법 - RHEL 10 Kickstart 생성 문서 —
ksvalidator -v RHEL10검증 흐름 - Ubuntu Autoinstall Quick Start —
user-data,meta-data,ds=nocloud-net전달 방식 - Ubuntu Autoinstall Reference — 24.04 이후 최상위
autoinstall:및 스키마 검증 규칙 - Ubuntu Server Netboot 문서 — UEFI/BIOS PXE에서 live server installer 부팅 절차
- Debian stable 릴리스 정보 — 2026-03-07 기준 stable이 Debian 13 (trixie)임을 확인
- Debian Installer Preseed 가이드 —
preseed/url,auto=true,priority=critical커널 인자 - Debian example-preseed / EFI 가이드 — UEFI용 GPT/EFI
partman옵션 예시
관련 문서
이 주제와 관련된 다른 문서를 더 깊이 이해하고 싶다면 다음을 참고하세요.