How to Set Up an Air-Gapped offline YUM Repository for RedHat-Based Systems

David (Dudu) Zbeda
21 min readDec 20, 2024

--

Introduction

Calling all DevOps engineers, IT administrators, Linux enthusiasts, and tech aficionados!
Have you ever faced the challenge of managing software installations in an air-gapped or isolated environment? Whether you’re working in a highly secure on-premises setup or tackling operational constraints, one common hurdle is creating a reliable offline YUM repository for RedHat-based distributions.

In disconnected environments, having an offline repository isn’t just convenient — it’s essential. It allows you to:

  • Operate securely in air-gapped environments.
  • Control software availability by offering only pre-approved packages.

As always, I aim to turn real-world challenges into actionable solutions. Today, I’m sharing a comprehensive guide to creating an offline YUM repository for RedHat distributions.

Why an Offline YUM Repository?

Air-gapped or on-premises environments isolate systems from the internet to enhance security or meet operational requirements. In such setups, software updates and installations often become bottlenecks. An offline YUM repository addresses this by enabling you to:

  • Maintain secure operations without direct internet access.
  • Provide curated, pre-approved software packages to your servers.

The solution is straightforward: a local YUM repository tailored for disconnected environments. This guide will walk you through setting it up with ease.

What to Expect from This Guide

This solution is designed for RedHat 8.10 and Rocky 8.10 distributions, but it can be adapted to support other versions — I have included the steps in the troubleshooting section below. Before diving in, here are some key considerations:

A Red Hat Enterprise Linux (RHEL) system requires a valid license to:

  • Access Red Hat’s support services.
  • Register the system with Red Hat’s online repositories to download and install packages.

While it’s possible to install packages on an unregistered Red Hat server using an offline repository, ensure this approach aligns with Red Hat’s terms of service. Please consult your legal team, spouse, or even that uncle who always seems to know everything before proceeding.

What You’ll Learn

In this blog, I’ll provide Ansible playbooks to help you effortlessly set up an offline YUM repository server for both RedHat 8.10 and Rocky 8.10. These playbooks will streamline the process, making setup smooth and manageable.

Flow

Blog Goals

In this blog, I’ll guide you through the step-by-step process of setting up an offline YUM repository server with customized packages. This setup will enable the project client servers to securely connect to the offline repository and seamlessly install the packages required for your project.

To simplify and automate the process, we’ll use Ansible playbooks. I’ll provide detailed explanations and in-line comments to help you understand each step.

Here’s what we’ll cover:

  1. Register the RedHat Server and Configure Online Repositories

This step is relevant only if your offline repository server runs on RedHat 8.10.

  • We’ll begin by registering the RedHat server and enabling the official Red Hat repositories (BaseOS and AppStream).
  • Note: You’ll need a valid RedHat subscription (username and password) to complete this step.

2. Download Required RPM Packages

Identify and download the RPM packages necessary to:

  • Set up and manage the offline repository server.
  • Install packages on client servers in your environment.

This process will be performed on a server connected to the internet.

3. Configure Environment Inputs

To streamline tasks with Ansible, we’ll set up two critical configuration files:

  • Inventory File: Specifies the repository server’s IP and lists all client servers in your environment, guiding Ansible on where to execute tasks.
  • Environment Input File: Contains environment-specific configurations, offering flexibility to adapt the setup for different requirements.

4. Deploy the Offline Repository Server

Using an Ansible playbook, we’ll:

  • Copy the packages to the YUM repository server
  • Configure the repository on the server.
  • Generate a secure SSL certificate for the repository to ensure all client servers connect securely.

Important Note:
The YUM repository can be set up on either a Rocky or RedHat OS, and it can serve a mix of client servers running both Rocky and RedHat. However, when downloading project-specific packages (e.g., tmux), ensure that the package is downloaded separately on both Rocky and RedHat systems. This ensures all necessary dependencies are included for the corresponding client operating systems.

5. Configure the Repository on Client Servers and Distribute the Certificate

With another Ansible playbook, we’ll:

  • Set up client servers to connect to the offline repository.
  • Distribute the repository server’s public SSL certificate to all client servers, ensuring secure communication.

