Skip to main content
AI
  • Get started with AI

    • Red Hat AI

      Accelerate the development and deployment of enterprise AI solutions.

    • AI learning hub

      Explore learning materials and tools, organized by task.

    • AI interactive demos

      Click through scenarios with Red Hat AI, including training LLMs and more.

    • AI/ML learning paths

      Expand your Red Hat OpenShift AI knowledge using these learning resources.

    • AI quickstarts

      Focused AI use cases designed for fast deployment on Red Hat AI platforms.

    • No-cost AI training

      Foundational Red Hat AI training.

  • Featured resources

    • Red Hat OpenShift AI
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

Red Hat AI Factory with NVIDIA

Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.

Learn
  • Self-guided

    • Documentation

      Find answers, get step-by-step guidance, and learn how to use Red Hat products.

    • Learning paths

      Explore curated walkthroughs for common development tasks.

    • Guided learning

      Receive custom learning paths powered by our AI assistant.

    • See all learning
  • Hands-on

    • Developer Sandbox

      Spin up Red Hat's products and technologies without setup or configuration.

    • Interactive labs

      Learn by doing in these hands-on, browser-based experiences.

    • Interactive demos

      Click through product features in these guided tours.

  • Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics
  • Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
Build
  • Get started

    • Red Hat build of Podman Desktop

      A downloadable, local development hub to experiment with our products and builds.

    • Developer Sandbox

      Spin up Red Hat's products and technologies without setup or configuration.

  • Download products

    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products
  • Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset
  • References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
Community
  • Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions
  • Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github
  • Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

Join the Red Hat Developer program

Download Red Hat products and project builds, access support documentation, learning content, and more.

ConsoleDocsSupport Search
New For you

Recommended

We'll recommend resources you may like as you browse. Try these suggestions for now.

  • Product downloads
  • Cheat sheets
  • Red Hat Developer learning portal
  • Developer blog
  • E-books
  • Developer Sandbox
Log in

Get more with a Red Hat Developer account

  • Product downloads
  • Console access
  • Event registration
  • Training & trials
Explore more account benefitsLog in or register

A subscription may be required for some services.

Contact us

How to deploy an image mode update in offline and air-gapped environments

