Mastering rpm-build and rpmlint: Bringing ‘Home-Grown’ Scripts to Fedora Standards

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

The Problem: Manual Deployment – A SysAdmin’s Time Sink

Think about it. You’ve just finished writing a great log backup tool in Python. Your boss asks you to immediately deploy it to 50 Fedora servers in the company’s infrastructure. What do you do?

The quickest way is using scp to push files, then ssh into each machine to chmod +x and create symlinks in /usr/bin. It sounds fine, but the reality is different. If just a few machines are missing dependencies or need an update, manually fixing every server becomes a disaster.

I’ve used Fedora as my main OS for 2 years. When faced with the challenge of distributing internal tools, I hesitated between using Ansible to copy files or finding a more “standard” way. RPM packaging turned out to be the answer that saved me 80% of maintenance time.

Why Manual File Copying Makes You Tired

When you install software by “copy-pasting,” the DNF package manager is completely unaware of their existence. This leads to 4 major issues:

  • Version Chaos: It’s very difficult to check which server is running v1.0 and which has been upgraded to v1.2.
  • Missing Dependency Errors: Your tool might need curl or jq, but a file-copying script can’t automatically pull them in.
  • Nightmare Uninstallation: You must remember the exact location of every file you dropped in to delete them manually.
  • Integrity: No checksums, no digital signatures. Who can guarantee the files on the server haven’t been tampered with?

Are Alternatives Actually Better?

Before choosing RPM, I considered several options:

  1. Tarballs (.tar.gz): Simple, but still suffers from dependency management issues and is very hard to roll back when something goes wrong.
  2. Flatpak: Great for desktop apps but too bloated for CLI tools that need deep system access.
  3. Containers (Podman/Docker): A good choice for environment isolation. However, for lightweight scripts, running a container can sometimes feel like “using a sledgehammer to crack a nut.”

Professional Packaging with rpm-build and rpmlint

In the Fedora/RHEL ecosystem, RPM is the “native language.” Packaging as .rpm lets you leverage the power of dnf: automatic dependency installation, version management, and mass deployment via internal repositories with a single command.

Step 1: Set Up the Environment

First, install the package building and testing toolkit. Open your terminal and run:

sudo dnf install -y rpm-build rpmlint rpmdevtools

Next, initialize the RPM workspace directory structure using the command:

rpmdev-setuptree

This command creates the ~/rpmbuild directory with specialized subfolders: SOURCES (source code), SPECS (build configuration files), and RPMS (the final products).

Step 2: Prepare the Source Code

Suppose I have a script named itfromzero-hello.sh. I’ll compress it according to version 1.0 standards.

# Create directory structure
mkdir -p itfromzero-hello-1.0
cat <<EOF > itfromzero-hello-1.0/itfromzero-hello.sh
#!/bin/bash
echo "Welcome to itfromzero.com!"
EOF

# Package the tarball
tar -czvf itfromzero-hello-1.0.tar.gz itfromzero-hello-1.0/
mv itfromzero-hello-1.0.tar.gz ~/rpmbuild/SOURCES/

Step 3: Write the SPEC File – The Soul of the RPM Package

Navigate to ~/rpmbuild/SPECS and create the itfromzero-hello.spec file. This is where you define the “ID card” for your software.

Name:           itfromzero-hello
Version:        1.0
Release:        1%{?dist}
Summary:        Greeting script from itfromzero

License:        MIT
URL:            https://itfromzero.com
Source0:        %{name}-%{version}.tar.gz

BuildArch:      noarch
Requires:       bash, curl

%description
Standard RPM packaging example for SysAdmins and Developers.

%prep
%setup -q

%install
mkdir -p %{buildroot}/usr/bin
install -m 0755 itfromzero-hello.sh %{buildroot}/usr/bin/itfromzero-hello

%files
/usr/bin/itfromzero-hello

%changelog
* Sun May 17 2026 Admin <[email protected]> - 1.0-1
- Initial package

Important Note: The Requires section is where you list dependencies. If the target machine lacks curl, DNF will automatically download it before installing your tool.

Step 4: Verify with rpmlint

Don’t rush to build just yet. Let rpmlint check for syntax errors first. This is a habit of professional package maintainers.

rpmlint ~/rpmbuild/SPECS/itfromzero-hello.spec

If errors appear, you must fix them. Warnings can be considered for ignoring depending on the situation.

Step 5: Publish the RPM Package

The long-awaited moment has arrived. Use the rpmbuild command to craft the installation file:

rpmbuild -ba ~/rpmbuild/SPECS/itfromzero-hello.spec

After a few seconds, the RPM file will be neatly placed in the ~/rpmbuild/RPMS/noarch/ directory, ready for distribution.

Step 6: Verify the Result

Try installing the package you just created like a real piece of software:

sudo dnf install ~/rpmbuild/RPMS/noarch/itfromzero-hello-1.0-1.fc40.noarch.rpm

Type itfromzero-hello and enjoy the result. Professional, isn’t it?

Conclusion

Getting used to rpm-build might feel a bit overwhelming at first due to the syntax in the .spec file. But believe me, when managing dozens of servers, having an internal RPM repository will help you sleep soundly. Instead of spending 2 hours on manual commands, you only need 2 minutes for a dnf update across the entire system. Don’t be afraid to make mistakes—it’s the fastest way to upgrade your Linux skills!

Share: