Artifact repositories in 2026: revisit Sonatype Nexus Repository Community, Pulp and Reposilite before you proxy another package registry

Every build in a company depends on a few servers it does not own. A Maven build reaches out to Maven Central, a frontend build pulls hundreds of packages from the npm registry, and a Python job downloads wheels from PyPI. When the internet link or a public registry has a bad day, no team can ship. The same is true for your own libraries: the shared jar that three teams use often lives in a folder on somebody’s laptop, or in a server that was set up years ago and never upgraded.

An artifact repository manager sits between your builds and those public registries. It caches what you download (a proxy repository), stores what you publish (a hosted repository), and gives clients one address for both (a group). It is plumbing, but it holds credentials, decides which packages enter the company, and needs backups and patches like any other server.

We revisit three self-hosted options that are actually maintained in 2026: Sonatype Nexus Repository Community Edition (the free edition of Nexus Repository 3, which replaced Nexus OSS in 2025, with usage limits and its own licence), Pulp (a GPL-licensed, plugin-based content platform from the Pulp community, used heavily in the Red Hat world, with plugins for Maven, npm, Python, RPM, Debian and more) and Reposilite (a small Apache-2.0 Maven repository manager written in Kotlin). We considered swapping the third tool. Artipie is MIT licensed and supports many formats, but its last release was v1.17.16 in April 2024, so we left it in the history section. JFrog Artifactory OSS is free, but it covers Maven, Gradle, Ivy, SBT and generic files only, not npm or PyPI. Reposilite stays because many Java teams only need a good Maven server, and it is the lightest honest answer for them.

There is real news this autumn. Sonatype shipped Nexus Repository 3.97.0 on 14 October 2026, followed quickly by 3.97.1, 3.97.2 and 3.97.3 on 27 October. From 3.97.0 an administrator must acknowledge required base telemetry, and Community Edition has no supported exemption. Sonatype also published a long list of Nexus Repository 3 security advisories this year, the latest on 15 October. In mid October, eight intermediate certificate authorities of the Indian CA eMudhra were found to have weak, recoverable keys; browsers blocked them and eMudhra revoked them, and both Nexus (3.97.2 and the 3.87.3 backport) and Reposilite (3.6.4 to 3.6.6) shipped updates that remove trust in the affected certificates from their images. Pulp released pulpcore 3.123.0 on 21 October and patched several older branches on 23 October, pulp_maven fixed an unauthenticated upload hole in its deploy API in 0.36.0 on 20 October, and pulp_python 3.38.0 on 2 November fixed a cross-site scripting issue in its simple index. Reposilite 3.6.6 came out on 2 November.

This post sits next to our posts on container registries, dependency updates and vulnerability scanners. Container images have their own registries, and we covered Harbor and zot already, so here containers get only a short mention. This post is about language packages: Maven, npm, PyPI and their cousins.

A scenario to keep us honest

We will use one invented company through the post. Kakatiya Ledger Systems is an invented example, not a real business: a Warangal software company that builds core banking, loan and deposit software for urban cooperative banks and cooperative credit societies in Telangana and Andhra Pradesh. It has about 160 people, of whom about 95 write code. The platform team is three people, led by Sravani, who look after GitLab CE, six Jenkins agents, the test servers and the office network.

What they use today:

  • Java: about 40 Spring Boot services and libraries built with Maven, plus one Android field collection app built with Gradle. Shared libraries such as the interest calculation module and the audit logging starter are published to a Nexus Repository OSS 3.38 server that a former engineer set up in 2022 on a VM. It still uses the OrientDB database, nobody has upgraded it, and every settings.xml and Jenkins job uses the same admin password.
  • JavaScript: six React frontends and two Node.js services. They fetch packages straight from the public npm registry. There is a shared component library under the scope @kls, which is currently copied between repositories because nobody set up a private npm registry. The scope is not registered on the public registry.
  • Python: reporting and data migration scripts and one Django admin tool. Developers install from PyPI directly, and a few internal wheels sit in a shared network folder.
  • Network: one 300 Mbps leased line with a smaller broadband line as backup.

What triggered the review: in August a fibre cut took the leased line down for four hours, and every build failed, including an urgent fix for a bank’s interest posting batch. In the same quarter, a cooperative bank’s IT audit asked for the list of third-party components in a release and for proof that builds pull from a controlled source. And when Sravani read Sonatype’s advisories this year, she found that the old Nexus server was affected by several of them, and that its OrientDB database means there is no direct upgrade to current versions.

Sravani’s questions: one tool or more, whether the free Nexus edition fits within its limits, how to get off the old Nexus, whether Pulp or Reposilite can do the job, how people and CI should sign in, how much server it needs, how cleanup and backups work, and how three people can keep it patched.

The short version

  • All three are maintained, but they solve different sizes of problem. Nexus Repository Community Edition covers the most formats with a mature web UI, proxy, hosted and group repositories, and cleanup policies. Pulp covers many formats through plugins and is API-first, built for content management and mirroring as much as for build caching. Reposilite does one thing, Maven, and does it with very little memory.
  • Nexus Community Edition is free, but it is not open source and it has hard limits. Since 3.87.0 (December 2025) the limits are 40,000 total components and 100,000 requests per day. Over either limit, adding new components pauses until usage is back under both. Since 3.97.0 the instance must send base telemetry to Sonatype, and if it cannot for 10 days, it goes read-only. The open-source core in the nexus-public repository supports only Maven, raw and APT.
  • Pulp is GPL-2.0-or-later with no usage limits. It is built from pulpcore plus plugins, runs as API, content and worker processes on PostgreSQL, and is installed most easily as a container. Its Python and RPM plugins are mature. Its Maven and npm plugins are younger and changed a lot in 2026, including a security fix for unauthenticated Maven uploads in October.
  • Reposilite is Apache-2.0, ships as one JAR and Docker images, needs Java 17 or newer, and proxies and hosts Maven repositories with token-based permissions. It does not do npm or PyPI.
  • For Kakatiya we recommend measuring first: a six-week pilot of Nexus Community Edition 3.97.3 on PostgreSQL for two teams, with the Usage Center watched daily, and a parallel Pulp test for npm and PyPI. If the projected usage stays well under the Community Edition limits and the telemetry rule is acceptable, standardise on Nexus. If not, either price Nexus Pro or split the job: Reposilite for Maven and Pulp for npm and Python. Details later.
  • Do not migrate the cache. Migrate the hosted packages and the client settings. What matters is your own libraries, the credentials, and every settings.xml, .npmrc and pip.conf.

