on a fedora system, we can create local dnf repos hosting packages built locally via rpmbuild; these local repos work nicely with remote repos that we normally use;

creating a local dnf repo involves several steps:

  1. create the repo dir;

    there are some considerations when creating the repo dir: because the repo contains packages that are installed system-wide, it is recommended to protect the repo dir with root permission; also, a dnf repo hosts packages for a specific distro, release version and arch; ideally, the name of the repo reflects these properties;

    here is what we do: we create this repo at /opt/repo/fedora-31-x86_64, with two subdirs for binary and source packages, respectively:

    $ sudo mkdir -p /opt/repo/fedora-31-x86_64/{RPMS,SRPMS}
    $ sudo chown -R root:root /opt/repo
    $ sudo chmod -R go-w,a-st /opt/repo
    
  2. build rpm packages locally;

    now we have the repo dir but not the packages; as we said, our local repo hosts packages built locally via rpmbuild; more specifically, we build these packages with:

    $ cd ~/rpmbuild
    $ rpmbuild -ba SPECS/{package}.spec
    

    the built binary and source packages are left in ~/rpmbuild/RPMS and ~/rpmbuild/SRPMS, respectively;

  3. fill the repo with packages;

    this is just plain file copy:

    $ sudo cp -r ~/rpmbuild/RPMS/* /opt/repo/fedora-31-x86_64/RPMS/
    $ sudo cp -r ~/rpmbuild/SRPMS/* /opt/repo/fedora-31-x86_64/SRPMS/
    

    it is unlikely that you built packages as root; did you? if you did, fix it; it is good habit not to abuse root privilege; so we assume the packages have normal user ownership; when we move them into the repo dir, we change their ownership and permission:

    $ sudo chown -R root:root /opt/repo/fedora-31-x86_64
    $ sudo chmod -R go-w,a-st /opt/repo/fedora-31-x86_64
    

    now the ~/rpmbuild dir is useless for our local repo; you can remove it if you want, or keep it if you need more from it;

  4. create repo metadata:

    to actually make the dir a dnf repo, we need a tool createrepo:

    $ sudo dnf install createrepo
    

    now create repo metadata with:

    $ sudo createrepo /opt/repo/fedora-31-x86_64
    

    this generates a subdir repodata containing repo metadata, turning the repo dir into a real dnf repo;

  5. add this repo to dnf:

    now we need to make dnf aware of this repo; we can do this with dnf itself:

    $ dnf config-manager --add-repo /opt/repo/fedora-31-x86_64
    

    but this is not the most clever way of doing so; instead, we manually create a file /etc/yum.repos.d/local.repo:

    [Local]
    name=Local Repository
    baseurl=file:///opt/repo/fedora-$releasever-$basearch
    gpgcheck=0
    priority=0
    enabled=1
    

    this allows several customizations:

    • in baseurl, we include variables releasever and basearch, so that this file doesnt have to change if we have upgraded our system;

    • we disable gpgcheck because this is a local repo managed by ourselves;

    • we set priority to a very low value so that this local repo has higher priority over remote repos (the default priority is 99);

  6. now we should be able to install packages from this local repo using dnf:

    $ dnf install {package}
    

    we issue the install command as usual; since our local repo has a higher priority, packages there will be preferred over those from remote repos;

  7. to allow further changes to the repo, we can add a small maintenance script:

    #!/bin/bash
    set -eo pipefail
    repo="/opt/repo"
    chown -R root:root "$repo"
    chmod -R go-w,a-st "$repo"
    createrepo "${repo}/fedora-31-x86_64"
    

    run this script every time we add, modify or remove packages in this repo;