6. Package Installation

We’ll validate the setup by installing yor project packages (e.g: nginx , tmux) via the offline repository.

7. Upgrades and Updates

We’ll ensure the solution supports:

  • Updating the offline repository server when new packages are added.
  • Regenerating and redistributing SSL certificates to client servers as needed.

8. Extras

Lastly, I’ll share some useful commands to help you test and troubleshoot your setup effectively and some reference Links

Understanding YUM, DNF, and Securing Your Repository

Yum vs. Dnf

With the release of RHEL 8, DNF replaced YUM as the default package manager. DNF offers several enhancements, including:

  • Faster performance and improved dependency resolution.
  • Better plugin support for extensibility.
  • Better dependency handling.
  • Modular content management, allowing you to select specific package versions.

The yum command remains available for backward compatibility but acts as a link to DNF. For example:

# Backward-compatible
yum install nginx
# Recommended
dnf install nginx

While YUM commands still work, they may be deprecated in future RHEL releases. Adopting DNF ensures compatibility with the latest features and best practices.

Secure Repository Setup

When configuring a secure repository, two primary methods can be employed to ensure security:

  1. HTTPS: Encrypts the connection between the client and the repository server, preventing interception or tampering during file transfers.
  2. GPG Keys: Validate the authenticity and integrity of packages by verifying their cryptographic signatures.

In air-gapped, offline environments, where you control the RPMs and repository setup, HTTPS is generally sufficient because:

  • The environment is isolated, mitigating the risk of external tampering.
  • The RPMs are sourced and managed by you, reducing the necessity for additional GPG verification.

Using HTTPS in such controlled environments ensures secure communication while keeping configuration simple, without sacrificing security.

Prerequisites and Ingredients

Before diving into the steps, ensure you have the following components and requirements ready:

  1. Internet server

This server will be used to download the required packages from online repositories. You can choose RedHat or Rocky distribution

Requirements (RedHat-based YUM Repository):

  • A valid RedHat license for registration.
  • RedHat 8.10 operating system installed.
  • Internet connection (required during registration and package download phases).

Requirements (Rocky-based YUM Repository):

  • Rocky 8.10 operating system installed.
  • Internet connection (required during registration and package download phases).

2. YUM repository server

This server will host the offline repository.

Requirements:

  • RedHat 8.10 or Rocky 8.10 operating system installed.
    Note: Regardless of the operating system installed, the YUM repository server can seamlessly serve both RedHat and Rocky Linux systems.
  • Private network connection (no internet access required)
  • IP address: For this exercise, the YUM repository server’s IP is 10.100.102.31
  • A user with Sudo privileges and a password set up

Note: For Ansible to function properly, all environment servers must be configured with the same username and password.

3. Client-server(s)

These servers will consume packages from the offline YUM repository.

Requirements:

  • RedHat 8.10 or Rocky 8.10 operating system installed.
  • Private network connection (no internet access required)
  • IP Address: For this exercise,
    Client Rocky server IP is 10.100.102.35
    Client RedHat server IP is 10.100.102.36
  • A user with sudo privileges and a password set up

Note: For Ansible to function properly, all environment servers must be configured with the same username and password.

4. Ansible application

Ansible will automate the setup and configuration tasks.

Requirements:

  • Can be installed on any Linux distribution (e.g., Ubuntu, Red Hat).
  • For this exercise, I’m using WSL (Windows Subsystem for Linux) on my Windows machine.
  • Private network access to the YUM repository server and client servers.
  • SSH access to all environment servers.
  • All environment servers defined with the same user and password.

For details on installing WSL with Ansible, check out my LinkedIn post:
👉 WSL2: Seamlessly Install Ubuntu OS, Docker, and Ansible

5. Ansible playbooks

Download the required Ansible playbooks from my GitHub repository:

👉 GitHub Repository: yum-offline-repository

Files needed:

  • inventory-file.yml
  • project-inputs.yml
  • redhat-deploy-offline-repository.yml
  • rocky-deploy-offline-repository.yml
  • update-repo-list-on-client-servers.yml
  • distribute-repository-server-certificate.yml
  • download-project-packages.sh
  • redhat-download-mandatory-packages.sh
  • rocky-download-mandatory-packages.sh