Where things stand on 3 November 2026

Sonatype Nexus Repository Community Edition

  • Releases: 3.97.0 on 14 October 2026, 3.97.1 on 20 October, 3.97.2 on 23 October and 3.97.3 on 27 October, according to Sonatype’s release notes. The nexus-public GitHub repository carried tags up to release-3.97.2-02 when we checked. A 3.87 line still receives fixes: 3.87.3 on 28 October backported the eMudhra certificate removal.
  • What 3.97 brought: required base telemetry with an administrator acknowledgement; a new Pro+ edition with malware quarantine and intake policies (it needs Sonatype IQ Server 208 or newer); service account tokens, documented as a Pro and Pro+ feature; an automatic repository health check on proxy repositories; fixes for chained proxies of Ansible Galaxy, Hugging Face, Terraform and Conda; and fixes to cleanup, including “retain last N versions” after the version normalisation change in 3.94, and RubyGems cleanup on PostgreSQL that silently cleaned nothing.
  • Known issues to read before upgrading: on PostgreSQL, versions 3.96.0 to 3.97.0 can grow the audit_events table, and from 3.97.1 audit persistence is off by default. 3.97.0 could fail to start on PostgreSQL databases with a non-English locale; 3.97.1 fixed that. 3.97.1 also fixed an out-of-memory problem in PyPI proxies under many concurrent simple index requests.
  • The edition itself: 3.77.0 (February 2025) renamed Nexus Repository OSS to Community Edition, allowed PostgreSQL and Kubernetes, and brought formats such as Composer, Cargo, Conan v2 and a Hugging Face proxy from Pro. 3.87.0 (December 2025) set the current limits of 40,000 components and 100,000 requests per day, and made Java 21 the minimum.
  • Source: the nexus-public repository on GitHub, under EPL-1.0, created in July 2015, with about 2,700 stars. Its README calls it Nexus Repository Core and says it supports Maven, raw and APT with the embedded H2 database. The Community Edition binary downloaded from Sonatype adds the other formats and PostgreSQL under the Community Edition licence agreement.

Pulp

  • Releases: pulpcore 3.123.0 on 21 October 2026 and 3.123.1 on 23 October, which fixed a distribution cache that could serve the previous repository version. On the same day the project shipped patch releases on several maintained branches, including 3.118.5, 3.105.25, 3.85.34 and 3.73.47. Minor versions arrive almost every week: 3.116 came in August and 3.123 in late October.
  • Plugins relevant here: pulp_maven, pulp_npm and pulp_python, plus pulp_rpm, pulp_deb, pulp_container, pulp_gem, pulp_ansible, pulp_rust, pulp_hugging_face and pulp_file.
  • pulp_python 3.38.0 (2 November 2026) added per-domain keys for attestation verification and fixed a cross-site scripting issue in the simple HTML index (CVE-2026-103871), with fixes also released on older lines (3.36.5, 3.27.8 and 3.19.6).
  • pulp_maven moved from 0.13 in June to 0.37.0 on 27 October 2026. Along the way it auto-added pull-through content to repositories (0.18.0), generated maven-metadata.xml (0.21.0), removed Maven publications (0.23.0, with an action required before upgrading), added role-based access control (0.25.0) and, in 0.36.0 on 20 October, fixed “the Maven deploy API allowing unauthenticated, unauthorized uploads”.
  • pulp_npm had its first non-alpha release, 0.1.0, in February 2025, added pull-through caching in 0.2.0 a week later, gained role-based access control on all viewsets and an npm publish API in 0.10.0 (August 2026), and reached 0.10.2 on 13 October 2026.
  • Source: pulpcore is GPL-2.0-or-later, its repository was created in February 2019, and it has about 625 stars. The project also maintains pulp-cli, the pulp-operator for Kubernetes and the pulp/pulp container images.

Reposilite

  • Releases: 3.6.0 on 11 August 2026 raised the minimum Java version from 11 to 17, moved to Javalin 7, reworked the dashboard with token management in the UI, added a resolution cache for unresolved artifacts and S3 key prefixes, and added an unauthenticated health endpoint. 3.6.4 (23 October) added the eMudhra mitigation to its Docker images. 3.6.6 (2 November) moved the images to a patched Temurin 21.0.13+9, stopped HEAD requests from downloading the artifact, added per-repository file permission settings and an optional time-to-live for cached metadata misses.
  • Scope: Maven repositories only, which also covers Gradle, sbt and other clients of the Maven repository layout.
  • Source: Apache-2.0, repository created in July 2017, about 1,900 stars, mostly maintained by one lead developer with sponsors. 3.0.0 arrived in August 2022.

The first questions to ask