August 13, 2025
Armando Ortiz
Related topics:
Linux
Related products:
Image mode for Red Hat Enterprise LinuxRed Hat Enterprise Linux

    The usual workflow for deploying image mode updates onto a host machine is dependent upon a network connection to access a registry and to obtain updates. However, for reasons involving security, location, or even hardware limitations, a system might end up needing an update when remote access isn't possible. Fortunately, image mode for Red Hat Enterprise Linux is flexible enough to maintain and update when deployed online, offline, and in air-gapped environments.

    Prerequisites

    For this article, I prepared my updates on a system running Fedora Workstation 42, and deployed the update to hardware running Red Hat Enterprise Linux 10 (RHEL). However, as long as you're able to create containers and have a system that supports image mode updates, the exact setup isn't important. 

    Here are the requirements for this workflow:

    • Podman
    • Skopeo
    • Access to a registry or a locally stored container
    • An external storage device for the container requiring an update 

    Benefits and disadvantages

    The method I demonstrate here is based on deploying updates on a device by device basis. While this is a perfectly functional method, it’s not ideal for all situations.

    Benefits

    • The machine you’re updating is able to be fully offline and airgapped

    Disadvantages

    • Can be a time consuming process when used across many devices
    • Requires someone on site capable of deploying the update

    If your system is capable of being online, then this approach is not the best option for you. Remote repositories are a great way to deploy updates to a system, and it doesn't require as much setup as this method does. If your situation doesn't match the benefits of this method, and you do have access to remote registries, read How to build, deploy, and manage image mode for RHEL to learn more about managing those systems.

    An overview of the process from start to finish:

    1. Prepare an external storage device on an online system
    2. Copy the image containing the updates you want to distribute to external storage
    3. Use the external storage device to apply updates to your offline system

    Prepare an external storage device on an online system

    One of the challenges of an offline update is obtaining the container you wish to use as the source of the update. In most cases, a container would be made on another system where testing can be done, and then distributed remotely for deployment. However, because this workflow assumes no internet or wireless connection, everything must be done with external storage devices rather than remote registries.

    Before you plug an external storage device into your online system, get a report about what storage devices are already connected to your system. Currently, you only care about the NAME column:  

    $ lsblk
    NAME          MAJ:MIN     SIZE   RO TYPE  MOUNTPOINTS
    zram0           251:0       8G    0 disk  [SWAP]
    nvme0n1         259:0   476.9G    0 disk  
    ├─nvme0n1p1    259:1     600M    0 part  /boot/efi
    ├─nvme0n1p2    259:2       1G    0 part  /boot
    └─nvme0n1p3    259:3   475.4G    0 part  

    Now plug in your external storage and run the same command. You can compare these two outputs to ensure that you know what your system calls your external storage device. In my case, the USB drive being used is named sda, and it has a partition called sda1.

    $ lsblk
    NAME        MAJ:MIN   SIZE   RO TYPE  MOUNTPOINTS
    sda             8:0   28.9G    0 disk  
    └─sda1         8:1   28.9G    0 part 
    zram0         251:0      8G    0 disk  [SWAP]
    nvme0n1       259:0  476.9G    0 disk  
    ├─nvme0n1p1  259:1    600M    0 part  /boot/efi
    ├─nvme0n1p2  259:2      1G    0 part  /boot
    └─nvme0n1p3  259:3  475.4G    0 part  

    The MOUNTPOINTS column lists the mount points of the partitions on your external storage. If your system mounts external storage automatically, then valid mount points already exist. However, if there are no mount points (as in my example), then you must mount it yourself before you can store anything on the device.

    Start with an empty directory. You can either create one, or use an existing empty directory that already exists for this purpose:

    $ sudo mkdir /mnt/usb/

    Once you've got an empty directory, you can mount your device partition. The mount command doesn't normally provide confirmation (only an error generates output). You can verify success by checking the mount point again (I've truncated the output for brevity):

    $ sudo mount /dev/sda1 /mnt/usb
    $ lsblk
    NAME         MAJ:MIN    SIZE   RO TYPE  MOUNTPOINTS
    sda              8:0   28.9G    0 disk  
    └─sda1          8:1   28.9G    0 part  /mnt/usb
    [...]

    Your external storage device is now ready for copying files onto it.

    Transfer an image to external storage

    You can now copy the container to your mounted device. For a container you've got stored locally, use the skopeo command (adapt the paths and names of the container for your own environment): 

    $ sudo skopeo copy --preserve-digests --all \
    containers-storage:localhost/rhel-container:latest \
    oci://mnt/usb/

    For a container stored on a remote registry:

    $ sudo skopeo copy --preserve-digests --all \
    example://quay.io/example:latest \
    oci://mnt/usb/

    Depending on the size of the container, these commands might take a few minutes to complete. Once the container has been copied, unmount and eject the external storage:

    $ sudo umount /dev/sda1
    $ sudo eject /dev/sda1

    Update the container on an offline system

    To apply the update, first plug the external storage device into your offline system. This might not be mounted automatically, so use the mkdir and mount commands as needed to locate the external storage and then mount it.

    For the sake of stability and reusability, it's best to copy the container from the external device over to the offline system's local container registry. Copy the container to the offline machine's local container storage:

    $ skopeo copy --preserve-digests --all \
    oci://var/mnt/usb \
    containers-storage:rhel-update:latest

    In this case, the mount point of the external storage is the path entered to the oci section, while the containers-storage section varies depending on the name and tag you wish the container to have. Use Podman to verify that your container is now local:

    $ podman images
    REPOSITORY			        TAG     IMAGE ID  CREATED  SIZE
    example.io/library/rhel-update   latest  cdb6d...  1 min    1.48 GB

    Deploy the update using bootc:

    $ bootc switch --transport containers-storage \
    example.io/library/rhel-update:latest

    If you weren't able to copy your container to local storage, then you must use the oci transport and the path to your storage device instead:

    $ bootc switch --transport oci /var/mnt/usb

    While it might seem to make more sense to use bootc upgrade, it's the --transport flag in bootc switch that enables you to specify an alternative source for the container. By default, bootc would attempt to pull from a registry because the bootc image builder used a registry to build the original image. There is no way to specify where an update is located when using bootc upgrade. By using bootc switch and specifying that you're using local container storage, this enables you to not only remove the requirement of a remote registry, but also to deploy updates by using  this local container in the future.

    After you’ve done this once, you can now successfully use bootc upgrade, as long as your local container and the update share the same location. If you want to switch to updates on a remote repository in the future, then you’d have to use bootc switch again. To ensure that the update was properly deployed, use the command bootc status:

    $ bootc status
    Staged image: containers-storage:example.io/library/rhel-update:latest
      Digest: sha256: 05b1dfa791...
      Version: 10.0 (2025-07-07 18:33:19.380715153 UTC)
    Booted Image: localhost/rhel-intel:base
      Digest: sha256: 7d6f312e09...
      Version: 10.0 (2025-06-23 15:58:12.228704562 UTC)

    The output shows your current booted image, along with any changes staged to happen. The container you used earlier is here, but note that staged changes do not occur until the next reboot. The output also confirms that updates will be pulled from your container storage.

    After a reboot, you can verify that you've booted into the correct image:

    $ bootc status
    Booted image: containers-storage:example.io/library/rhel-update:latest
    	Digest: sha256: 05b1dfa791...
    	Version: 10.0 (2025-07-07 18:33:19.380715153 UTC)
    Rollback image: localhost/rhel-intel:base
    	Digest: sha256: 7d6f312e09...
    	Version: 10.0 (2025-06-23 15:58:12.228704562 UTC)

    The Booted image is your updated image, and the Rollback image is your previous image. You've successfully performed an offline image mode update.

    If you're not using containers yet, and need help setting one up, read Image mode for Red Hat Enterprise Linux: A quick start guide. 

    Related Posts

    • How to build, deploy, and manage image mode for RHEL

    • How to create CI/CD pipelines for image mode for RHEL

    • Creating a VMDK using image mode for Red Hat Enterprise Linux

    • Image mode for RHEL: 4 key use cases for streamlining your OS

    • Containerizing workloads on image mode for RHEL

    • How image mode for RHEL simplifies software appliances

    Recent Posts

    • A day in the life of an NVIDIA H100 on Red Hat OpenShift 5

    • Migrate BuildConfigs to builds for Red Hat OpenShift with one plug-in install

    • Run Red Hat Enterprise Linux CoreOS on NVIDIA BlueField DPUs

    • Agent harness engineering: Separating model capabilities from enforcement

    • What's new for developers in Red Hat Enterprise Linux 10.3 and 9.9

    What’s up next?

    Use Podman Desktop to create a bootable Flask-based application using image mode for RHEL. We will integrate Flask, Gunicorn, and NGINX into a bootable container.

    Start the activity
    Red Hat Developers logo

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    Red Hat Developer

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility
    Ask AI