With all the prerequisites in place, let’s get started! 🚀

Let's start to play

Internet server:

RedHat Registration

Note: This step is required only if both the Internet server and the YUM offline repository server are based on RedHat. If your setup uses Rocky Linux or another operating system, skip this step.

To register your RedHat server and download the required packages, follow these steps:

Register your server

  1. Connect to the Internet server running RedHat 8.10
  2. Run the following command to register the server with your RedHat subscription: sudo subscription-manager register
  • Enter your RedHat username and password when prompted.

3. Verify the registration by ensuring you see response message like “the system has been registered …”

Redhat Registration conformation

Enable repository
Note: The process might change based on your registration packages

Enable repository — Option 1

1. Enable the necessary repositories by executing the following commands:

sudo subscription-manager repos --enable=rhel-8-for-x86_64-baseos-rpms
sudo subscription-manager repos --enable=rhel-8-for-x86_64-appstream-rpms
sudo subscription-manager repos --enable=codeready-builder-for-rhel-8-x86_64-rpms
sudo subscription-manager attach --auto
sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
  • Verify the enabled repositories by executing the command:
 sudo subscription-manager repos --list-enabled
  • Refresh the YUM cache metadata by executing the commands:
sudo yum clean all
sudo yum makecache

Enable repository — Option 2

  1. Check the repositories that are available under your subscription by executing the command
subscription-manager repos --list

2. Enable repo by executing the command

subscription-manager repos --enable=<repository-id>

Internet server:

Download essential packages

To create an offline repository, you need to download essential packages. Follow these steps:

  1. Create a directory to store the downloaded packages by executing the command: mkdir -p /data/repo-mandatory-packages

2. Depending on your operating system, create or download the appropriate script:

  • If your Internet server is running Rocky 8.10, use: rocky-download-mandatory-packages.sh
  • If your Internet server is running RedHat 8.10, use: redhat-download-mandatory-packages.sh

👉 GitHub Repository: yum-offline-repository

  • File location: ./package-download-script/rocky-download-mandatory-packages.sh
  • File location: ./package-download-script/redhat-download-mandatory-packages.sh

Rocky Script (rocky-download-mandatory-packages.sh):

#!/usr/bin/env bash
set -euo pipefail

# Define the directory where the packages and their dependencies will be downloaded.
DOWNLOAD_DIR="/data/repo-mandatory-packages"
mkdir -p "$DOWNLOAD_DIR"

# List of specific packages to download, including their exact versions (in NEVRA format).
PACKAGES=(
"drpm-0.4.1-3.el8.x86_64"
"createrepo_c-libs-0.17.7-6.el8.x86_64"
"createrepo_c-0.17.7-6.el8.x86_64"
"apr-1.6.3-12.el8.x86_64"
"apr-util-1.6.1-9.el8.x86_64"
"httpd-2.4.37-65.module+el8.10.0+1842+4a9649e8.2"
"httpd-filesystem-2.4.37-65.module+el8.10.0+1842+4a9649e8.2.noarch"
"httpd-tools-2.4.37-65.module+el8.10.0+1842+4a9649e8.2.x86_64"
"mod_http2-1.15.7-10.module+el8.10.0+1883+38ed6c58.1.x86_64"
"mod_ssl-1:2.4.37-65.module+el8.10.0+1842+4a9649e8.2.x86_64"
)

# Notify the user that the download process is starting.
echo "Downloading specified packages and their dependencies to $DOWNLOAD_DIR..."

# Iterate over the list of packages and download each one along with its dependencies.
for pkg in "${PACKAGES[@]}"; do
echo "Downloading $pkg and dependencies..."
dnf download --resolve --destdir="$DOWNLOAD_DIR" "$pkg"
done

# Confirm that the download process has completed.
echo "All specified packages and their dependencies have been downloaded to $DOWNLOAD_DIR."

Redhat Script (redhat-download-mandatory-packages.sh):

