| Tested on | Rocky Linux 10.2 (Red Quartz) |
|---|---|
| Package | lorax 40.5.15cpio 2.15pigz 2.8. |
| Applies to | RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora |
| Privilege | sudo or root |
| Scope | Create Anaconda updates.img on RHEL 8–10, embed it in boot media with mkksiso, load it with inst.updates, and verify the installer overlay. |
| Related guides | RHEL Image Builder Kickstart initrd.img update and rebuild guide custom RHEL ISO guide Kickstart PXE boot server guide |
updates.img is a compressed CPIO archive whose files are added to or replace matching paths in the Anaconda installer runtime. It is mainly useful for testing installer fixes, loading Anaconda add-ons, injecting installer configuration, and troubleshooting installation-time behavior.
This guide covers RHEL 8, 9, and 10 and equivalent Anaconda-based Enterprise Linux installers on Rocky Linux, AlmaLinux, and CentOS Stream. Production overlays also include patched Python modules, D-Bus service files, and /etc/anaconda/conf.d/ snippets when you need real installer customization beyond a harmless test marker.
updates.img, product.img, initrd.img, and Kickstart compared
| Method | Main purpose | Loaded when | Typical content |
|---|---|---|---|
updates.img |
Apply temporary updates to the Anaconda runtime | Installer startup | Anaconda add-ons, Python files, D-Bus files, configuration and test fixes |
product.img |
Package installer product customization | From images/ on boot media |
Branding, product configuration, add-ons and installer files |
initrd.img |
Provide the early boot and installer environment | Before Anaconda starts | Drivers, dracut modules and early-boot files |
| Kickstart | Automate installation choices | Read by Anaconda | Storage, packages, users, networking and post-install actions |
| Image Builder | Produce supported customized RHEL media or images | Before deployment | Packages, configuration and image composition |
This article focuses on updates.img. product.img uses a similar overlay layout but is a separate packaging workflow with its own .buildstamp expectations. A basic updates.img does not need .buildstamp.
updates.img and product.img, but supports installation-media customization through RHEL Image Builder. Use Kickstart for repeatable installation configuration whenever installer-runtime modification is not required.
Do not rebuild initrd.img when the change only needs to overlay the Anaconda runtime. For driver and early-boot changes, see the initrd.img update and rebuild guide. Do not use updates.img for changes that belong in Kickstart or the installed operating system.
How Anaconda applies updates.img
When Anaconda starts, it locates updates.img, extracts the compressed CPIO archive, and places files over matching paths in the installer runtime. New files become available to Anaconda during that installation only. The overlay does not automatically copy those files onto the target system under /mnt/sysroot.
The archive must reproduce the exact installer-runtime path. The installer environment is not the same as the target root that will be installed.
| Intended installer path | Path inside the working directory |
|---|---|
/etc/anaconda/conf.d/99-custom.conf |
./etc/anaconda/conf.d/99-custom.conf |
/usr/share/anaconda/addons/example/ |
./usr/share/anaconda/addons/example/ |
/usr/share/anaconda/dbus/services/example.service |
./usr/share/anaconda/dbus/services/example.service |
Red Hat still documents updates.img on RHEL 10, including HTTP, local disk or USB, installation-tree discovery, and embedding with mkksiso -u on releases that ship a current Lorax build.
Prepare the build environment
Install the packaging tools on a RHEL-family build host. Rocky Linux 10.2 ships them in the standard repositories.
sudo dnf install cpio pigz loraxConfirm the packages are present before you create the archive.
rpm -q cpio pigz loraxSample output:
cpio-2.15-3.el10.x86_64
pigz-2.8-7.el10.x86_64
lorax-40.5.15-1.el10.rocky.0.4.x86_64cpio creates the archive, pigz compresses it, and lorax provides mkksiso for ISO embedding. gzip works when pigz is unavailable; pick one compressor and use it consistently in the procedure.
Create a clean workspace separate from unrelated initrd experiments.
mkdir -p ~/anaconda-updates/work
cd ~/anaconda-updates/workKeep the source boot ISO outside the working tree, for example:
~/anaconda-updates/rhel-10-boot.isoDo not build under a directory such as /tmp/custom_initrd. updates.img is an Anaconda runtime overlay, not an initrd.img rebuild.
Create a safe test customization
This walkthrough uses a marker file that proves the overlay was fetched, extracted, and applied without risking an invalid Anaconda configuration key. Production overlays commonly add /etc/anaconda/conf.d/ snippets, add-ons under /usr/share/anaconda/addons/, or patched Python modules after you compare the target installer version.
Create the archive path for the marker file.
mkdir -p usr/share/golinuxcloudAdd a short text file whose contents you can verify in the installer shell.
printf '%s\n' 'updates.img loaded successfully' \
> usr/share/golinuxcloud/updates-image-test.txtThat file maps to /usr/share/golinuxcloud/updates-image-test.txt in the installer runtime.
/etc/anaconda/conf.d/ file from an older release, inspect /etc/anaconda/anaconda.conf on the exact installer you are customizing.
Build and inspect updates.img
Run the archive command from the root of the working tree so paths stay relative.
find . -print0 \
| cpio --null -o -H newc \
| pigz -9 > ../updates.imgThe -print0 and --null pair safely handles unusual filenames, newc selects an explicit modern CPIO format, and building from the working root prevents an unwanted parent directory prefix.
Red Hat also documents a shorter equivalent:
find . | cpio -c -o | pigz -9cv > ../updates.imgCheck the resulting file type.
file ../updates.imgSample output:
../updates.img: gzip compressed data, max compression, from Unix, original size modulo 2^32 1024List the archive contents without extracting it.
pigz -dc ../updates.img | cpio -itSample output:
.
usr
usr/share
usr/share/golinuxcloud
usr/share/golinuxcloud/updates-image-test.txtThe first path component must match the installer-runtime layout. Reject archives that begin with a build-host prefix such as home/user/anaconda-updates/work/... or tmp/custom_updates_img/....
Do not add .buildstamp to this basic updates.img.
Add updates.img to a boot ISO
Current RHEL 10 versions of mkksiso support embedding an Anaconda updates image directly. Confirm that the installed version provides the option:
mkksiso --help | grep -E -- '--updates|-u'When the option is available, embed the image:
sudo mkksiso \
-u ~/anaconda-updates/updates.img \
~/anaconda-updates/rhel-10-boot.iso \
~/anaconda-updates/rhel-10-updated.isoThe -u option is a current RHEL 10 workflow and might not be available in the older Lorax packages shipped with RHEL 8 or RHEL 9. On those releases, load the image externally with inst.updates= or follow the custom RHEL ISO guide for release-specific ISO extraction and repackaging.
Confirm the output ISO exists after the command completes.
ls -lh ~/anaconda-updates/rhel-10-updated.isoOptionally inspect ISO metadata when isoinfo is installed:
isoinfo -d -i ~/anaconda-updates/rhel-10-updated.isoFor manual xorrisofs, EFI partition, boot-catalog, and MD5 rebuild steps, see the custom RHEL ISO guide instead of duplicating that procedure here.
Boot the modified ISO
Attach the new ISO through your hypervisor, write it to USB media, or expose it through BMC virtual media. Boot the system and confirm that Anaconda starts normally before you rely on the overlay.
Load updates.img externally with inst.updates
Rebuilding the ISO is not required when the image is reachable during installer startup.
Load over HTTP or HTTPS
inst.updates=https://install.example.com/rhel/updates.imgNetworking must be available before Anaconda can retrieve the file. Add ip=dhcp or other network boot options only when your boot environment requires them.
Load from USB or a local disk
By device name:
inst.updates=sda1:/images/updates.imgPrefer a stable UUID when the device name may change in the installer environment:
inst.updates=UUID=b4234403-dafb-44c1-b878-4d57b40c9843:/updates.imgDevice naming in the installer can differ from the installed system, so UUID is usually safer.
Load from an installation tree
Anaconda can discover a correctly named updates.img from supported installation-tree locations. For network trees, keep the file name exactly updates.img. For NFS installations, current RHEL documentation recognizes paths such as images/updates.img and RHupdates/updates.img.
See the RHEL 10 boot options reference for the complete syntax across protocols.
Add inst.updates to PXE or GRUB
Append the option to the installer kernel command line. The bootloader directive may be linux, linuxefi, or another firmware-specific form.
linuxefi images/pxeboot/vmlinuz \
inst.repo=https://install.example.com/rhel/10/BaseOS/x86_64/os/ \
inst.ks=https://install.example.com/kickstart/server.ks \
inst.updates=https://install.example.com/rhel/updates.img \
ip=dhcpUse current inst.* options instead of legacy ks= or ksdevice= syntax from RHEL 7 boot menus. For PXE server layout, see the Kickstart PXE boot server guide without repeating that full procedure here.
Verify that Anaconda loaded the image
Boot with the modified ISO or an inst.updates= option that points at your image.
Open the installer shell by switching to the tmux console:
Ctrl+Alt+F1Then press Ctrl+b, release both keys, and press 2 to open the interactive root shell. To return to the graphical installer, use Ctrl+Alt+F6.
Check for the injected marker file.
cat /usr/share/golinuxcloud/updates-image-test.txtExpected output:
updates.img loaded successfullySearch installer logs for retrieval and application messages.
grep -Ri 'updates' /tmp/anaconda.log /tmp/program.log /tmp/storage.logOn systems where journalctl is available in the installer environment:
journalctl -b | grep -i updatesSuccessful download does not prove the customized file is valid. Verify both that the file exists in the installer runtime and that Anaconda accepts the customization. Installation logs normally live under /tmp during installation and are copied into the installed system after a successful install.
Extract and rebuild an existing updates.img
Create a new extraction directory for each rebuild. Using a timestamp avoids mixing files from an earlier extraction:
extract_dir="$HOME/anaconda-updates/extracted-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$extract_dir"
cd "$extract_dir"Extract the archive.
pigz -dc "$HOME/anaconda-updates/updates.img" | cpio -idmvModify the required files, then rebuild from inside the extraction root.
find . -print0 \
| cpio --null -o -H newc \
| pigz -9 > "$HOME/anaconda-updates/updates-rebuilt.img"Verify the rebuilt image before use.
pigz -dc "$HOME/anaconda-updates/updates-rebuilt.img" | cpio -itSample output:
.
usr
usr/share
usr/share/golinuxcloud
usr/share/golinuxcloud/updates-image-test.txtExtracting into a non-empty directory can leave stale files in the rebuilt image. Always extract into a new directory.
Troubleshoot updates.img loading failures
Installer cannot download updates.img
Check URL spelling and case, DNS resolution, installer networking, HTTP status, TLS trust, and proxy requirements.
From another system on the network:
curl -I https://install.example.com/rhel/updates.imgInside the installer shell, use the tools available in that runtime to confirm connectivity to the same URL.
Archive loads but files are missing
Inspect archive paths on the build host.
pigz -dc updates.img | cpio -itCommon causes include building from the wrong working directory, absolute or parent paths in the archive, a misspelled installer path, placing files under the target-system tree instead of the installer runtime, or compressing the archive twice.
Anaconda fails after applying the image
Remove the image and boot the unmodified installer to confirm the overlay caused the failure. Inspect /tmp/anaconda.log, /tmp/program.log, /tmp/packaging.log, and journalctl when available.
Likely causes include Python or API incompatibility, an invalid Anaconda configuration option, a missing D-Bus service or policy file, a file from another RHEL major version, or replacing a critical installer file with an incompatible build.
PXE boot ignores inst.updates
Confirm the option appears on the final kernel command line, the URL is reachable from the installer rather than only from the PXE server, required networking options are present, and the boot entry you edited matches the firmware mode in use.
cat /proc/cmdline| Symptom | Likely cause | Main verification |
|---|---|---|
| Image not downloaded | Network or URL failure | curl, installer logs |
| File absent after loading | Incorrect archive path | cpio -it |
| Anaconda crashes | Incompatible customization | /tmp/anaconda.log |
| PXE option ignored | Wrong boot entry or command line | /proc/cmdline |
| Modified ISO does not boot | ISO build or label problem | Rebuild with mkksiso |
| Changes appear in installed OS unexpectedly | Confusion between installer and target roots | Review overlay path and Kickstart |
When product.img is the better choice
product.img is normally associated with installer product customization such as branding and pixmaps, GUI stylesheets, product or profile configuration, installer add-ons, and persistent Anaconda configuration packaged with the boot media. It is normally placed at images/product.img on the installation ISO.
Unlike the basic updates.img workflow, current Red Hat documentation associates .buildstamp with product customization and product.img. Documented product content paths include /usr/share/anaconda/pixmaps/, /usr/share/anaconda/addons/, /etc/anaconda/profile.d/, and /etc/anaconda/conf.d/.
Use a dedicated product.img guide when branding or persistent installer customization is the goal. inst.updates= can load a compatible overlay from another location even when the file name is not literally updates.img, but this article consistently names the artifact updates.img.
For supported RHEL media composition without hand-built installer overlays, see Cockpit Image Builder for custom RHEL ISO.
Conclusion
updates.img remains part of current Anaconda-based RHEL-family installers. Build it as a compressed CPIO archive whose paths mirror the installer runtime, omit .buildstamp for a basic overlay, embed it with mkksiso -u on RHEL 10 when that option is available, or load it with inst.updates= over HTTP, local disk, USB, or an installation tree. Verify the overlay inside the installer environment before you trust a full installation run.
Use Kickstart or Image Builder when runtime modification is unnecessary. RHEL 7 used older boot-option syntax; treat EL7 as legacy and follow current Red Hat documentation for RHEL 8, 9, and 10.
References
- Red Hat Enterprise Linux 10 — Customizing Anaconda —
updates.img,product.img,mkksiso -u, and overlay paths - Red Hat Enterprise Linux 10 — Boot options reference —
inst.updates=syntax and supported sources - initrd.img update and rebuild guide — early-boot changes that do not belong in
updates.img - Custom RHEL ISO guide — manual ISO rebuild workflows beyond
mkksiso

