How to create a custom rpm repository on Linux

Rpm is the acronym of RPM Package Manager: it is the low-level package manager in use in all the Red Hat family of distributions, such as Fedora and Red Hat Enterprise Linux.

An rpm package is a package containing software that is meant to be installed using this package management system, and rpm packages are usually distributed via software repositories. In this tutorial we learn how to create a custom rpm repository and how to configure our distribution to use it as a software source.

In this tutorial you will learn:

  • How to create an rpm repository
  • How to use the repository as a software source


Software requirements and conventions used

Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Any distribution of the Red Hat family
Software dnf, createrepo
Other Administrative privileges to configure the repository
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user

Software installation

For the sake of this tutorial we will create our custom repository on a local machine with IP that will use as an http server. On this machine, the first thing we need to do is to install the createrepo package. The distribution installed on the remote machine doesn’t need to be an rpm-based distribution itself, as long as said package is available. In our case, for example, the system installed on the server is Debian, so to install the package we need to run the following command:

$ sudo apt-get update && sudo apt-get install createrepo

As we said before, in our specific example we want to make the software hosted on our custom repository to be accessible via the HTTP protocol, therefore we need to install an HTTP server; in this case we will work with Apache. Installing it on Debian, it’s just a matter of running:

$ sudo apt-get install apache2

Once the packages are installed, we can proceed and create our rpm repository in few, very simple steps.

Creating the repository

The default Apache VirtualHost DocumentRoot created when Apache is installed on Debian is /var/www/html. At this point we can choose to create a VirtualHost for our repository, or simply create the repository directory as part
of the default one. For the sake of simplicity, in this tutorial we will explore the latter option:

$ sudo mkdir /var/www/html/repo

The repo directory we created with the command above, inside the default VirtualHost DocumentRoot, will host our packages, and will be the base of our repository. To better structure it, we now want to create some subdirectories
named after the distribution, its version and the architecture of the packages we want to make available. Suppose, for example, we want to use the repository on Fedora 33 x68_64, we should run the following command:

$ sudo mkdir -p /var/www/html/repo/fedora/releases/33/x86_64

The next step consists in populating the repository. All we have to do is to place the packages we want to make available, inside the appropriate repository directory. In this case, as an example, I will populate the repository with a package obtained by compiling the VSCode editor from source. The package is called code-1.56.0-1617183449.el8.x86_64.rpm. Once it is copied, our file structure should look like that:

└── fedora
    └── releases
        └── 33
            └── x86_64
                └── code-1.56.0-1617183449.el8.x86_64.rpm

With our repository populated, all we want to do is to run the createrepo command inside the directory containing the packages. In this case we would run:

$ sudo createrepo /var/www/html/repo/fedora/releases/33/x86_64

The command will create the repository metadata inside a directory named repodata, based on the packages contained in the destination directory and must be re-launched each time the repository is updated with new packages or old packages are removed. Once the command is launched, our directory structure will look like:

└── fedora
    └── releases
        └── 33
            └── x86_64
                ├── code-1.56.0-1617183449.el8.x86_64.rpm
                └── repodata
                    ├── 22ab1d1d123bb7d7cde556bf8a8ac4daf9cdb75572f40ebdd2f399908cb7f6b9-other.xml.gz
                    ├── 26ed9b63868b2e0263dfa817e21921c4e7542c1be9f6b7875381bba6bd78d1c6-primary.sqlite.bz2
                    ├── 50fc300a761812761cf9a8413a619da23cf336d49999753568ce19a97c025d44-other.sqlite.bz2
                    ├── a523f54b5fcd0720c182969f991f51e125728a361f31237725dc9418d5e126ea-primary.xml.gz
                    ├── af2fa9ea5deaffca5ffc9f3e524155defa8cfa5656962845a45c8b0e984f3e19-filelists.sqlite.bz2
                    ├── f95849cf860f1184b97d30000ea1f9f1c35edd6d625dcd387453187510dd4a18-filelists.xml.gz
                    └── repomd.xml

Our repository was successfully created. Now we have to configure our distribution to use it as a software source.

Adding the repository as a software source

Let’s move to our rpm-based distribution and see how to configure it in order to use our custom repository as a software source. Repository configuration files are found under the /etc/yum.repos.d directory, and must have the
.repo extension. By looking inside the directory we can see the already existing ones:

$ ls /etc/yum/repos.d
fedora-cisco-openh264.repo   fedora-updates-testing-modular.repo
fedora-modular.repo          fedora-updates-testing.repo
fedora.repo                  rpmfusion-free.repo
fedora-updates-modular.repo  rpmfusion-free-updates.repo
fedora-updates.repo          rpmfusion-free-updates-testing.repo

Now, let’s create our custom repository configuration. Inside the file, as a minimum set of information, we should provide:

  • The repository id
  • The repository name
  • A repository baseurl
  • The repository status
  • Whether to check the gpg signature of the packages or not

We will save such information in a file called ownrepo.repo, here is its content:

name=Own repository

The definition reported inside brackets ([ownrepo]) is the repository ID, and must be unique in all repository definitions. With the name key we provided a human-readable name for the repository as a string. This is optional; if a name is not provided, the repository ID will be used also as a name.

With the baseurl key we specify a list of the URLs for the repository. The URLs must be separated by a space or a comma. In our example we just provided a single URL, but you can notice we used two variables in it:

  • $releasever
  • $basearch

The expansion of the first one, $releasever, will result in the release version of the operating system, in this case 33, since we are installing our repository on a Fedora 33 system. The second variable, $basearch, will be expanded in a string representing the base architecture of the system, which in our case is x86_64.

The enabled key requires a boolean value which determines if the repository should be considered active or not. The last key we used is gpgcheck: it also requires a boolean value, and is used to determine if a gpg signature check should be performed on the packages installed from the repository. In our example we simply disabled the check, since the repository is meant for personal use only.

Now that our repository is configured, we can try to install the code package from it, simply by running:

$ sudo dnf install code
Own repository                                                                    451 kB/s |  13 kB     00:00
Dependencies resolved.
 Package              Architecture           Version                                Repository               Size
 code                 x86_64                 1.56.0-1617183449.el8                  ownrepo                 100 M

Transaction Summary
Install  1 Package

Total download size: 100 M
Installed size: 294 M
Is this ok [y/N]:

Once we provide an affirmative answer to the prompt and confirm it, the package will be installed on our system.


In this article we learned how easy it is to create a custom rpm repository with the createrepo utility, and we saw how to create a dnf configuration file on our distribution to use it a software source. We saw a minimal subset of
the keys which can be used in the repository configuration; for a more detailed list you can consult the official dnf documentation.