#!/usr/bin/env bash
set -euo pipefail

# Define the directory where the packages and their dependencies will be downloaded.
DOWNLOAD_DIR="/data/repo-mandatory-packages"
mkdir -p "$DOWNLOAD_DIR"

# List of specific packages to download, including their exact versions (in NEVRA format).
PACKAGES=(
"drpm-0.4.1-3.el8.x86_64"
"createrepo_c-libs-0.17.7-6.el8.x86_64"
"createrepo_c-0.17.7-6.el8.x86_64"
"apr-1.6.3-12.el8.x86_64"
"apr-util-1.6.1-9.el8.x86_64"
"httpd-2.4.37-65.module+el8.10.0+22196+d82931da.2.x86_64"
"httpd-filesystem-2.4.37-65.module+el8.10.0+22196+d82931da.2.noarch"
"httpd-tools-2.4.37-65.module+el8.10.0+22196+d82931da.2.x86_64"
"mod_http2-1.15.7-10.module+el8.10.0+21653+eaff63f0.x86_64"
"redhat-logos-httpd-84.5-2.el8.noarch"
"mod_ssl-2.4.37-65.module+el8.10.0+22196+d82931da.2.x86_64"
)

# Notify the user that the download process is starting.
echo "Downloading specified packages and their dependencies to $DOWNLOAD_DIR..."

# Iterate over the list of packages and download each one along with its dependencies.
for pkg in "${PACKAGES[@]}"; do
echo "Downloading $pkg and dependencies..."
dnf download --resolve --destdir="$DOWNLOAD_DIR" "$pkg"
done

# Confirm that the download process has completed.
echo "All specified packages and their dependencies have been downloaded to $DOWNLOAD_DIR."

3. Enable script execution by executing the command:
chmod 777 rocky-download-mandatory-packages.sh
or
chmod 777 redhat-download-mandatory-packages.sh

4. Execute the appropriate script based on your operating system by executing the command:
./rocky-download-mandatory-packages.sh
or
./redhat-download-mandatory-packages.sh

5. Verify that the packages were downloaded to the folder by executing the command: ls /data/repo-mandatory-packages

Maintenance Server — Mandatory packages

Internet server:

Download project packages

You’ll also need to download packages required for your project, such as: nginx, nmap, and tmux.
Note: If you wish to serve both RedHat and Rocky Linux from the same YUM repository, you will need two internet servers:

  • One based on RedHat.
  • One based on Rocky Linux.

Run the download-project-packages.sh script on each server separately, as package dependencies differ between the two operating systems.

  1. Create a directory for project-specific packages by executing the command: mkdir -p /data/repo-project-packages

2. Create or download the script download-project-packages.sh from the GitHub repository:

Download project packages Script (download-project-packages.sh):

#!/usr/bin/env bash
set -euo pipefail

# Define the directory where the packages and their dependencies will be downloaded.
DOWNLOAD_DIR="/data/repo-project-packages"
mkdir -p "$DOWNLOAD_DIR"

# List of specific packages to download, including their exact versions (in NEVRA format).
PACKAGES=(
"tmux.x86_64"
"nginx.x86_64"
"nmap.x86_64"
)

# Notify the user that the download process is starting.
echo "Downloading the latest x86_64 packages (and noarch where specified) and their dependencies to $DOWNLOAD_DIR..."

# Iterate over the list of packages and download each one along with its dependencies.
for pkg in "${PACKAGES[@]}"; do
echo "Downloading $pkg and dependencies..."
dnf download --resolve --destdir="$DOWNLOAD_DIR" "$pkg"
done

# Confirm that the download process has completed.
echo "All specified x86_64 (and noarch) packages and their dependencies have been downloaded to $DOWNLOAD_DIR."

3. Enable script execution by executing the command: chmod 777 download-project-packages.sh

4. Execute the script by executing the command: ./download-project-packages.sh

5. Verify that the packages were downloaded to the folder by executing the command: ls /data/repo-project-packages

Maintenance Server — Project packages

Ansible server:

preparation

To execute the Ansible playbook, we need to have Ansible installed on any Linux distribution.

  1. Verify that ansible is installed by executing the command: ansible — — version and confirm output
  2. Confirm that the output displays the installed version of Ansible.
Verify Ansible is installed

3. Create a project directory by executing the command: mkdir -p /projects/offline-repo , You can define a different path if needed

4. Ensure the Ansible server can SSH into all environment servers.

Ansible server:

Move package from the internet server

At this stage, let’s assume all our servers are operating in an air-gapped environment, with no network connection to the Internet.

To maintain security and avoid direct connections between the Ansible server and the Internet server, we’ll need to manually copy the repo-mandatory-packages and the repo-project-packages folders from the Internet server to the Ansible server under the project directory.

This can be done using a portable storage device—or, for the nostalgic among us, even a CD-ROM if you prefer! 😊

  1. Copy the repo-mandatory-packages and the repo-project-packages folder from the internet server to your Ansible server under the project folder /projects/offline-repo

Ansible server:

Copy project files

Copy the following files from the GitHub repository to your project folder:

  • inventory-file.yml
  • project-inputs.yml
  • redhat-deploy-offline-repository.yml
  • rocky-deploy-offline-repository.yml
  • update-repo-list-on-client-servers.yml
  • distribute-repository-server-certificate.yml

