EPEL and CRB repos on Rocky and Alma
Why dnf cannot find your package on Rocky Linux and AlmaLinux: what BaseOS, AppStream and CRB hold, how to add EPEL safely, and how to keep repos clean.
Why dnf cannot find the package you want
EPEL and CRB are the two repositories a fresh Rocky Linux or AlmaLinux server does not hand you, which is why dnf install htop on a new box answers with No match for argument: htop and then Error: Unable to find a match: htop. Nothing is broken and no mirror is down. The base distribution ships a small set of packages on purpose, CRB is present but switched off, and EPEL is a separate community repository you have to add.
On Ubuntu the same package sits in universe, and universe is enabled on nearly every cloud image, so the question never comes up. The Red Hat family splits its packages differently and defaults to less. The fix is three commands. The rest of this guide is the part nobody tells you in week one: what those repositories promise, what they do not promise, and how to stop a third party repository from quietly taking over your base system.
How these commands were checked. Our command test containers run Ubuntu only, so the dnf commands below were not executed on our own test machines. They follow the Rocky Linux and AlmaLinux documentation. Every step names the output you should see, so check each one on your own server instead of pasting the whole block at once.
What are BaseOS, AppStream and CRB?
BaseOS is the operating system itself: the kernel, glibc, systemd, the core userland. Versions here are frozen for the life of the major release, and security fixes are backported into those frozen versions. A version number that looks years old in BaseOS is not an unpatched package. It is a patched old version, which is the whole point of an enterprise distribution.
AppStream holds the things you run on top: web servers, databases, language runtimes, editors, monitoring agents. On version 8, much of AppStream was delivered as modules with alternate streams, so dnf module list mattered and you picked, for example, one PHP stream. Version 9 dropped nearly all modularity, so on Rocky 9 and Alma 9 you usually get one version of a thing and no module to enable first.
Extras is enabled by default and is very small. It mostly holds release packages for other repositories, which is where epel-release itself comes from. That detail is why you never need to trust a random URL to install EPEL on Rocky or Alma.
CRB is the CodeReady Builder repository, called PowerTools on version 8. It holds the build side of the distribution: development headers, static libraries, and the test and documentation tooling that packages need at build time. It is already on the mirror and disabled by default. On Red Hat's own product the same content is called CodeReady Linux Builder, it comes with the subscription, and Red Hat states it is not covered by support. Rocky and Alma inherit both the content and the disabled default.
For readers arriving from Debian or Ubuntu: main mixes runtime packages and -dev headers in one archive, so there is no CRB to enable there. The closest match for EPEL is universe, which is community maintained and carries no vendor support promise.
What EPEL is, and who stands behind it
EPEL stands for Extra Packages for Enterprise Linux. It is a Fedora project: packages that exist in Fedora, rebuilt for the current enterprise release, maintained by the EPEL Special Interest Group, which is mostly volunteers from the Fedora community. Red Hat hosts the build and mirror infrastructure, and some Red Hat engineers maintain packages in it. That is where the relationship ends. EPEL is not a Red Hat product. There is no support contract and no SLA (service level agreement) behind an EPEL package, on RHEL or on a rebuild.
One policy makes EPEL safe to enable at all: an EPEL package must never replace a package from the base distribution. If AppStream ships nginx, EPEL will not. That rule is enforced by the people who review EPEL packages, so it is a promise about EPEL only. It protects you from nothing else you add later.
The lifetime promise is different from the base distribution too, and this is what bites in year three. A BaseOS package version is frozen for the whole ten year life of the major release. An EPEL maintainer commits to a much shorter window: at least one RHEL minor release or 13 months, whichever is shorter. Most packages are maintained far longer than that in practice. Some are retired when the maintainer moves on, and some jump to a new major version in the middle of your distro's life, because EPEL follows Fedora. So a routine dnf upgrade can hand you a new major version of an EPEL tool on a machine you thought was stable, and a package you depend on can stop receiving updates with no announcement that reaches you.
One more consequence worth knowing before you enable it: EPEL is built against the newest RHEL minor release. If you hold a server back on an older minor, using a frozen mirror or a vendor point release repository, an EPEL package can require a base library newer than the one you have. dnf reports that as a missing dependency, and it looks like a mirror problem when it is really a version skew problem.
Enable CRB and install EPEL on Rocky or Alma
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager --set-enabled crb
sudo dnf install -y epel-release
sudo dnf makecache
dnf repolist --enableddnf repolist --enabled should now list baseos, appstream, extras, crb and epel. You may also see a small epel-cisco-openh264 entry, which epel-release adds. If crb is missing from that list, the enable step did not take, and the next section explains why.
On Rocky 8 and Alma 8 the repository is still called PowerTools, so the middle command becomes sudo dnf config-manager --set-enabled powertools. Repository ids are case sensitive, and older CentOS 8 documentation spells it PowerTools with capitals, which will not match. On AlmaLinux 10 the CRB repository is enabled by default from 10.0 onwards (changed in September 2025), so there you only need the epel-release step.
epel-release comes from extras, which is already enabled, so there is no URL to trust and no key to import by hand. The package writes /etc/yum.repos.d/epel.repo and installs the EPEL signing key under /etc/pki/rpm-gpg/. Confirm gpgcheck=1 in that file, and ignore any guide that tells you to work around a signature error with --nogpgcheck. A failing signature check means the package is not what it claims to be, or your clock is wrong.
On Rocky, epel-release also installs a small helper at /usr/bin/crb, so sudo crb enable and crb status do the same job without the plugin. Check whether you have it with command -v crb before you rely on it, because it is not present on every branch of every rebuild.
To prove EPEL is reachable rather than just listed, ask it for a package that only it carries:
dnf repoquery --repo=epel htopThat prints the package name, version and architecture. Silence means the repository is enabled but returning nothing, which is usually a mirror or metadata problem rather than a configuration one, so try sudo dnf clean all && sudo dnf makecache next.
Why dnf says no such command: config-manager
This is the first thing that trips people, and it happens on exactly the images most VPS providers hand you.
No such command: config-manager. Please use /usr/bin/dnf --help
It could be a DNF plugin command, try: "dnf install 'dnf-command(config-manager)'"config-manager is a plugin, not a built in dnf subcommand. It ships in dnf-plugins-core, which a full server install pulls in and which minimal images, cloud images and container images leave out. dnf's own suggestion works because the package declares that virtual capability:
sudo dnf install -y 'dnf-command(config-manager)'Quote it. The parentheses are shell syntax, so an unquoted version fails with a syntax error rather than a dnf error.
If you cannot install the plugin because the repository you need is the disabled one, edit the file instead. Find which file holds the section, open it, and set enabled=1 under [crb]:
grep -rl crb /etc/yum.repos.d/That is exactly what config-manager writes, so nothing is lost by doing it by hand. dnf repolist --enabled confirms the result.
Some EPEL packages will not install until CRB is on
The second common trap gives an error that never mentions CRB. An EPEL package that links against a library shipped only in CRB fails during dependency resolution, and the message names the library and the package that wanted it:
Error:
Problem: conflicting requests
- nothing provides libexample.so.0()(64bit) needed by examplepkg-1.4-2.el9.x86_64 from epelThe cause is that CRB is disabled, so dnf cannot see the only repository that provides that library. Check the two things in order:
dnf repolist --enabled
dnf --enablerepo=crb repoquery --whatprovides 'libexample.so.0()(64bit)'If the second command names a package while the plain install still fails, CRB is off. This class of error is common enough that AlmaLinux turned CRB on by default in version 10 specifically to stop it happening. --enablerepo=crb also works as a one time flag on a single install, but leave CRB enabled permanently if you use EPEL at all, because the next EPEL update can pull in a new CRB dependency without warning you first.
Which repository did this package come from?
After a few weeks with four repositories enabled, the useful question stops being what is installed and becomes where it came from.
dnf repolist --all
dnf info htop
dnf repoquery --installed --qf '%{from_repo} %{name}' | sort | uniq -c | sort -rn
dnf repository-packages epel list installeddnf info on an installed package prints a From repo line. dnf list installed shows the same information in its third column with an @ in front, so @epel means installed from EPEL, and @System means dnf does not know where it came from, which usually means somebody ran rpm -i on a downloaded file. The repoquery line gives a count per repository, which is the fastest way to discover that a server you inherited has forty packages from a repository you have never heard of. The last command lists exactly what one repository has given you, and that inventory is what you need before you decide to remove it.
The apt habit here is apt-cache policy <package>, and the dnf and apt command equivalents are worth keeping open in a second tab for the first month, because the concepts map cleanly even when the flags do not.
How do I stop a third party repo replacing a base package?
EPEL promises not to do this. No other repository does. A vendor repository for a database, an agent or a language runtime can ship its own build of a library that BaseOS also provides, and dnf will install it, because dnf's default rule is simple: the highest version wins, wherever it comes from.
Two controls do most of the work, and both live in the repository file under /etc/yum.repos.d/.
priority= decides which repository wins when more than one carries the same package name. Lower numbers win and the default is 99, so give your base repositories a low number and any third party repository a high one. dnf then takes the base package even when the third party version is newer. Modern dnf handles this itself, so the separate yum-plugin-priorities package of the CentOS 7 era is not part of the answer any more.
includepkgs= is the stronger of the filter options. excludepkgs= blocks named packages from a repository, which requires you to predict what it might ship. includepkgs= inverts that: this repository may provide these names and nothing else. A vendor repository that should only ever give you its own agent is one line.
[vendor-tools]
name=Vendor tools for EL9
baseurl=https://packages.example.com/el9/x86_64/
enabled=1
gpgcheck=1
gpgkey=https://packages.example.com/RPM-GPG-KEY-vendor
priority=90
includepkgs=vendor-agent,vendor-agent-pluginsOn version 8 there is one more setting to know. A package from a third party repository can be hidden when an AppStream module provides the same name, and module_hotfixes=1 in that repository's section tells dnf to stop filtering it. If a package is visible to dnf repoquery but will not install on an 8 box, that is usually why. Version 9 dropped nearly all modules, so this rarely appears there.
To pin one package to one version, install python3-dnf-plugin-versionlock and use sudo dnf versionlock add <package>. That is the equivalent of apt-mark hold. Note one reversal that catches people coming from Debian: in apt a higher Pin-Priority wins, in dnf a lower priority wins.
Why mixing RHEL adjacent repos makes a server unupgradeable
Rocky, Alma, CentOS Stream, Oracle Linux and RHEL are close enough that their packages install on each other, and far enough apart that the result stops being a system anyone can support.
The mechanism is version numbers. CentOS Stream 9 runs ahead of RHEL 9, so pointing a Rocky 9 box at a Stream repository, even once, even for one package, leaves you holding packages whose versions are ahead of anything Rocky will ever ship. When the next Rocky minor release arrives, its version of that package is lower than yours, so dnf upgrade will not touch it. The machine now runs a combination nobody tested, and it stays that way quietly for years while you assume it is patched.
The symptom is dnf upgrade reporting nothing to do while sudo dnf distro-sync proposes to downgrade a long list of packages. distro-sync is the repair tool: it forces every installed package to match what the enabled repositories actually offer, downgrades included. Disable the foreign repository first, then run it, then read the proposed list before you accept it. The repair fails when the older RPM is no longer on the mirror, and at that point rebuilding the server from a clean image is faster and safer than fighting the dependency solver.
ELevate era leftovers are the other common version of this problem. ELevate is the AlmaLinux migration tool built on Leapp, used to move a CentOS 7 box forward or to convert between rebuilds. A migration that was rushed leaves EL7 repository files in /etc/yum.repos.d/ and EL7 packages still installed. Find them with rpm -qa | grep el7. Each one is a package that no enabled repository can ever update, and a later Leapp run reports them as packages it cannot map, which becomes an upgrade blocker you clear by hand. Clear them out while the server is calm, not on the day you need the next major upgrade.
A vendor repository shadowing an AppStream package is the mild version of the same disease, and the includepkgs line above is the cure. Container tooling is the usual case, because containerd.io from Docker's own repository conflicts with runc from AppStream, so one of them has to go. Decide once, write the exclusion down, and follow a known good order: the Docker install on Rocky Linux walkthrough covers which distribution packages to remove first.
The apt to dnf translation for repositories
/etc/apt/sources.list.d/*.sourcesbecomes/etc/yum.repos.d/*.repo, where one file can hold several[sections], each with its own id.add-apt-repository universebecomesdnf install epel-release, with the difference thatuniverseis still inside Ubuntu's own archive and EPEL is a separate project.apt updatehas no equivalent you must remember. dnf refreshes metadata on its own schedule, anddnf makecacheforces it now.apt-cache policy <pkg>becomesdnf info <pkg>, plusdnf list --showduplicates <pkg>to see every version on offer.apt-mark holdbecomesdnf versionlock add, frompython3-dnf-plugin-versionlock.- Pinning in
/etc/apt/preferences.d/becomespriority=in the repository section, with the numbers running the opposite way. dpkg -S /path/to/filebecomesrpm -qf /path/to/file.
Automatic updates transfer as an idea rather than as syntax, since there is no unattended-upgrades here. The timer, the config file and the question of whether to reboot are covered in dnf-automatic on Rocky and Alma.
Keep the repository list short
Enable CRB, install epel-release, then write down what you did and why, either in your configuration management or in a plain file on the box. That note is worth more than it sounds when the server is three years old and somebody else is holding it.
Search before you add. Run dnf search, then dnf info, and only then consider a new repository. A surprising share of what people enable EPEL for is already in AppStream. System monitoring is the clearest example, since Performance Co-Pilot ships in the base repositories and needs no third party anything. Every extra repository is another party who can ship you a package on a Tuesday, and every one of them makes the next major upgrade harder.
If you are still choosing between the two distributions, this whole layout is the same on both, and epel-release behaves identically. The real differences are elsewhere: the Rocky Linux and AlmaLinux comparison covers the rebuild philosophy, since AlmaLinux now targets ABI (application binary interface) compatibility rather than a line for line rebuild.
FAQ
How do I enable EPEL on Rocky Linux 9 or AlmaLinux 9?
Run sudo dnf install -y dnf-plugins-core, then sudo dnf config-manager --set-enabled crb, then sudo dnf install -y epel-release. Confirm with dnf repolist --enabled, which should list baseos, appstream, extras, crb and epel. Enable CRB before you install EPEL packages, because many of them depend on libraries that only CRB provides. On version 8 the repository id is powertools instead of crb.
Is it safe to enable EPEL on a production server?
It is widely used and it is built on a policy that EPEL packages never replace a package from the base distribution, so enabling it does not change what BaseOS or AppStream give you. The caveat is support: EPEL is a volunteer Fedora project with no service level agreement, and a maintainer commits to a package for as little as one RHEL minor release or 13 months. Keep an inventory with dnf repository-packages epel list installed, and use dnf versionlock on any EPEL package that a customer facing service depends on.
Why does dnf say no such command: config-manager?
Because config-manager is a dnf plugin rather than a built in command, and minimal or container images ship without dnf-plugins-core. The message itself gives the fix: sudo dnf install -y 'dnf-command(config-manager)', quoted so the shell does not read the parentheses. If you cannot install anything yet, run grep -rl crb /etc/yum.repos.d/, open the file it names, and set enabled=1 in the [crb] section by hand.
What is the difference between CRB and PowerTools?
They are the same repository under two names. Version 8 calls it PowerTools with the id powertools, version 9 and later call it CRB with the id crb, and Red Hat's own product calls the content CodeReady Linux Builder. It carries development headers, static libraries and build time tooling, and it is disabled by default on Rocky and on AlmaLinux 9. AlmaLinux 10 enables it by default from 10.0, so check dnf repolist --enabled before you run the enable command there.
How do I remove EPEL again without breaking things?
Inventory first with dnf repository-packages epel list installed, because removing the epel-release package alone does not remove anything installed from EPEL. Those packages stay on disk, lose their source of updates, and stop getting security fixes with no error to tell you. Decide package by package, remove or replace the ones you no longer need, and only then run sudo dnf remove epel-release. If something from EPEL has replaced nothing and simply must go, sudo dnf repository-packages epel remove clears the set in one transaction, so read the proposed list carefully before you confirm it.