Before comparing features, Sravani should answer these for Kakatiya. The answers decide the tool more than any feature list.

  • Which formats, today and in two years? Maven, npm and PyPI are certain. Ask whether RPM or Debian mirrors for servers, Helm charts, or container images will come later. One tool for everything is simpler to run; two tools that each fit well can be simpler to trust.
  • How big is the cache, really? Count unique package versions across lockfiles and the Maven local repositories of CI agents. A React app’s package-lock.json often lists more than a thousand packages, and every version you have ever downloaded stays in the cache until cleanup removes it.
  • How many requests per day? One npm install can send a request for every package’s metadata and another for every tarball. Multiply by CI builds per day and developers. This number matters for Nexus Community Edition’s daily limit.
  • Can the server talk to the internet? A proxy obviously needs to reach Maven Central and the npm registry, but Nexus Community Edition also needs to reach Sonatype’s telemetry endpoint. A fully air-gapped site changes the answer.
  • Which packages are yours, and which names could be taken? Internal scopes, group IDs and package names must never be fetched from a public registry by mistake. List them.
  • How will people and CI sign in? Local accounts, LDAP, SSO, tokens. Shared admin passwords in build files are what we are trying to end.
  • Who patches, and how fast? All three shipped security fixes this year. If nobody can upgrade within a week of a critical advisory, the server becomes the weakest point in the build.

How each one works

Nexus Repository: one Java application, one database, blob stores

Nexus Repository 3 is a Java application with a web UI and a REST API. It keeps configuration and component metadata in a database, either the embedded H2 or an external PostgreSQL, and keeps the actual files in blob stores, which in Community Edition are file system blob stores. Each repository has a format and a type: proxy (fetches from a remote URL and caches), hosted (you publish to it) or group (one URL that searches several repositories in order). A typical setup is a Maven group made of maven-releases, maven-snapshots and a maven-central proxy, and the same pattern for npm and PyPI.

Proxy repositories have settings for how long to keep cached metadata and components before checking the remote again, and a negative cache that remembers “not found” answers for a while. Routing rules can stop requests for certain paths from going to a remote, which is how you keep internal names from leaking to a public registry. The database tracks components and assets; tasks in the background handle cleanup, compaction of blob stores, rebuilding indexes and similar work.

Since 3.71.0, OrientDB is gone; only H2 and PostgreSQL remain. Since 3.78.0 the download bundle includes a Java runtime, and since 3.87.0 Java 21 is the minimum.

Pulp: pulpcore, plugins, and three kinds of process

Pulp is a Django application. pulpcore provides the common model and each plugin adds a content type. A running Pulp has three kinds of process: the API server (pulpcore-api, Django REST Framework behind gunicorn), the content app (pulpcore-content, an aiohttp server that clients download from and that fetches on-demand content from the remote), and workers (pulpcore-worker) that run tasks such as syncs and publications. Tasks are queued in PostgreSQL. Each worker runs one task at a time, and tasks that touch the same resource run one after another.

The vocabulary is different from Nexus and worth learning once:

  • A remote describes an upstream source, such as PyPI or Maven Central, and its sync policy: immediate downloads everything during sync, on_demand records metadata and downloads files only when a client asks.
  • A repository holds content, and every change creates a new repository version. You can roll a distribution back to an older version. This is Pulp’s strongest idea.
  • A distribution publishes a repository version, or a remote for pull-through caching, at a URL under the content app.
  • Content guards protect what a distribution serves, and domains let one Pulp host separate tenants.

For language packages, Pulp’s model is usually pull-through: a distribution with a remote serves what is already in the repository and fetches the rest from upstream. The pulp_python docs say remotes default to on_demand because syncing all of PyPI needs terabytes, and they point to pull-through caching as the alternative. Since pulp_maven 0.18.0 and in pulp_npm, content fetched through the cache can be added to a repository, so you can see and freeze what was used.

Reposilite: one JAR, one working directory

Reposilite is a Kotlin application on Javalin, distributed as a single “all” JAR (about 58 MiB for 3.6.6) and as Docker images. It keeps its local configuration in configuration.cdn, its shared configuration (repositories, authentication, proxies) in a JSON file or the database, its database in SQLite by default, and its artifacts under repositories/ in the working directory or in S3-compatible storage.

The generated configuration lists MariaDB and SQLite as supported, and MySQL, PostgreSQL and H2 as experimental, “not covered with tests”. A fresh instance creates three repositories: releases and snapshots (public read) and private (private read). Each repository can list proxied upstreams, such as Maven Central, with options to store fetched files locally, limit which group IDs and file extensions may be fetched, and set timeouts. Access is controlled by access tokens, each with permissions on routes such as /releases for read or write.

Formats supported

  • Nexus Community Edition: Sonatype’s format list covers Alpine, Ansible, APT, CocoaPods, Composer, Conan, Conda, Docker, Git LFS, Go (hosted since 3.93), Helm, Hugging Face, Maven, npm, NuGet, OCI, p2, Pub, PyPI, R, raw, RubyGems, Cargo, Swift, Terraform and Yum. Bower is listed but is not supported on the H2 or PostgreSQL databases. Some formats, such as NuGet v2, Cargo and Hugging Face, need PostgreSQL in Community Edition. Check each format’s page for proxy, hosted and group support; not every format has all three.
  • Pulp: through plugins, Maven, npm, Python, RPM, Debian, container images, Ruby gems, Ansible content, Rust crates, Hugging Face models and plain files. Maturity differs. The RPM, container and Python plugins are long established; the Maven and npm plugins are young and were changing quickly through 2026.
  • Reposilite: Maven repository layout only, which serves Maven, Gradle, sbt, Leiningen and other clients of that layout.

For Kakatiya, all three formats it needs today are covered by Nexus and by Pulp. Reposilite covers only the Java side.

Security, sign-in and permissions