👉 GitHub Repository: yum-offline-repository

  • File location: ./ansible/*
project playbooks

Ansible server:

Update inventory file

In Ansible, you need to specify which tasks run on which servers. This is achieved using an inventory file, where you define host groups and associate them with the relevant IPs for each group.

In this setup, the inventory file includes the following groups:

  • [repository-server]: The server hosting the offline repository.
  • [redhat-client]: The RedHat client servers that will connect to the offline repository.
  • [rocky-client]: The Rocky Linux client servers that will connect to the offline repository.
  1. You can create or download the inventory-file.yml from the GitHub repository:
    👉 GitHub Repository: yum-offline-repository
  2. Modify the file to include the IP addresses of your servers under the appropriate groups.

inventory-file.yml

[repository-server]
10.100.102.31

[redhat-client]
10.100.102.36

[rocky-client]
10.100.102.35
  • Replace 10.100.102.31, 10.100.102.36, and 10.100.102.35 with the actual IPs of your environment’s servers.

Ansible server:

Update project-inputs file

The project-inputs.yml file contains mandatory parameters that define key configurations for the offline repository setup. These parameters must be updated to reflect your project’s specific environment.

Mandatory Parameters to Update

  • yum_repository.ip; Specifies the IP address of the offline repository server. Ansible will use this parameter to update the /etc/hosts file on the client servers, mapping the IP to the repository hostname.
  • yum_repository.hostname; Specifies the hostname of the offline repository server. Ansible will use this parameter to set the hostname of the offline repository server & Add the hostname to the /etc/hosts file on the client servers.
  • source_packages_path.mandatory_packages_files_location ; Specifies the location of the mandatory packages directory on the Ansible server
  • source_packages_path.project_packages_files_location ; Specifies the location of the project-specific packages directory on the Ansible server.

All other parameters should not be changed

  1. You can create or download the project-inputs.yml from the GitHub repository:
    👉 GitHub Repository: yum-offline-repository
  2. Modify the following fields to match your project setup:
  • yum_repository.ip
  • yum_repository.hostname
  • source_packages_path.mandatory_packages_files_location
  • source_packages_path.project_packages_files_location

project-inputs.yml

### Yum Repository Configuration ###

## Define the IP address and hostname to assign to the server ##
yum_repository:
ip: 10.100.102.31
hostname: offline-repository

## Define the paths where the mandatory and project packages are located on the Ansible server ##
## In this example the path is /mnt/c becuase i'm running the ansible on my WSL machine
source_packages_path:
mandatory_packages_files_location: /mnt/c/projects/offline-repo/repo-mandatory-packages
project_packages_files_location: /mnt/c/projects/offline-repo/repo-project-packages

## Multi-Repository Support ##
## Use the following template to configure multiple repositories as needed ##
offline_repo:
yum_repository_name: offline-repo
yum_repository_address: "https://{{ yum_repository.hostname }}"
yum_repository_path: offline-repo
yum_repository_description: offline repo rpm files
yum_repository_enabled: 1
yum_repository_gpgcheck: 0

## Do Not Modify !!! ##
## Certificate Configuration ##
## This section contains the parameters required for configuring the YUM certificate ##
certificate_configuration:
server_hostname: "{{ yum_repository.hostname }}"
private_key_path: /etc/pki/tls/private/
private_key_file_name: private.key
certificate_request_path: /etc/pki/tls/certs/
certificate_request_file_name: certificate_request.csr
certificate_path: /etc/pki/tls/certs/
certificate_file_name: "{{ yum_repository.hostname }}.crt"
key_size: 4096
passphrase:
key_type: rsa
country_name: xx
state: xx
province: xx
email_address:
organization_name: "{{ yum_repository.hostname }}"
certificate_validation_period: 1000
approved_certificate_path: /etc/pki/ca-trust/source/anchors/

Ansible server:

Run deploy-offline-repository playbook

The deploy-offline-repository playbook automates the setup of the offline repository server. The playbook performs the following tasks:

  • Updates the YUM offline repository server hostname based on the parameters in the project-inputs.yml file.
  • Updates the /etc/hosts file
  • Configures SELinux settings.
  • Copies mandatory and project packages from the Ansible server to the offline repository server under /var/www/html/offline-repo
  • Installs mandatory packages.
  • Updates the HTTPd configuration.
  • Creates a self-signed certificate and a public certificate.
  • Sets up the repository based on the provided packages
  • Reboot server

Run the following steps in order to deploy the offline repository server

  1. Connect to the ansible server via ssh
  2. Navigate to your project folder by executing the command: cd /projects/offline-repo
  3. Run the playbook by executing the command:
  • If your YUM offline repository server is running Rocky 8.10,
    use: rocky-deploy-offline-repository.yml
ansible-playbook rocky-deploy-offline-repository.yml -i inventory-file.yml --user=zbeda --ask-pass --ask-become-pass
  • If your YUM offline repository server is running RedHat8.10,
    use: redhat-deploy-offline-repository.yml
ansible-playbook redhat-deploy-offline-repository.yml -i inventory-file.yml --user=zbeda --ask-pass --ask-become-pass
  • ansible-playbook: Executes an Ansible playbook.
  • deploy-offline-repository.yml: Specifies the playbook file to run.
  • -i inventory-file.yml: Points to the inventory file containing enviroment server IPs.
  • --user=zbeda: Connects to the remote hosts using the specified username (zbeda).
  • --ask-pass: Prompts for the SSH password to connect to the remote hosts.
  • --ask-become-pass: Prompts for the privilege escalation password (e.g., for sudo tasks).
Playbook execution

4. Verify that the playbook was executed successfully

Ansible Playbook successful run

Note:
If the certificate was already generated, you will be prompted to confirm whether a new certificate needs to be created. If you have not yet distributed the public certificate to the client servers, choose “1.” Otherwise, proceed to the Updates & Upgrades section below.

5. Open your browser and navigate to the offline repository server using its IP address: https://10.100.102.31

  • verify that you see a certificate warning — this is expected for self-signed certificates.
  • Ensure that the repository displays the expected packages.

Ansible server:

Run update-repo-list-on-client-servers playbook

The update-repo-list-on-client-servers playbook is used to configure client servers to connect to the offline repository. It runs on all client servers defined in the inventory-file.yml under the groups [redhat-client] and [rocky-client]. The playbook performs the following tasks:

  • Updates the /etc/hosts file on the client servers to include the offline repository server’s IP address and hostname.
  • Adds a new repository configuration file to the /etc/yum.repos.d directory on the client servers.

Run the following steps in order to configure offline repository server on the environment client server

  1. Connect to the ansible server via ssh
  2. Navigate to your project folder by executing the command: cd /projects/offline-repo
  3. Run the playbook by executing the command:
ansible-playbook update-repo-list-on-client-servers.yml -i inventory-file.yml --user=zbeda --ask-pass --ask-become-pass
  • ansible-playbook: Executes an Ansible playbook.
  • deploy-offline-repository.yml: Specifies the playbook file to run.
  • -i inventory-file.yml: Points to the inventory file containing enviroment server IPs.
  • --user=zbeda: Connects to the remote hosts using the specified username (zbeda).
  • --ask-pass: Prompts for the SSH password to connect to the remote hosts.
  • --ask-become-pass: Prompts for the privilege escalation password (e.g., for sudo tasks).

4. Verify that the playbook was executed successfully

Ansible Playbook successful run

5. Connect to one for the client servers via ssh

6. Check the /etc/hosts file to confirm that the repository server's IP and hostname were added.

6. Verify that the repository server was added with the relevant information by executing the command : sudo vi /etc/yum.repos.d/offline-repo.repo

New Repository

Ansible server:

Run distribute-repository-server-certificate playbook

The distribute-repository-server-certificate playbook is used to distribute the public certificate created during the repository server deployment. It ensures all client servers trust the repository server’s certificate, allowing secure communication with the offline repository.

This playbook runs on all client servers defined in the inventory-file.yml under the [redhat-client] and [rocky-client] groups.

The playbook performs the following tasks:

  • Connects to the repository server and copy the public certificate to the ansible server under /tmp folder
  • Copies the public certificate from the Ansible server to all client servers
  • Configures the client servers to trust the repository server’s certificate.

Run the following steps in order to distribute the public certificate of the offline repository to the client servers

  1. Connect to the ansible server via ssh
  2. Navigate to your project folder by executing the command: cd /projects/offline-repo
  3. Run the playbook by executing the command:
ansible-playbook distribute-repository-server-certificate.yml -i inventory-file.yml --user=zbeda --ask-pass --ask-become-pass
  • ansible-playbook: Executes an Ansible playbook.
  • deploy-offline-repository.yml: Specifies the playbook file to run.
  • -i inventory-file.yml: Points to the inventory file containing enviroment server IPs.
  • --user=zbeda: Connects to the remote hosts using the specified username (zbeda).
  • --ask-pass: Prompts for the SSH password to connect to the remote hosts.
  • --ask-become-pass: Prompts for the privilege escalation password (e.g., for sudo tasks).
Playbook execution

4. Verify that the playbook was executed successfully

Ansible Playbook successful run

Verification

At this stage, we’ve completed the following steps:

  • Configured the offline repository server with project files.
  • Created a repository and generated a self-signed certificate.
  • Configured the client servers to connect to the new repository.
  • Distributed the public self-signed certificate to the client servers.

Now it’s time to verify that everything is working as expected.

  1. Connect to one of the client servers via ssh
  2. Install tmux by executing the command: sudo dnf install -y tmux
  3. verify that tmux was installed successfully by executing the command: tmux -V
successful installation of tmux

4. Install nginx by executing the command: sudo dnf install -y nginx

5. verify that nginx was installed successfully

Congratulations! 🎉

you now have your very own offline YUM repository server up and running!

With this setup, you can:

  • Install packages securely and reliably on your client servers, even in air-gapped environments.
  • Control the availability of approved packages, ensuring compliance and consistency within your environment.
  • Easily expand and update your repository to adapt to new requirements.

If you liked this blog don’t forget to clap and follow me on both Medium and Linkedin

www.linkedin.com/in/davidzbeda

Updates & Upgrades

Upgrade the YUM Repo with New Packages

When new packages need to be added to the repository, follow these steps:

  1. Login to the Internet server
  2. Update the download-project-packages.sh script by adding the new packages under the PACKAGES parameter or download the packages manually — Check the command section below
  3. Transfer the downloaded packages to the Ansible server under the defined project_packages_files_location (/projects/offline-repo/repo-project-packages)
  4. Connect to the Ansible server via SSH
  5. Navigate to your project folder by executing the command: cd /projects/offline-repo
  6. Run the playbook by executing the command:

Note :During installation, you will be prompted to confirm whether you want to replace the private key. Press `1` to skip or wait for 1 minute for the playbook to automatically proceed.

ansible-playbook deploy-offline-repository.yml -i inventory-file.yml --user=zbeda --ask-pass --ask-become-pass
  • This playbook regenerates the repo list that will include the new packages

7. Run the playbook by executing the command:

ansible-playbook clear-dnf-cache.yml -i inventory-file.yml --user=zbeda --ask-pass --ask-become-pass
  • This playbook clears the dnf cache on all environment servers to ensure they fetch the updated file list from the offline repository server.

Update — Generate a New Certificate

If the certificate expires or needs to be regenerated due to security policies, follow these steps:

  1. Connect to the Ansible server via SSH
  2. Navigate to your project folder by executing the command: cd /projects/offline-repo
  3. Run the playbook by executing the command:

Note: During installation, you will be prompted to confirm whether you want to replace the private key. Press `1` to skip or wait for 1 minute for the playbook to automatically proceed.

ansible-playbook deploy-offline-repository.yml -i inventory-file.yml --user=zbeda --ask-pass --ask-become-pass
  • This playbook generates a new self-sign certificate and a public key

7. Run the playbook by executing the command:

ansible-playbook distribute-repository-server-certificate.yml -i inventory-file.yml --user=zbeda --ask-pass --ask-become-pass
  • This playbook distributes the new public key to all client servers

Extras

Command

Clear Cached Data

dnf clean all
  • Description: Clears cached data used by the dnf package manager.
  • When to Use:
  1. After adding or updating the repository server.

2. After adding new files to an existing repository

Download offline packages

dnf download --resolve --destdir=/tmp/offline-packages <package-name>
  • Description: Downloads a package and its dependencies to a specified directory.
  • Example: To download the tmux package to /tmp, run: dnf download --resolve --destdir=/tmp tmux

List registered Repositories

dnf repolist
  • Description: Displays all the registered repositories on the client server.
dnf repolist

List Installed packages

dnf list installed
  • Description: Displays the installed packages on your server and indicates the repository from which they were fetched.
List the tmux package

Create a Repository

createrepo /var/www/html/offline-rep
  • Description: Creates a repository from the RPM packages located in the /var/www/html/offline-repo directory.
  • Important:
  1. Copying files to the directory without running this command will not expose the package to the client servers.
  2. After adding new files to the YUM offline repository server and running the createrepo command, you must either restart the client servers or run the following command to refresh the cache: “dnf clean all”

Troubleshooting

Aligning the Solution with Different RedHat or Rocky Linux Versions

To align the offline repository solution with a different RedHat or Rocky Linux version (e.g., 9.5), follow these steps:

  1. Set Up the Internet Server
    Install an Internet-connected server running the desired RedHat or Rocky Linux version. For example, if you’re targeting version 9.5, ensure the server is running that version.
  2. Update the Package Download Script
  • Modify the rocky-download-mandatory-packages.sh or redhat-download-mandatory-packages.sh script.
  • Instead of specifying a versioned package name, only define the package name and architecture.
    Example:
    Change apr-1.6.3-12.el8.x86_64 to apr.x86_64.

3. Download Mandatory Packages
Run the updated script on the Internet-connected server to download the necessary files.

4. Download Project-Specific Packages
Execute the download-project-packages.sh script to fetch packages matching the running OS version.

5. Transfer Files
Move the downloaded files from the Internet-connected server to the Ansible server.

6. Update Ansible Playbooks
Edit the rocky-deploy-offline-repository.yml or redhat-deploy-offline-repository.yml playbook:

  • Locate the ansible task : “Install createrepo and HTTPD with SSL using local RPM files.”
  • Update the playbook with the new package versions downloaded in the previous steps.
    Note: HTTPD must be installed as a group.

7. Run the Process
Execute the full process to create the offline YUM repository for your desired version.

reference

If you liked this blog don’t forget to clap and follow me on both Medium and Linkedin

www.linkedin.com/in/davidzbeda

--

--

David (Dudu) Zbeda
David (Dudu) Zbeda

Written by David (Dudu) Zbeda

DevOps | Infrastructure Architect | System Integration | Professional Services | Leading Teams & Training Future Experts | Linkedin: linkedin.com/in/davidzbeda

No responses yet