Page
Build a sample Node.js and React application in a bootable container
In this lesson, we will package the application and the Red Hat Enterprise Linux 10 operating system into one unit. We will use systemd to manage the Node.js process and firewalld to restrict port access to the system as a best practice for security.
Prerequisites:
- Complete Lesson 1: Access the Red Hat Container Registry.
- Complete Lesson 2: Build the Node.js and React application.
- A basic understanding of how to traverse a Linux file system.
- An understanding of how to create and edit Linux text files.
- Podman Desktop installed.
In this lesson, you will:
- Create a systemd unit file to start your application at boot time.
- Create a
Containerfileto install the necessary components and configure a bootable container. - Build a container image.
- Build a bootable image.
Step 1: Create a systemd unit file for your application
Before we package everything up to deploy our application as a VM, you’ll need a systemd unit file, which automatically starts your application. We’ll now implement the hello-node.service file. Once system networking begins, this file will start our application.
Create a hello-node.service file from your native desktop, nodejs-dev/bootc/app/hello-node.service or directly in the container, /app/hello-node.service with the following content:
[Unit]
Description=Node.js 24 App
After=network-online.target
[Service]
ExecStart=/usr/bin/node /app/server.js
WorkingDirectory=/app
Restart=on-failure
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetStep 2: Create the production Containerfile to install the components and configure a bootable container
From your native desktop environment, create the file nodejs-dev/bootc/Containerfile. Note that this is not the same as the node-js-dev/Containerfile you used to develop your application. The contents of the new file are as follows:
FROM registry.redhat.io/rhel10/rhel-bootc:latest
RUN dnf install -y nodejs24 firewalld && dnf clean all
# Set Node.js 24 as default using alternatives
RUN alternatives --install /usr/bin/node node /usr/bin/node-24 24
# Open port 8080 in the RHEL firewall
RUN firewall-offline-cmd --add-port=8080/tcp
WORKDIR /app
COPY app/dist/ ./dist/
COPY app/server.js app/package.json ./
RUN /usr/bin/npm-24 install --omit=dev
COPY app/hello-node.service /etc/systemd/system/
RUN systemctl enable hello-node.service firewalldNow that you have your configuration files, let’s create the bootable RHEL image mode container.
Step 3: Build the container image
In Lesson 1, we installed the Red Hat build of Podman Desktop, which includes the Bootable Containers extension used for image mode deployments.
To pull your first bootable container, follow these steps.
In Podman Desktop, select Bootable Containers from the side menu bar to access the Dashboard section (Figure 1).

Figure 1: Welcome to Bootable Containers dashboard screen. - Within the Bootable Containers section, select Images from the left navigation.
On the Images screen, select the option to pull the example container image from registry.gitlab.com (Figure 2).
When you complete this, you will see the example image listed.

Figure 2: Bootable containers images listing screen with the example image now available.
Note
The file size of the image is over 700MB (compressed) and may take a while to download.
Build an image from the Containerfile
Next, let’s use the Containerfile we created in Lesson 3 to build an image.
- Open Podman Desktop on your local machine and go to the Images section in the left navigation.
- Select Build to open the Build image from the Containerfile screen.
- Provide the following:
- Containerfile path:
your_home_directory/nodejs-dev/bootc/Containerfile - Build directory path:
your_home_directory/nodejs-dev/bootc - Image name:
nodejs-dev-bootc-image Platform hardware spec: I chose the Intel and AMD x86_64 image option for my desktop environment (Figure 3).

Figure 3: The Build image from Containerfile screen in Podman Desktop.
- Containerfile path:
Select Build once you have entered the information. Observe if any issues or warnings are displayed as you build the image.
Once you’ve successfully created the image (Figure 4), it will be listed on the Images dashboard (Figure 5).

Figure 4: Successful Containerfile build output in Podman Desktop. 
Figure 5: The container images listing screen with a new entry for the example image.
At this point, our image can run like any other container with Podman. This can be highly beneficial for basic testing and iterating on your application. In the next step, you will install, or write, your container image as a disk image and run it as a Linux system.
Step 4: Build the bootable image
While a traditional application container image is like a self-contained software package that you install onto an existing OS, image mode uses bootc to deliver a complete, bootable OS installation disk, but managed and versioned like a container image. The magic of bootc is that it can install the contents of the container image to disk or file system and provide any format you need to run on virtually any platform. Podman Desktop makes this process simple because you can target a wide variety of platforms and image types.
To build an image in Podman Desktop:
- Open Podman Desktop on your local machine and go to the Images section from the left navigation. If you just completed the prior steps, you will already be on this screen.
Select the option to Build Disk Image from the Actions menu (Figure 6).

Figure 6: The Podman Desktop container images screen with the expanded menu under the actions kebab. Figure 6: The Podman Desktop container images screen with the expanded menu under the actions menu. - Select Build on the Disk Images screen.
Provide the configuration details. For this exercise, we chose Virtualization Guest Image (qcow2) as the image type and a default filesystem (Figure 7).

Figure 7: The completed Build Disk Image configuration. Expand the Interactive build config section towards the bottom of the screen. This is where you will enter the SSH credentials that you need for the next section (Figure 8).

Figure 8: The expanded interactive build config section for building a disk image in Podman Desktop. - Select Build.
Observe if any issues or warnings are displayed as the disk image builds. Once you’ve successfully created the image, you will see a success message (Figure 9) listed in the Bootable Containers > Disk Images section of Podman Desktop.

Figure 9: A successful disk image build.
Set up a virtual machine
Virtual environments provide a quick and convenient way to test your images. You can test modifications and configurations without impacting your primary operating system or incurring cloud expenditures. Once your image has been validated and you’re happy with it, we encourage you to create images for all the platforms you’d like to target.
Podman Desktop version 1.8.0 and later makes it easy to launch your built disk image as a virtual machine. After successfully building your disk image, simply select Virtual Machine (Experimental). Before doing so, please ensure you've met the necessary prerequisites, which may include specific hardware or software requirements.
Summary
This learning path demonstrates how easy it is to add the Red Hat SSO extension to Podman Desktop and access the Red Hat registry to create a Node.js and React application container image that is ready to boot and run with image mode. You can easily extend the rudimentary bootable application container you created into a functional application.
As a developer, there are several reasons why you should care about deploying the application in image mode:
- Full stack reproducibility: Image mode allows you to define your app, user space, and the entire OS, ensuring consistency from development to production.
- Simplified OS management: You can now treat OS updates and configurations as image rebuilds, integrating them into your existing container workflows.
- Ideal for appliances and edge: Image mode is perfect for creating specialized software appliances or consistent OS environments for edge devices with tightly coupled OS and application.
- Testing: With image mode it is easy to spin up VMs on your desktop or in the cloud, running the exact OS and application build for testing.
The next steps you could take in completing your application might include the following:
- Extend the application code beyond the prototype, Hello World.
- Integrate the application with a database, such as SQLLite, MariaDB, MySQL, and PostgreSQL.
- Configure keys and infrastructure to improve the security of the Node.js built-in webserver components.