Who can sign in, and how

  • Nexus Community Edition has local users and LDAP. SAML and OIDC single sign-on are Pro features, according to Sonatype’s edition comparison. User tokens let people use a token instead of their password in build tools; Sonatype’s page on user tokens does not state the edition, and we could not verify whether Community Edition includes them, so test it in your pilot. Service account tokens, new in 3.97.0, are documented as Pro and Pro+ only. Anonymous access is a global setting; turn it off unless you have a reason.
  • Pulp authenticates its REST API with Basic and session authentication against its own users by default, and can be extended through Django and Django REST Framework, for example with an external identity provider or certificates in front. Every API URL except /pulp/api/v3/status/ needs authentication. Access to content is controlled separately, with content guards on distributions. Each plugin defines roles, such as the permission to modify an npm repository that publishing needs in pulp_npm.
  • Reposilite uses access tokens. A token has a name, a secret and a set of route permissions, and since 3.6.0 tokens can be managed in the dashboard. LDAP is available in the shared configuration. Brute force protection exists in the configuration but was off by default in the instance we started.

Permissions in practice

The pattern is the same everywhere: anonymous or read-only for proxies, write for CI on release repositories, delete for almost nobody, and admin for two named people. In Nexus that means roles built from privileges such as nx-repository-view-maven2-maven-releases-add. In Pulp it means object roles on repositories and distributions. In Reposilite it means tokens with route permissions.

Two rules matter more than the tool:

  • Release repositories should not allow redeploying the same version. Nexus hosted repositories have a deployment policy; set “disable redeploy” for releases. Reposilite’s redeployment setting was false by default in our drill, and a second upload of the same file returned HTTP 409. In Pulp, repository versions keep the history, but check what your plugin version allows.
  • Internal names must not be resolved from public registries. Use routing rules in Nexus, allowedGroups on Reposilite proxies, and the include and exclude lists on pulp_python remotes; for other Pulp plugins, check what the remote can filter in your version. For npm, register your scope on the public registry or make sure the client resolves it only from your server. This is how dependency confusion attacks are stopped.

The advisory record

  • Nexus Repository 3: Sonatype’s security advisories page listed 30 advisories for Nexus Repository 3 dated between 11 May and 15 October 2026 when we read it. Most need an authenticated user with a specific privilege, which is a reminder that admin and near-admin privileges are dangerous in themselves. Examples: remote code execution through a crafted licence file by a user with the licensing privilege (CVE-2026-10748, fixed in 3.92.0); code execution through the data store API’s connection settings on H2 by a user who can update data stores (CVE-2026-17603, affecting 3.20.0 to 3.94.x, fixed in 3.95.0); privilege escalation through role management (CVE-2026-97712, rated High, affecting 3.0.0 to 3.96.4, fixed in 3.97.0); and an unauthenticated information leak through an ExtDirect method that reveals whether Java classes exist (CVE-2026-97666, fixed in 3.97.0, with a suggested mitigation of requiring authentication for /service/extdirect at the reverse proxy). Others covered server-side request forgery through webhooks, redirects and certificate retrieval, weak randomness in API key generation, stored cross-site scripting, a script execution setting that was not enforced (CVE-2026-77124, fixed in 3.96.0) and webhook secret disclosure. For the advisories we read, Sonatype said it was not aware of exploitation.
  • Pulp: we found no GitHub security advisories listed for pulpcore, pulp_python or pulp_maven. That does not mean no security fixes. The pulp_python XSS (CVE-2026-103871) was announced in release notes, and the pulp_maven unauthenticated deploy fix in 0.36.0 is a serious one if you exposed the deploy API. With Pulp, read the changelog of every plugin you run.
  • Reposilite: GitHub lists a reflected XSS in the directory listing (CVE-2026-53526, published 13 August 2026, fixed in 3.6.0), and three issues in 2024, including a high-severity path traversal through the javadoc endpoint (CVE-2024-36117), all fixed in 3.5.12.
  • Certificates: the eMudhra incident is a good example of a risk that does not show up as a CVE in your repository manager. Java applications use their own trust store. Nexus fixed it in 3.97.2 and 3.87.3, Reposilite in its Docker images from 3.6.4, and if you run Reposilite’s JAR on your own Java, you must update that Java yourself. Red Hat tracked the issue in its bulletin RHSB-2026-012.

Build credentials are secrets

A token that can publish to maven-releases is as powerful as a commit to every service that depends on that library. Keep publishing tokens in the CI secret store, not in settings.xml files checked into repositories, give each pipeline its own token, and rotate them when people leave. Our post on secret scanning covers how to find the ones already committed.

Performance and capacity

We did not run load tests on any of the three. Treat every sizing figure here as the vendor’s own guidance, and our small drill result as a single observation on a shared box.

  • Nexus Repository: Sonatype’s system requirements describe profiles. In Sonatype’s guidance, an extra small deployment handles about 100 requests per second sustained, with spikes of 150 to 200, on one node with 4 vCPU and 16 GiB of memory; a small deployment handles about 500 requests per second with 8 vCPU and 32 GiB; a medium one about 4,000 requests per second across three nodes, which needs Pro. Sonatype says the embedded H2 database is suited to up to 200,000 requests per day or 100,000 components, that containers are not supported with H2, and that PostgreSQL is recommended for production. Other vendor rules worth copying into your runbook: Java 21; do not run as root; raise the open file limit; give Nexus up to two-thirds of the machine’s memory; do not run antivirus scanners over its directories; keep at least 4 GB of free disk at all times, or the database goes read-only; NFSv4 is acceptable for blob stores but not for the database. The application itself is about 390 MB on disk, and Sonatype notes that Docker and Maven repositories can easily reach 500 GB.
  • Community Edition limits are far below the hardware: 100,000 requests per day is just over one request per second on average. A single XS server can serve a hundred times that. For Community Edition, the licence limit, not the hardware, is the capacity planning number.
  • Pulp: we did not find official sizing guidance. Capacity depends on the number of API, content and worker processes, PostgreSQL, and storage. The content app serves downloads, and the API and workers can be scaled separately in the Compose and Kubernetes setups. Plan for PostgreSQL like any production database, and for storage that grows with every repository version you keep.
  • Reposilite: the 3.6 release notes give minimal requirements of Java 17 or newer and 32 MB or more of memory. An older guide page still mentions Java 11 to 18 and a 20 MB minimum, so it is out of date. In our drill, the process reported 22.61 MB of memory used after a start of 0.40 seconds, but the whole Java process used about 227 MiB of resident memory with a heap cap of 96 MB, because a JVM needs memory beyond its heap. Plan by the process, not by the heap.

