Import Packages from External Sources¶
Use Repod's import feature to mirror packages from public or internal repositories into your private repository without uploading files manually.
How importing works¶
Importing is a two-step process:
-
Sync the index β Repod fetches the remote repository's package metadata (
Packages.gzfor APT,repomd.xmlfor RPM) and stores it in a searchable local catalog. No packages are downloaded at this stage. -
Import a package β Repod downloads the selected package binary from the remote source, runs it through the full security pipeline (antivirus, CVE scan, GPG verification), and publishes it to your distribution.
Step 1 β Add an external source¶
Navigate to Import β Sources β Add source, or use the API:
Common external sources¶
| Name | URL | Distribution |
|---|---|---|
| Ubuntu 22.04 | http://archive.ubuntu.com/ubuntu |
jammy |
| Ubuntu 24.04 | http://archive.ubuntu.com/ubuntu |
noble |
| Debian 12 | http://deb.debian.org/debian |
bookworm |
| Nginx stable | http://nginx.org/packages/ubuntu |
jammy |
| Name | URL |
|---|---|
| EPEL 9 | https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/ |
| EPEL 8 | https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/ |
| AlmaLinux 9 BaseOS | https://repo.almalinux.org/almalinux/9/BaseOS/x86_64/os/ |
| AlmaLinux 9 AppStream | https://repo.almalinux.org/almalinux/9/AppStream/x86_64/os/ |
| Nginx stable (RPM) | https://nginx.org/packages/rhel/9/x86_64/ |
Step 2 β Sync the index¶
Syncing fetches the remote metadata and populates the local searchable catalog. This does not download any packages.
In the web UI: Import β Sources β [source name] β Sync now
Via API (returns a real-time SSE stream):
The response is a Server-Sent Events stream. Each line is a progress update:
data: {"status":"syncing","count":0,"message":"Fetching index..."}
data: {"status":"syncing","count":4521,"message":"Processing packages..."}
data: {"status":"done","count":4521,"message":"Index updated"}
Sync duration
Syncing a large source (e.g. Ubuntu jammy main+universe) can take 30β120
seconds due to the size of Packages.gz. Subsequent syncs are faster because
only changed packages are processed.
Step 3 β Browse and select packages¶
After syncing, browse the package catalog under Import β Catalog. Use the search box to find packages by name.
The catalog shows for each package:
- Name, version, architecture
- Size
- Last sync timestamp
- Description
Step 4 β Import a package¶
Select a package in the catalog and click Import, or use the API:
The import runs the full security pipeline and returns a result:
{
"status": "published",
"package": "nginx",
"version": "1.24.0",
"distribution": "jammy",
"pipeline": {
"antivirus": "clean",
"cve_scan": "no_findings",
"gpg": "unsigned_pass",
"dependencies": "satisfied"
}
}
Batch import¶
To import multiple packages at once, use a shell loop:
PACKAGES=(nginx curl libssl3 openssl)
SOURCE_ID=1
DIST=jammy
for pkg in "${PACKAGES[@]}"; do
echo "Importing $pkg..."
curl -sf -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
http://localhost:8000/import/packages \
-d "{
\"source_id\": $SOURCE_ID,
\"package\": \"$pkg\",
\"distribution\": \"$DIST\"
}"
echo
done
Omit version to import the latest
If version is omitted, Repod imports the latest available version from
the synced index.
Air-gapped environments¶
In air-gapped networks where Repod cannot reach external URLs directly, you can pre-download packages and upload them via the standard upload endpoint:
# On an internet-connected machine
apt-get download nginx
scp nginx_1.24.0-1_amd64.deb repod-server:/tmp/
# On the Repod server β upload the .deb
TOKEN=$(curl -s ... | jq -r .access_token)
curl -X POST -H "Authorization: Bearer $TOKEN" \
-F "file=@/tmp/nginx_1.24.0-1_amd64.deb" \
-F "distribution=jammy" \
http://localhost:8000/upload/
# On an internet-connected machine
dnf download nginx --destdir=/tmp/
scp /tmp/nginx-*.rpm repod-server:/tmp/
# On the Repod server β upload the .rpm
TOKEN=$(curl -s ... | jq -r .access_token)
curl -X POST -H "Authorization: Bearer $TOKEN" \
-F "file=@/tmp/nginx-1.24.0-1.el9.ngx.x86_64.rpm" \
-F "distribution=almalinux9" \
http://localhost:8000/upload/
Troubleshooting¶
Sync returns 0 packages¶
APT: The remote Release file cannot be fetched β check URL, network
access, and whether the source requires authentication.
RPM: The repodata/repomd.xml is unreachable or the SQLite index database
is locked.
Fix a locked SQLite index:
docker exec -u root backend-api \
chown appuser:appuser /repos/package-index/packages.db
docker compose restart backend-api
Import fails with 404 Not Found¶
The package version in the catalog no longer exists on the remote server (removed upstream). Re-sync the index and select a current version.
Package stuck in pending_review¶
The CVE scan found findings matching the review policy. Go to
Security β Review queue, examine the findings, and approve or reject.
GPG key retrieval failed during import¶
The remote package is signed with a key Repod doesn't trust. This is expected for external packages. The package still passes if the GPG check is configured as soft (default behavior).
Scheduled synchronization¶
To keep the index fresh automatically, configure a scheduled sync in Settings β Scheduled tasks or use a cron job:
# Sync all sources daily at 02:00
0 2 * * * curl -sf -X POST \
-H "Authorization: Bearer $REPOD_TOKEN" \
http://localhost:8000/import/sources/1/sync >> /var/log/repod-sync.log 2>&1
Replace $REPOD_TOKEN with a long-lived API token created for the automation
user (admin or maintainer role).