Breadcrumb

  1. Red Hat Interactive Learning Portal
  2. Red Hat Enterprise Linux learning
  3. Build a hardened LAMP stack and deploy it in image mode for Red Hat Enterprise Linux
  4. Use Podman Quadlets to manage containers as system services

Build a hardened LAMP stack and deploy it in image mode for Red Hat Enterprise Linux

Build a LAMP stack application on Red Hat Enterprise Linux 10 using hardened images and bootc to turn containers into a bootable, verified virtual machine.

Quadlets are a specific type of configuration file that Podman uses to automatically create systemd service files. Instead of writing complex scripts to manage container lifecycles, you write a .container file that functions like a standard Red Hat Enterprise Linux configuration file. You will also configure the AutoUpdate setting so the containers can update automatically without requiring an operating system (OS) reboot.

Prerequisites:

In this lesson, you will:

  • Configure the network, storage, and MariaDB container Quadlets.
  • Configure the PHP-FPM container.
  • Configure the Apache HTTP server container as a web proxy.

Use Podman Quadlets to manage containers as system services 

Before you configure Quadlets to manage your containers as system services through systemd, first create the directory lampdev-hardened/quadlets where you will keep your Quadlet configuration files:

mkdir lampdev-hardened/quadlets

Step 1: Configure the network Quadlet

In this first step, you create a dedicated virtual bridge so your containers can talk to each other by name (e.g., mariadb) rather than IP addresses.  Place the following in the file lampdev-hardened/quadlets/lamp.network:

[Network]
# No extra config needed; this creates a basic bridge for our stack.

Step 2: Configure the storage Quadlet

This step ensures your data survives a reboot or an OS update. Create the file lampdev-hardened/quadlets/mariadb-data.volume with the following contents:

[Volume]
# This defines a persistent location for our database files.

Step 3: Configure the MariaDB container Quadlet

The following Quadlet runs your database. Note the Before= line. The directive ensures the database is ready before the application starts. Before= does NOT wait for the service to be "ready" (healthy); it only ensures the order of the start commands.  Place the following contents in the file lampdev-hardened/quadlets/mariadb.container:

[Unit]
Description=MariaDB database server (Red Hat Hardened Image)
Requires=lamp-secrets.service
After=lamp-secrets.service
Before=php-fpm.service

[Container]
Image=registry.access.redhat.com/hi/mariadb:latest
ContainerName=mariadb
Network=lamp.network
PublishPort=3306:3306
Secret=mariadb_root_password,type=env,target=MARIADB_ROOT_PASSWORD
Secret=mariadb_app_password,type=env,target=MARIADB_PASSWORD
Environment=MARIADB_USER=appuser
Environment=MARIADB_DATABASE=hellodb
Volume=mariadb-data.volume:/var/lib/mysql:Z

# Enable independent updates without a full OS reboot
AutoUpdate=registry

[Service]
Restart=always

[Install]
WantedBy=multi-user.target default.target

Step 4: Configure the PHP-FPM container

This runs the logic you wrote in the previous lesson. It waits for the database to be up before it starts. Place this content in the file lampdev-hardened/quadlets/php-fpm.container:

[Unit]
Description=PHP-FPM application server (Red Hat Hardened Image)
Requires=mariadb.service lamp-secrets.service
After=mariadb.service lamp-secrets.service
Before=httpd.service

[Container]
Image=registry.access.redhat.com/hi/php:latest-fpm
ContainerName=php-fpm
Network=lamp.network
Environment=DB_HOST=mariadb
Environment=DB_USER=appuser
Secret=mariadb_app_password,type=env,target=DB_PASS
Environment=DB_NAME=hellodb
Volume=/srv/www:/var/www/html:z

# Enable independent updates without a full OS reboot
AutoUpdate=registry

[Service]
Restart=always

[Install]
WantedBy=multi-user.target default.target

Step 5: Configure the Apache HTTP server container as a web proxy

This configures only what is needed to serve traffic and proxy to PHP. Place the following content in the file lampdev-hardened/quadlets/httpd.container:

[Unit]
Description=Apache httpd reverse proxy (Red Hat Hardened Image)
Requires=php-fpm.service
After=php-fpm.service

[Container]
Image=registry.access.redhat.com/hi/httpd:latest
ContainerName=httpd
Network=lamp.network
PublishPort=8080:8080
Volume=/srv/www:/var/www/html:z,ro
Volume=/etc/httpd/conf.d/proxy-php.conf:/etc/httpd/conf.d/proxy-php.conf:Z,ro

# Enable independent updates without a full OS reboot
AutoUpdate=registry

[Service]
Restart=always

[Install]
WantedBy=multi-user.target default.target

Step 6: Test and verify 

Before deploying the Quadlets into a permanent Red Hat Enterprise Linux image, you must verify the syntax. Podman includes a tool that simulates the conversion from a Quadlet file to a standard systemd service.

Open your terminal in the folder where you saved your .container.network, and .volume files. Run the following command:

QUADLET_UNIT_DIRS=$(pwd) /usr/libexec/podman/quadlet -dryrun

The tool will output configuration text. Look for the ExecStart lines. If you see ExecStart=/usr/bin/podman run ..., Podman successfully processed your request. It mapped your volumes, networks, and environment variables into a format Red Hat Enterprise Linux uses during boot. If the output is empty or shows an error, a path is likely incorrect or a bracket is missing. 

Success! You’ve configured the Podman Quadlets to tell the operating system how to manage your containers. Next, you will package the application and operating system into a verified image. 

Previous resource
Create and run a LAMP application locally
Next resource
Package the application and operating system into a verified image