Setting Up a Private Apt/Yum Repository for Internal Packages
When your organization has custom packages—custom nginx builds with modules, internal monitoring agents, patched libraries—they need to be distributed across servers. Manually copying .deb/.rpm via scp doesn't scale: versions diverge, updates are missed, and there's no central version control. A private repository solves it: apt install internal-agent or dnf update nginx-custom gives each server the latest signed version.
We, as practicing DevOps engineers with 10+ years of experience, set up such repositories turnkey. Our certified specialists (Kubernetes, AWS, Linux) ensure stability and security—from GPG signing to automated CI/CD publishing. Contact us to assess your project in one day. Over 5 years, we have deployed more than 50 repositories for clients in finance and telecom.
Why Use a Private Repository?
- Versioning and rollbacks: maintain version history, easily roll back if issues arise.
- Security: GPG signing prevents substitution; access is limited via RBAC.
- Automation: CI/CD can publish packages on every tag, and Ansible can update servers.
- Scalability: the repository can run on a dedicated server or in the cloud, serving hundreds of machines.
How to Set Up an Apt Repository with Aptly?
aptly is a tool for managing Debian/Ubuntu repositories. It can sign, snapshot, and publish via HTTP. Deployment takes 30 minutes.
apt install aptly gnupg
# Create GPG key for signing
gpg --batch --gen-key <<EOF
Key-Type: RSA
Key-Length: 4096
Name-Real: Internal Repo
Name-Email: [email protected]
Expire-Date: 0
%no-protection
EOF
gpg --export --armor [email protected] > /etc/apt/trusted.gpg.d/internal-repo.asc aptly repo create -distribution=jammy -component=main internal
aptly repo add internal /path/to/package_1.0_amd64.deb
aptly publish repo internal filesystem:public:jammyServing via Nginx:
server {
listen 80;
server_name repo.internal.example.com;
root /var/www/aptly/public;
autoindex on;
location / {
try_files $uri $uri/ =404;
}
}On the client:
deb [signed-by=/etc/apt/trusted.gpg.d/internal-repo.asc] http://repo.internal.example.com jammy main
apt update && apt install internal-agent How to Set Up a YUM/DNF Repository with createrepo?
For RHEL/CentOS/AlmaLinux, use createrepo_c for fast metadata generation:
dnf install createrepo_c gpg
mkdir -p /var/www/repos/el9/x86_64/Packages
cp internal-agent-1.0.x86_64.rpm /var/www/repos/el9/x86_64/Packages/
createrepo_c /var/www/repos/el9/x86_64/
createrepo_c --update /var/www/repos/el9/x86_64/ # when adding packagesSigning:
gpg --detach-sign --armor /var/www/repos/el9/x86_64/repodata/repomd.xml Client: /etc/yum.repos.d/internal.repo:
[internal]
name=Internal Repository
baseurl=http://repo.internal.example.com/el9/x86_64/
enabled=1
gpgcheck=1
gpgkey=http://repo.internal.example.com/RPM-GPG-KEY-Internal
What About Nexus Repository Manager as a Universal Solution?
If you need a repository with a web UI, access control, and support for multiple formats (apt, yum, Maven, npm, Docker), use Nexus OSS. Run in Docker:
---
services:
nexus:
image: sonatype/nexus3:latest
ports:
- "8081:8081"
volumes:
- nexus-data:/nexus-data
environment:
INSTALL4J_ADD_VM_PARAMS: "-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g"
---Uploading a package:
curl -u admin:password --upload-file package_1.0_amd64.deb \
"http://nexus.internal:8081/repository/apt-internal/" Tool Comparison Table
| Criteria | Aptly | createrepo | Nexus OSS |
|---|---|---|---|
| Formats | Debian/Ubuntu | RHEL/CentOS | Apt, Yum, Maven, npm, Docker |
| Web UI | No | No | Yes |
| Access control | Via Nginx | Via Nginx | RBAC, LDAP, OIDC |
| Snapshot support | Yes | No | Yes |
| CI/CD integration | REST API | SCP/rsync | REST API |
For two distros (Ubuntu and CentOS), you can run Aptly and createrepo on the same server. If you need versatility, Nexus is a better choice: it saves up to 60% administration time.
How to Automate Publishing with CI/CD?
The ideal workflow: CI/CD builds the package, signs it, and publishes to the repository. Clients receive updates via standard apt upgrade or Ansible.
Example for GitLab CI:
---
publish:
stage: deploy
script:
- dpkg-buildpackage -us -uc -b
- curl -u ${NEXUS_USER}:${NEXUS_PASS} \
--upload-file ../internal-agent_*.deb \
"${NEXUS_URL}/repository/apt-internal/"
only:
- tags
We set up such pipelines in 1–2 days. You can also trigger Ansible playbooks to update packages on servers after publishing.
What's Included
- Infrastructure audit and tool selection.
- Repository deployment (Aptly/createrepo/Nexus) with GPG signing.
- Nginx or reverse proxy configuration for distribution.
- Connecting target servers to the repository (via Ansible).
- CI/CD pipeline for automated publishing.
- Documentation and team training (runbook).
- 30-day warranty support.
Common Mistakes When Setting Up a Repository
- Forgetting to add the GPG key on clients → GPG check failed error.
- Not enabling Nginx autoindex for package listing.
- Using
--allow-unauthenticated— a security hole. - Not creating snapshots before updates → rollbacks impossible.
Timelines and How to Start
| Stage | Duration |
|---|---|
| Simple repository (Aptly/createrepo) | 1–2 days |
| Nexus with CI/CD integration | 3–5 days |
| Documentation and training | +1 day |
Pricing is individual — depends on number of distros, servers, and automation complexity. We'll assess your project in one day. Get a consultation by contacting us.
Security and Availability
An internal package repository is critical infrastructure: if it goes down, apt upgrade on hundreds of servers fails. We set up availability monitoring via Prometheus blackbox exporter and a backup mirror for fault tolerance.
GPG signing is mandatory: clients verify the digital signature before installation, preventing package substitution even if the transport is compromised. GPG key rotation is scheduled and automated via Ansible.
Contact us — we'll assess your project in 1 day and propose the best solution for your infrastructure.