For Kakatiya, the honest capacity question is not CPU. It is the Community Edition limits for Nexus, and disk for everything. Ninety-five developers and six CI agents building Maven, npm and Python projects can generate a lot of requests on a busy day, and the npm cache alone can hold many thousands of package versions. Measure it before choosing.

Licences and editions

  • Nexus Repository Community Edition is free to use under Sonatype’s Community Edition licence agreement, which must be accepted in the setup wizard or through the EULA REST API before users can download or upload. It is not open source. The open-source part is Nexus Repository Core in nexus-public under EPL-1.0, which builds with Java 21 and supports Maven, raw and APT only. The limits since 3.87.0 are 40,000 total components and 100,000 requests per day. When usage passes either limit, the instance stops accepting new components until usage is below both, and existing components can still be downloaded. The Usage Center shows the counts, which can take up to an hour to update. A user in GitHub issue 883 on nexus-public reported that the limits were 100,000 components and 200,000 requests a day before 3.87.0; we did not find that earlier figure in Sonatype’s current documents. As we read the documents, a proxy that needs to cache a version it has never seen is adding a component, so a build could fail while the instance is over the limit. We did not test this.
  • Telemetry: from 3.97.0 an administrator must acknowledge base telemetry. Community Edition has a 10-day grace period and Pro 45 days; after that, an instance that cannot send telemetry goes read-only. Sonatype says Community Edition has no supported telemetry exemption and points disconnected sites to its commercial options. Sonatype describes the data as anonymous, without repository or component names. The endpoints for Community Edition are under nxrm.telemetry.sonatype.com. If your outbound traffic goes through a proxy that inspects TLS, add its certificate to the Nexus trust store. The status check GET /service/rest/v1/status/check reports “Baseline Telemetry”, but can return HTTP 200 while a check is unhealthy, so parse the body in monitoring.
  • Nexus Pro and Pro+: from Sonatype’s edition page, Community Edition is self-hosted only and lacks high availability, SAML and OIDC single sign-on, cloud blob stores (S3, Azure and Google Cloud Storage), disaster recovery replication, deletion rollback and FIPS mode. Pro+ adds malware quarantine and intake policies. We did not find a public list price for Pro; ask Sonatype for a quote.
  • Pulp is GPL-2.0-or-later, with the plugins under GPL as well. Running it internally, unchanged or changed, creates no duty to publish code. There is no paid edition and no usage limit. Commercial support comes through products built on Pulp, which are outside the scope of this post.
  • Reposilite is Apache-2.0. There is no paid edition. The project accepts sponsorship.

For Kakatiya: Pulp and Reposilite have no licence questions for internal use. Nexus Community Edition is free but conditional, on limits and on telemetry. Ask legal to read the Community Edition agreement once, and ask the security team whether outbound telemetry is acceptable for a company that builds banking software.

Operations and day two

Install

  • Nexus: download the Community Edition bundle for Linux, which includes a Java runtime, unpack it, create a dedicated nexus user, set the data directory (sonatype-work) on a separate disk, and run it as a systemd service, or use the official sonatype/nexus3 image with PostgreSQL (containers are not supported with H2). On first start, read the generated admin password from admin.password in the data directory, change it, accept the licence, decide on anonymous access and acknowledge telemetry. Put a reverse proxy with TLS in front.
  • Pulp: the documented quick start is the single pulp/pulp container image, with directories for settings, pulp_storage and the PostgreSQL data mounted from the host. The settings directory holds the database encryption key, so treat it as a secret and back it up. Set a unique SECRET_KEY, run pulpcore-manager check --deploy, and set the admin password with pulpcore-manager reset-admin-password. A Compose setup lets you scale API, content and worker processes, and the pulp-operator covers Kubernetes, including backup and restore resources. Day-to-day work is through pulp-cli or the API; a web UI exists as a separate project.
  • Reposilite: run the JAR with Java 17 or newer, java -jar reposilite-3.6.6-all.jar -wd /srv/reposilite -h 127.0.0.1 -p 8080, or use the Docker image or Helm chart. The first start writes configuration.cdn. Create the first token with --token name:secret on the command line, which gives a temporary token with all permissions, use it to create a permanent admin token in the dashboard, and then remove the flag. Note that the default hostname in the configuration is 0.0.0.0, which listens on every interface.

