reposync: Mirroring a YUM Repository Locally
When machines on an intranet can’t reach public YUM mirrors directly, the common approach is to sync the entire repository down on a machine that has internet access, then serve it as a local repo. reposync does exactly that: pulls the remote repository’s rpm packages into a local directory by repoid. This post starts from the CentOS 6-era yum-utils usage (the original environment) and tests, one item at a time, the real dnf-era differences inside a Rocky Linux 9.3 container (dnf 4.14) — with a somewhat counterintuitive conclusion: the compatibility scripts are still there and most old flags still work; what actually breaks is the --metadata flag name that circulates online.
The Overall Flow
Syncing a repository locally takes four steps: install the tools → create the directory → find the repoid → run the sync. After syncing, createrepo must generate the metadata before clients can treat the directory as a repository.
Install the Tool Package
The package carrying the reposync command has a different name on the two system generations:
1 | # CentOS 6/7 (yum era) |
Verification: on CentOS 6/7, reposync --help prints output; in the Rocky 9 container, after installing dnf-utils the standalone reposync command still exists (/usr/bin/reposync is a compatibility script pointing at /usr/libexec/dnf-utils), and the dnf reposync subcommand works at the same time — both paths are viable.
Create the Download Directory
Create the storage directory first; locally downloaded rpm packages land here:
1 | mkdir -p /data1/centos/$releasever |
$releasever is the YUM/DNF system-version variable; at execution time it is replaced with the current system’s major version (CentOS 6 → 6, Rocky 9 → 9), so packages of different versions naturally land in separate directories. Note that expanding this variable directly in the shell yields an empty string — it is resolved by yum/reposync itself. To get the value at the shell level, rpm -E %rhel worked in testing (the Rocky 9 container printed 9); files like /etc/dnf/vars/releasever do not exist in the Rocky 9 container, so don’t count on them.
Get the Repoid
To know which repositories to sync, you first need their repoids:
1 | yum repolist # CentOS 6/7 |
Sample output (the original article’s CentOS 6 environment):
1 | Loaded plugins: fastestmirror, product-id, subscription-manager |
From the output, this machine has 4 repoids: base, epel, extras, updates. A repoid corresponds to the [serverid] in a .repo config file — the name inside the brackets. It distinguishes repositories and must be unique; with duplicate names, the later one overrides the earlier.
Sync the Repositories
Sync all 4 repositories in one go, into the directory created earlier:
1 | reposync -n --repoid=base --repoid=epel --repoid=extras --repoid=updates \ |
What this command does:
--repoidnames the repositories to sync; you can pass one or several (as long as the download directory is the same);-psets the destination path;-nmeans--newest: download only the newest version of each package and skip older ones, saving a lot of disk space.
When it runs, reposync automatically creates a same-named directory under the destination path for each repoid, so packages lie in their own per-repo directories. Verified on the Rocky 9 container (a small local repository of 3 self-built rpms — the mechanism is identical to a public mirror):

Real dnf-era Differences (Verified on Rocky 9)
The counterintuitive conclusion first: the old CentOS 6-era command reposync -n --repoid=X -p PATH runs unchanged on Rocky 9 — the compatibility script from dnf-utils translates the yum-era flags to dnf as-is. What actually fails is the garbled-by-word-of-mouth --metadata; the verified error:

--metadata was prefix-matched by argparse into --metadata-path (an option that takes an argument), hence expected one argument. The correct flag is --download-metadata. Item-by-item comparison of verified results:
| Purpose | CentOS 6/7 (yum-utils) | Rocky 9 (dnf 4.14, verified) |
|---|---|---|
| Invocation | reposync |
both reposync (compat script) and dnf reposync work |
| Newest packages only | -n / --newest |
-n (help text reads -n, --newest-only); both forms verified working |
| Destination path | -p PATH |
-p PATH (--download-path), compatible |
| Sync repodata too | manual createrepo needed | --download-metadata (not --metadata) |
The Rocky 9 equivalent command:
1 | dnf reposync --repoid=baseos --repoid=appstream \ |
--download-metadata is the dnf version’s nicety: repodata is synced along with the packages, eliminating the createrepo step (in the yum era you ran createrepo /data1/centos/6/base yourself; on Rocky 9 that command comes from the createrepo_c package, and /usr/bin/createrepo is still there).
After Syncing: Metadata and Consumption Verification
In the yum era the sync produced only rpms; for clients to treat the directory as a repository, you still had to generate metadata inside it:
1 | createrepo /data1/centos/6/base |
Then configure a .repo file on the client pointing at this directory (file:// or http://). With the dnf version’s --download-metadata, this step can be skipped. Finally, a consumption test closes the loop — verified: installing a package directly from the synced copy succeeded:

Points to Watch
- The bigger the repository, the longer the sync takes — first-time syncs of large repos like base plus epel routinely hit tens of GB and hours; run it in the background with
nohup ... &, and resume simply by running it again (reposync skips packages that already exist unchanged). -n(–newest-only) pulls only the newest packages; if your local repo must serve mixed deployments of old packages (legacy apps pinned to specific old versions), evaluate before dropping that flag — full history is a lot larger.- After syncing, remember to generate/sync the metadata (createrepo or –metadata); a directory with only rpms and no repodata is not recognized by clients.
- Plan disk space ahead: the status column of
dnf repolistcounts packages; to estimate size roughly,dnf repoquery --repoid=X --qf '%{downloadsize}' | awk '{s+=$1}END{print s/1024/1024 " MB"}'. - Schedule periodic incremental syncs with cron (once daily at low peak); reposync is naturally idempotent — reruns pull only additions and changes.
- The CentOS 6/7 commands in this post follow the original (yum-utils 1.x; that environment is EOL and was not re-run); the Rocky 9 portions were verified in a rockylinux:9 container (dnf 4.14), including the self-built repository, sync, metadata, and the consumption loop (the tree package installed successfully from the synced copy).
reposync’s value in one sentence: when the public mirror can’t come in, move the mirror in. Three takeaways from the Rocky 9 verification: the compatibility scripts are still there (old commands are safe), repodata syncs via --download-metadata (don’t write --metadata), and after syncing run one installation check with --repofrompath — and the intranet-repository job is closed.
This article was rebuilt from the author’s CSDN blog posts written between 2020 and 2024, originally published on CSDN.