1111# --skip-mirror Skip fai-mirror (reuse existing mirror)
1212# --clean Remove all build artifacts and cached data, then exit
1313# --dry-run Validate config and show what would be built, then exit
14+ # --arch ARCH Target architecture: amd64 (default) or arm64
1415# --no-docker Run natively even on macOS (used internally by Docker)
1516#
1617# Copyright (c) 2026 — Licensed under the GNU General Public License v3.
@@ -41,6 +42,7 @@ NC='\033[0m' # No Color
4142
4243CONFIG_FILE=" ./build.yaml"
4344OUTPUT_OVERRIDE=" "
45+ TARGET_ARCH=" amd64" # Target ISO architecture (amd64 or arm64)
4446VERBOSE=0
4547SKIP_SETUP=0
4648SKIP_MIRROR=0
@@ -66,6 +68,7 @@ Options:
6668 --skip-mirror Skip fai-mirror (reuse existing mirror)
6769 --clean Remove all build artifacts and cached data, then exit
6870 --dry-run Validate config and show what would be built, then exit
71+ --arch ARCH Target architecture: amd64 (default) or arm64
6972 --no-docker Run natively (used internally by Docker entrypoint)
7073
7174Examples:
@@ -153,6 +156,10 @@ parse_args() {
153156 NO_DOCKER=1
154157 shift
155158 ;;
159+ --arch)
160+ TARGET_ARCH=" $2 "
161+ shift 2
162+ ;;
156163 * )
157164 log_fatal " Unknown option: $1 \nRun './build.sh --help' for usage."
158165 ;;
@@ -222,16 +229,21 @@ run_in_docker() {
222229 output_dir=" $( cd " $( dirname " ${OUTPUT_OVERRIDE:- ./ output/ fai.iso} " ) " && pwd) "
223230 mkdir -p " $output_dir "
224231
225- # Build the Docker image (only if Dockerfile changed)
232+ # Map target arch to Docker platform
233+ local docker_platform=" linux/${TARGET_ARCH} "
234+ echo -e " Target architecture: ${TARGET_ARCH} (platform: ${docker_platform} )"
235+
236+ # Build the Docker image for the target platform
226237 local dockerfile_hash
227238 dockerfile_hash=" $( md5 -q " $REPO_ROOT /Dockerfile" 2> /dev/null || md5sum " $REPO_ROOT /Dockerfile" | cut -d' ' -f1) "
228239 echo -e " Building Docker image (hash: ${dockerfile_hash: 0: 8} )..."
229- docker build -t fai-luks-builder " $REPO_ROOT "
240+ docker build --platform " $docker_platform " -t " fai-luks-builder: ${TARGET_ARCH} " " $REPO_ROOT "
230241
231242 # Construct docker run arguments
232243 local -a docker_args=(
233244 --rm
234245 --privileged
246+ --platform " $docker_platform "
235247 --tmpfs /tmp:exec
236248 -v " ${CONFIG_FILE} :/workspace/build.yaml:ro"
237249 -v " ${output_dir} :/output"
@@ -271,8 +283,10 @@ run_in_docker() {
271283 local output_basename
272284 output_basename=" $( basename " ${OUTPUT_OVERRIDE:- fai-luks.iso} " ) "
273285
286+ passthrough+=(--arch " $TARGET_ARCH " )
287+
274288 echo -e " Starting container..."
275- docker run " ${docker_args[@]} " fai-luks-builder \
289+ docker run " ${docker_args[@]} " " fai-luks-builder: ${TARGET_ARCH} " \
276290 --config /workspace/build.yaml \
277291 --output " /output/${output_basename} " \
278292 " ${passthrough[@]} "
@@ -539,9 +553,16 @@ write_fai_config() {
539553 log_info " Wrote /etc/fai/fai.conf"
540554
541555 cp " $REPO_ROOT /templates/nfsroot.conf.tpl" /etc/fai/nfsroot.conf
542- # Inject the release codename into nfsroot.conf (it's outside the config space)
556+ # Inject the release codename and arch-specific GRUB package into nfsroot.conf
543557 template_replace " TEMPLATED_RELEASE" " $BUILD_RELEASE " /etc/fai/nfsroot.conf
544- log_info " Wrote /etc/fai/nfsroot.conf (release: $BUILD_RELEASE )"
558+ local grub_efi_pkg
559+ case " $TARGET_ARCH " in
560+ amd64) grub_efi_pkg=" grub-efi-amd64-bin" ;;
561+ arm64) grub_efi_pkg=" grub-efi-arm64-bin" ;;
562+ * ) log_fatal " Unsupported architecture: $TARGET_ARCH " ;;
563+ esac
564+ template_replace " TEMPLATED_GRUB_EFI_PKG" " $grub_efi_pkg " /etc/fai/nfsroot.conf
565+ log_info " Wrote /etc/fai/nfsroot.conf (release: $BUILD_RELEASE , grub: $grub_efi_pkg )"
545566
546567 # Enable FAI repo in the nfsroot apt sources
547568 if [ -f /etc/fai/apt/sources.list ]; then
@@ -703,6 +724,11 @@ assemble_config_space() {
703724 chmod 600 " $config_dir /.luks_passphrase"
704725 log_info " LUKS passphrase written to config space"
705726
727+ # Derive arch class name (amd64 → AMD64, arm64 → ARM64)
728+ local arch_class
729+ arch_class=" $( echo " $TARGET_ARCH " | tr ' [:lower:]' ' [:upper:]' ) "
730+
731+ template_replace_all " TEMPLATED_ARCH_CLASS" " $arch_class " " $config_dir "
706732 template_replace_all " TEMPLATED_RELEASE_CLASS" " $BUILD_RELEASE_CLASS " " $config_dir "
707733 template_replace_all " TEMPLATED_RELEASE" " $BUILD_RELEASE " " $config_dir "
708734 template_replace_all " TEMPLATED_ADMIN_USER" " $BUILD_ADMIN_USER " " $config_dir "
@@ -944,6 +970,7 @@ do_dry_run() {
944970 echo " timezone: $BUILD_TIMEZONE "
945971 echo " locale: $BUILD_LOCALE "
946972 echo " keyboard: $BUILD_KEYBOARD "
973+ echo " target_arch: $TARGET_ARCH "
947974 echo " disk_device: $BUILD_DISK_DEVICE "
948975 echo " efi_size: $BUILD_EFI_SIZE "
949976 echo " boot_size: $BUILD_BOOT_SIZE "
@@ -976,7 +1003,9 @@ do_dry_run() {
9761003 done
9771004
9781005 echo -e " \n${BOLD} Final class list:${NC} "
979- echo " DEFAULT LINUX AMD64 DHCPC FAIBASE DEBIAN ${BUILD_RELEASE_CLASS} GRUB_EFI LUKS_SERVER CUSTOM_SETUP LAST"
1006+ local arch_class_dry
1007+ arch_class_dry=" $( echo " $TARGET_ARCH " | tr ' [:lower:]' ' [:upper:]' ) "
1008+ echo " DEFAULT LINUX ${arch_class_dry} DHCPC FAIBASE DEBIAN ${BUILD_RELEASE_CLASS} GRUB_EFI LUKS_SERVER CUSTOM_SETUP LAST"
9801009
9811010 echo -e " \n${GREEN}${BOLD} Dry run complete — config is valid.${NC} "
9821011 exit 0
0 commit comments