Upgrades

  • Nexus: since 3.77.0 you can upgrade directly from 3.71.0 or later. Older installations on OrientDB must first reach the 3.70.x line, migrate to H2 or PostgreSQL there, and then upgrade; OrientDB support was officially sunset on 9 January 2026. Nexus 2 must go to 3.76.0 first. Read the known issues for every version. Recent ones were serious: in 3.83.0 to 3.89.1, the Verify and Repair or Data Repair Plan tasks could delete valid assets (fixed in 3.90.0, and the task was disabled in 3.87.2), and 3.87.0 changed the S3 client library in a way that affected some non-AWS S3 storage. Take a database and blob store backup before every upgrade.
  • Pulp: pulpcore and each plugin have their own versions and compatibility ranges. Upgrade them together in a test instance, run pulpcore-manager migrate, and read every plugin’s changelog for “action required” notes, such as pulp_maven 0.23.0, which needed distributions to point at repositories before upgrading. Pulp patches several branches at once, so you can stay on a maintained branch rather than chasing every weekly minor.
  • Reposilite: replace the JAR or image, keep the working directory, and let the database migrations run at start. The 3.6 line needs Java 17, and the JAR uses whatever Java you give it, so plan Java updates too.

Backups

  • Nexus on PostgreSQL: back up the database with your normal PostgreSQL tools and the blob store directories, at about the same time, since the database points to blobs. Back up the node ID and the etc configuration in the data directory as well. On H2, Sonatype provides the “Admin - Backup H2 Database” task, which you run before copying the blob stores. Our post on PostgreSQL backups covers the database side.
  • Pulp: back up PostgreSQL, the pulp_storage directory or bucket, and the settings directory with the encryption key. Without that key, encrypted fields in the database cannot be read after a restore.
  • Reposilite: back up the working directory: repositories/, the database file (or the external database), and both configuration files. If artifacts live in S3, back up the bucket.

What to back up and what to skip: hosted repositories are the real data; proxy caches can be rebuilt from upstream, though a cache of a version that has since disappeared upstream is worth more than it looks. Decide per repository.

Cleanup and storage

  • Nexus: cleanup policies select components by age, last download, release or pre-release, and asset name patterns. A “retain the last N versions” option exists in recent versions; check whether your edition includes it, because we did not confirm that for Community Edition. A policy runs through the cleanup task and only soft-deletes in a file blob store; the “Compact blob store” task frees the disk space. Test a policy with its preview before attaching it, especially after the 2026 fixes to “retain last N versions”.
  • Pulp: every change makes a repository version, so set retain_repo_versions on repositories where you do not need history, remove orphans with the orphan cleanup task, and use the reclaim disk space task for on-demand content you no longer want to keep locally.
  • Reposilite: storage per repository has an optional quota, and old snapshots or cached files need your own cleanup routine. We did not find a built-in age-based cleanup policy in what we read; check the documentation for your version before relying on one.

Migration

From an old Nexus Repository OSS

This is Kakatiya’s real case. A 3.38 server on OrientDB cannot jump to 3.97. The documented path is: back up, upgrade to the 3.70.x line, run the database migration from OrientDB to H2 or PostgreSQL, then upgrade to the current release. If the server holds only a few hundred internal artifacts, a simpler and cleaner option is to build a new instance and copy the hosted content across with a script that downloads each artifact and uploads it through the REST API or mvn deploy:deploy-file. You lose upload history, but you also leave behind the shared admin password and years of default settings.

From Nexus to Reposilite or Pulp for Maven

Both are standard Maven repositories, so the move is mostly copying files in the Maven layout and changing URLs. For Reposilite with file system storage, the files can, in principle, be placed under the repository directory with their checksum files; we did not test a bulk copy, so deploy a sample through the API first and compare. For pulp_maven, upload or deploy into a repository and point a distribution at it. Do not copy proxy caches; let them fill again.

npm and Python

For npm, the private packages need to be republished to the new hosted registry with npm publish --registry, and every .npmrc needs the new registry and scope lines. For Python, internal wheels can be uploaded with twine to Nexus or Pulp. Lockfiles that record resolved URLs, such as package-lock.json, may hold the old registry address; plan to regenerate or rewrite them.

The client side

The part that takes the longest is not the server. It is the dozens of settings.xml mirrors, Gradle repository blocks, .npmrc files, pip.conf index URLs and CI variables. Put the URLs in one place per tool, such as a shared Maven settings file managed by CI and a global .npmrc on agents, and keep a list of every repository and pipeline you changed. Our post on self-hosted CI covers where those agent settings live.

Side by side

Best fit

  • Nexus Community Edition: small and medium teams with many formats who want one server and a mature UI, and who fit within 40,000 components and 100,000 requests a day and can send telemetry.
  • Pulp: teams that want an open-source, unlimited, API-driven platform, especially those who also mirror RPM or Debian packages, need repository versions and rollback, or run several tenants.
  • Reposilite: Java teams that need a light, private Maven repository and a cache of Maven Central, on minimal hardware.

Sign-in and permissions

  • Nexus: local users and LDAP in Community Edition, SSO in Pro, fine-grained privileges and roles.
  • Pulp: Basic and session authentication by default, Django-extensible, role-based access per object, content guards.
  • Reposilite: access tokens with route permissions, LDAP option.

Operations

  • Nexus: one Java process plus PostgreSQL, cleanup policies and tasks in the UI, a known upgrade path, frequent releases with known issues to read.
  • Pulp: API, content and worker processes plus PostgreSQL, best run in containers, weekly minors with maintained branches, most work through the CLI or API.
  • Reposilite: one JAR or container and a working directory, very small footprint, a one-maintainer project.

A worked plan for Kakatiya

Month 1: count, protect and freeze

  • Make an inventory: every hosted repository on the old Nexus and how many artifacts it holds, every internal npm package and Python wheel, and every place a registry URL is configured.
  • Measure demand. Count unique package versions in the lockfiles of the six frontends and two Node.js services, run pip freeze in the Python projects, and look at the Maven local repositories on the CI agents. Estimate requests per day from the number of builds per day and the size of a typical install.
  • Protect what exists. Take a VM snapshot and a copy of the old Nexus data directory, change the shared admin password, create separate read and deploy accounts, and restrict the server to the office network and VPN. Register the @kls scope on the public npm registry, or at least make sure no client resolves it from there.
  • Freeze new manual uploads to the old server except through CI.

Months 2 and 3: pilot two candidates

  • Build a new Nexus Community Edition 3.97.3 instance on a 4 vCPU, 16 GiB VM (Sonatype’s extra small profile) with a separate PostgreSQL, behind the existing reverse proxy, office and VPN only. Create proxy, hosted and group repositories for Maven, npm and PyPI, turn off anonymous access, set release repositories to disable redeploy, and add routing rules for internal group IDs and the @kls scope.
  • Acknowledge telemetry only after security agrees, and add the status check, with body parsing, to monitoring.
  • Move two teams, one Java team and one frontend team, and their CI jobs to the new instance. Watch the Usage Center every day and note component counts and requests per day.
  • In parallel, run a Pulp test instance with pulp_npm and pulp_python as pull-through caches for the same frontend team and one Python project, using the container image with persistent settings, storage and PostgreSQL directories. Note what is easy and what needs scripting.
  • Copy the internal Maven libraries from the old Nexus to the new hosted repository with a script, and check checksums for a sample.

Month 4: decide with numbers

  • If two teams use less than about a third of the Community Edition limits, so that the whole company would stay comfortably below them with room to grow, and security accepts the telemetry, standardise on Nexus Community Edition. This is our judgement of a safe margin, not a Sonatype figure.
  • If the numbers come close to the limits or the telemetry is not acceptable, choose between a Nexus Pro quote and a split setup: Reposilite 3.6 for Maven (hosted plus a Maven Central proxy, with tokens for CI) and Pulp for npm and Python. The split setup costs nothing in licences but means two tools to patch and back up.

Months 5 and 6: move everyone and retire the old server

  • Move the remaining teams one at a time, with a shared Maven settings file and a global .npmrc and pip.conf on CI agents.
  • Test a restore of the database and blob stores, or the Pulp and Reposilite equivalents, on a second VM.
  • Set cleanup policies for proxy caches and snapshots, with previews checked first.
  • Switch the old Nexus to read-only for one month, then shut it down and keep the final backup.

What we do not recommend for Kakatiya

  • Exposing any of the three servers to the internet. Cooperative bank customers do not need it, and the advisory record shows that the web UI and API are where problems are found.
  • Upgrading the 3.38 server in place across OrientDB and many major versions as the first step. Build new and copy hosted content, unless there is history you must keep.
  • Running Nexus Community Edition on H2 in a container, which Sonatype does not support, or on H2 at all for a company of this size.
  • Mirroring all of PyPI or the npm registry with an immediate sync policy in Pulp. Use pull-through caching.
  • Using the latest image tag for any of them.

When not to adopt each

  • Do not pick Nexus Community Edition if your usage is near 40,000 components or 100,000 requests a day, if the server cannot send telemetry to Sonatype, if you need SSO with SAML or OIDC without paying, or if your policy requires OSI open-source software.
  • Do not pick Pulp if your team wants a point-and-click UI for daily work, cannot run a multi-process Django application with PostgreSQL, or needs a format whose plugin is still changing quickly and you cannot test each upgrade.
  • Do not pick Reposilite if you need anything other than Maven, or if a project led mainly by one maintainer does not meet your risk policy for a build-critical server.
  • Do not self-host at all if nobody owns patching within a week of a critical advisory, nobody tests restores, and the builds can tolerate reaching public registries directly. For very small teams, a hosted registry service, or the package registry in a Git forge you already run, may be enough.

A short history

  • Nexus: Sonatype’s Nexus started in the late 2000s as a Maven repository manager, and Nexus 2 became a common choice for Java teams. Nexus Repository 3 rewrote the product with an OrientDB database and added many formats. The nexus-public repository was created in July 2015. In the 2020s Sonatype moved Nexus 3 to H2 and PostgreSQL, ended OrientDB support with the 3.70.x line, renamed OSS to Community Edition in 3.77.0 in February 2025 with PostgreSQL allowed and usage limits, tightened the limits in 3.87.0 in December 2025, and made base telemetry mandatory in 3.97.0 in October 2026.
  • Pulp: Pulp began at Red Hat as a tool to manage software repositories, mainly RPM, and Pulp 2 was part of Red Hat Satellite and similar products. Pulp 3 is a rewrite on Django with pulpcore and plugins; the pulpcore repository was created in February 2019. Over the years it added plugins for containers, Python, Ansible, Debian and, more recently, Maven, npm, Rust and Hugging Face.
  • Reposilite: the repository was created in July 2017 by its lead developer as a light Maven repository. 3.0.0 in August 2022 rewrote much of it in Kotlin on Javalin with a new dashboard, and 3.6.0 in August 2026 moved to Java 17 and Javalin 7.
  • Others we looked at: Artipie (MIT) supports many formats, but its last release, v1.17.16, was in April 2024, and commits stopped in early 2025. JFrog Artifactory OSS is free but limited to Maven, Gradle, Ivy, SBT and generic repositories. GitLab, Gitea and Forgejo have package registries that host your own packages well; check their proxy support per format before using one as a cache, which we did not test for this post.

A simple decision guide

  • Do you need Maven, npm and PyPI in one server with a UI, and are you well below 40,000 components and 100,000 requests a day, with outbound telemetry allowed? Choose Nexus Community Edition on PostgreSQL.
  • Are you above those numbers, or need SSO, high availability or cloud blob storage, and have a budget? Get a quote for Nexus Pro.
  • Do you need an open-source, unlimited platform, especially with RPM or Debian mirrors, repository versions or multi-tenancy, and is your team comfortable with APIs and containers? Choose Pulp.
  • Do you only need Maven, on small hardware, with a simple token model? Choose Reposilite.
  • Is nobody available to patch and restore? Do not self-host yet.

Checklist before go-live

  • Inventory of hosted repositories, internal package names and every client configuration that points to a registry.
  • Measured component count and requests per day, with a projection for two years.
  • Admin password changed, anonymous access off, and at least two named admins.
  • Separate read and publish credentials, publish tokens only in the CI secret store.
  • Release repositories set to block redeploys of an existing version.
  • Internal names protected from public resolution: routing rules, allowed groups or remote filters, and the npm scope registered.
  • Server reachable only from the office, VPN and CI network, with TLS at the reverse proxy.
  • Java trust store current, including the eMudhra removal, and the image or JRE version recorded.
  • Telemetry decision written down for Nexus, and the status check in monitoring.
  • Cleanup policies previewed and scheduled, and disk alerts set well above the 4 GB Nexus minimum.
  • Database, blob store or storage, and configuration backed up, and one restore tested on a second machine.
  • Advisory feeds and changelogs subscribed for the server and every Pulp plugin you run, with an upgrade slot booked every month plus any security release.

Common mistakes

  • Treating the cache as disposable and the server as unimportant. When the server is down, every build is down. Monitor it like production.
  • One shared admin password in every build file. It ends up in Git, in logs and in old laptops. Use per-pipeline tokens.
  • Leaving internal names resolvable from public registries. This is the opening for dependency confusion.
  • Allowing redeploys on release repositories. A release that changes after it is published breaks reproducible builds and audits.
  • Skipping known issues in release notes. The 2026 Nexus releases had issues that could grow a table without limit or delete assets during repair tasks. Read before you upgrade.
  • Updating the application but not its Java. The eMudhra case showed that a trust store can need a fix even when the application has none.

Hands-on check: what we ran and what we did not

We kept this check small, user-level and inside /workspace/revisit/drill109 on our shared Linux box, on 3 November 2026 between about 2:26 and 2:31 AM IST. We did not use Docker, install system packages or start services. That ruled out Nexus and Pulp, which both need Docker or a PostgreSQL server in a sensible setup, so we did not run Nexus or Pulp for this post, and we did not test npm or PyPI clients, LDAP, backups or restores.

What we did with Reposilite:

  • Downloaded the 3.6.6 all-in-one JAR (60,332,439 bytes) from the project’s own Maven repository and checked it against the published SHA-256; it matched. The JAR carries its licence files under META-INF.
  • Ran it with a user-level Temurin 21.0.12.1 that was already on the box from an earlier drill, with a 96 MB heap, bound to 127.0.0.1 on a high port, with a temporary token from --token and the default SQLite database. This Java build is older than the patched 21.0.13+9 with the eMudhra change; that was acceptable for a loopback test and would not be for production.
  • Read the generated defaults: hostname 0.0.0.0 and port 8080 in the configuration, SQLite, brute force protection disabled, releases and snapshots public, private private, redeployment off, stored file permissions 600, 12 web threads and 4 IO threads.
  • Added a central repository proxying Maven Central with local storage. The health endpoint returned 200. The first fetch of the commons-lang3 3.17.0 jar took 0.21 seconds and the second 0.008 seconds, served from local storage; its SHA-1 matched Central’s. An absent artifact returned 404.
  • Tested permissions: an upload without a token or with a wrong token returned 401, with the right token 200, and a second upload of the same release file 409. Anonymous reads from the public repository returned 200, from private 401, and with the token 200.
  • Measured about 227 MiB of resident memory for the Java process, against the 22.61 MB the application reported at start.
  • Stopped the process, confirmed the port was free, and deleted the cached repository files. The notes are in NOTES.txt in the drill folder.

This proves only that Reposilite 3.6.6 starts quickly, caches Maven Central, and enforces its token and redeploy rules in a default setup. It says nothing about load, about Nexus or Pulp, or about restores.

Unlearn and re-learn

  • Unlearn: “Nexus OSS is open source and free forever.” Re-learn: Community Edition is free under Sonatype’s terms, with limits on components and requests and required telemetry; the open-source core covers only Maven, raw and APT.
  • Unlearn: “The repository manager is just a cache.” Re-learn: it holds your own releases and publish credentials, and decides which names come from where; back it up and lock it down.
  • Unlearn: “One tool must do every format.” Re-learn: two small tools that each fit can be easier to trust than one big one near its limits, as long as someone owns both.
  • Unlearn: “Patch the app and you are done.” Re-learn: the Java runtime and its trust store are part of the server, as the eMudhra case showed.

Sources

comments powered by Disqus

Releted Posts

No-code databases in 2026: revisit NocoDB, Baserow and Teable before you move another team spreadsheet off Airtable

Almost every company has one spreadsheet that quietly became a database. It started as a list of suppliers or a dispatch tracker in Google Sheets.

Read more

Self-hosted project tracking in 2026: revisit Plane, OpenProject and Redmine before you move another backlog off Jira

Many Indian software teams did not choose Jira so much as inherit it. Somebody set up a Jira Server licence in 2016, it moved to Data Center when Server ended, and ten years later it holds every bug, every sprint, every customer escalation and half the reasons behind old design decisions.

Read more

Self-hosted wikis in 2026: revisit BookStack, Wiki.js and Outline before you write another runbook in a shared drive

Ask any support engineer in a growing Indian company where the runbook for a failed nightly job lives, and you will usually get three answers.

Read more