☰
Nexus 3.24搭建Maven与NPM私服:安装配置与避坑指南
2026/10/12 6:33:39 网站建设 项目流程

简介:nexus-3.24.0-02-unix.tar.gz 是 Sonatype 公司 Nexus Repository Manager 3.24.0-02 版本的 Unix/Linux 安装包,面向 Java 开发者、Maven/Gradle 用户以及需要统一管理 NPM、NuGet 等制品的团队,用于搭建私有软件仓库与代理仓库,解决依赖下载缓慢、制品分散与权限管理问题。资源包约 149.69MB,解压后主要包含 nexus-3.24.0-02 主程序目录(含可执行文件、配置与库)和 sonatype-work 工作目录(用于存放制品、索引、日志与数据库),目录结构清晰,便于快速部署与升级时保留数据;压缩包内具体文件总数未单独统计。当前已有 212 人浏览学习。通过该包部署 Nexus 后,可配置 Maven 中央仓库代理加速依赖获取,将 Nexus 设为团队 NPM 默认 registry 实现包缓存和私有托管,并在 Web 控制台中创建代理仓库、存储库组与细粒度权限策略。无论是初学者搭建第一个制品仓库,还是团队希望构建内网统一软件源,这份原始官方安装包都能带来可靠的起点。

1. Nexus 3.24.0-02:一个 tar.gz 把 Maven 和 NPM 私服跑起来

第一次搭私服,很多人会纠结 Sonatype Nexus 还是 Artifactory,我的答案很简单:先看预算。Artifactory 的企业功能确实全,但团队只是想把手里的 Maven 和 NPM 依赖在内网收拢起来,那 Nexus OSS 这款免费开源的仓库管理器完全够用。这份 nexus-3.24.0-02-unix.tar.gz 是 3.x 系列里我用得最顺手的一个版本,tar.gz 解压即用,内置 Maven、NPM、Docker、Raw 等格式支持,默认端口 8081,单机十分钟内能跑起来。下面我照着生产环境的部署流程,把安装、Maven 仓库、NPM 仓库以及后来踩过的五个坑完整写出来。新手照着命令敲两小时能出活,老手可以直接跳到第 3 章看参数表。

2. 安装与首次启动:从解压到替 admin 改密码

2.1 解压与目录结构:nexus 和 sonatype-work 谁是谁

tar.gz 解压后会在目标目录下生成两个平级目录,先用tree -L 1 /opt把结构认清楚:

/opt/ ├── nexus-3.24.0-02/ │ ├── bin/ │ │ └── nexus │ ├── etc/ │ │ ├── nexus.properties │ │ └── jetty/ │ └── lib/ └── sonatype-work/ └── nexus3/ ├── admin.password ├── log/ └── db/

nexus-3.24.0-02是程序目录,升级、打补丁、覆盖安装都动这里;sonatype-work是数据目录,仓库配置、组件文件、数据库都落在里面。我踩过的第一个坑就是把两者混在一起看:程序目录坏了可以重新解压,数据目录没了,仓库里的依赖全得重新拉一遍。生产环境我会把sonatype-work单独挂到容量大的数据盘,或者用软链接指过去,而不是让它跟着/opt走。

解压时注意:不要用 root 跑后续的启动。Nexus 官方不建议 root 运行,我习惯先建一个专用系统用户,再解压、授权、启动。这样即使管理界面有安全漏洞,shell 权限也局限在这个用户内。

2.2 JVM 配置:nexus.vmoptions 里我改了三个参数

启动前打开bin/nexus.vmoptions,里面是 JVM 参数。这个文件的核心是三行内存配置:

-Xms1024m -Xmx1024m -XX:MaxDirectMemorySize=2g

内存给多少没有固定的答案,我给一个判断标准:机器内存小于等于 4G 时,Xms 和 Xmx 都压到 1024m;内存大于 8G 时给到 3g 到 4g。我一般把 Xms 和 Xmx 设成同一个值,避免运行时动态扩容触发 GC 抖动。MaxDirectMemorySize 影响 NIO 和 Jetty 的缓冲,NPM 包并发下载时容易吃满,设到 2g 起步比较稳妥。

3.24.0-02 这个版本要求 JDK 8,不要用 JDK 9 以上的版本去跑。常见做法是用系统自带的 JDK 8,如果服务器上默认 java 版本不对,在bin/nexus脚本顶部手动指定INSTALL4J_JAVA_HOME指向 JDK 8 的路径。这个参数比改 PATH 可靠,Nexus 的启动工具会优先读它。

2.3 启动、看日志、改密码:十分钟跑通

用专用用户启动,命令顺序我总结成一套,避免权限混乱:

useradd -r -m -s /bin/bash nexus tar -zxvf nexus-3.24.0-02-unix.tar.gz -C /opt chown -R nexus:nexus /opt/nexus-3.24.0-02 su - nexus -c "/opt/nexus-3.24.0-02/bin/nexus start" sleep 20 tail -n 30 /opt/sonatype-work/nexus3/log/nexus.log

启动脚本是通过su切换到 nexus 用户执行的,这样数据目录会由 nexus 用户自动创建,不需要提前建目录。sleep 20是个缓冲,让服务把嵌入式数据库初始化完再去看日志。日志里出现Started Sonatype Nexus OSS就说明启动成功。如果没看到,用前台模式跑一遍看完整报错:

su - nexus -c "/opt/nexus-3.24.0-02/bin/nexus run"

这样错误信息直接刷在终端里,比翻日志更直观。首次启动后浏览器访问http://服务器IP:8081,点右上角 Sign in,用户名是admin,密码在第一次启动时自动生成:

cat /opt/sonatype-work/nexus3/admin.password

登录后系统会强制改密。改完密这个文件就会失效,不用手动删。如果服务器开了防火墙,记得放行 8081 端口:

firewall-cmd --add-port=8081/tcp --permanent && firewall-cmd --reload

提示:不要跳过改密这一步。管理员密码是空的私服,在内网里等于请人进来乱传包。

3. Maven 仓库实战:proxy、hosted、group 三件套的配置与顺序

3.1 三种仓库角色怎么配:proxy 拉远程,hosted 存私有,group 聚合

Nexus 的 Maven 仓库本质是三种角色的组合。proxy 是远程代理,它从中央仓库或阿里云镜像拉依赖到本地缓存,团队里任何一个人请求过的 jar,第二个人再请求就走内网;hosted 是私有宿主仓库,自己写的公共组件 deploy 到这里,只对自己人开放;group 是聚合入口,把 proxy 和 hosted 合并成一个地址,客户端只配这一个 URL,不感知后面有几个仓库。

为什么需要 group 而不是让客户端配置多个源?因为 Maven 在处理多个远程仓库时,同一个构件的查找顺序不受你控制,容易出现这边缓存了旧版本、那边有新版但没查到的情况。group 可以在配置里严格声明查找顺序:私有仓库排在前,中央代理排在后,命中第一个就停。这个顺序是后面排错的重要基础。

Nexus 3.24 安装完自带一组默认 Maven 仓库:maven-central、maven-releases、maven-snapshots、maven-public。官方把最标准的组合已经配好了。我不建议直接复用,原因是默认仓库都落在同一个 blob store 里,以后想单独迁移 releases 数据会很麻烦。更清晰的做法是在界面上先建 blob store,再一格格建自己的仓库。

3.2 建仓库参数表:URL、Blob Store、Deployment Policy 怎么填

先到 Settings 的 Blob Stores 里创建三个 blob store:maven-blob、releases-blob、snapshots-blob,分别对应代理缓存、正式包、快照包。然后再到 Repositories 创建仓库,核心参数如下:

参数我的取值说明
Namemaven-central仓库名,同时影响访问路径
Remote Storagehttps://repo1.maven.org/maven2/中央仓库,国内网络建议换成阿里云镜像
Auto Blocktrue远程连续失败时自动熔断,不拖累本地
Blob Storemaven-blob代理缓存放这里,独立磁盘管理
Deployment PolicyDisable redeploy仅 hosted 仓库有,正式包不允许覆盖
Version PolicyReleasehosted 仓库只收 Release 包
Layout PolicyMaven 2不是 Maven 1,这个不能选错

hosted 仓库要建两个,一个给正式版maven-releases,一个给快照版maven-snapshots。关键差异在 Deployment Policy:releases 仓库选 Disable redeploy,同名同版本传第二次直接拒收,保证线上构件的不可变;snapshots 仓库选 Allow redeploy,开发阶段的快照版本允许覆盖重新发布。如果两个都选成 Disable redeploy,持续集成里每次快照构建都会 400。

group 仓库的成员顺序是关键。在maven-public的 Members 列表里,把 hosted 仓库拖到 proxy 上面:

顺序仓库名类型作用
1maven-releaseshosted私有正式包优先命中
2maven-snapshotshosted私有快照包优先命中
3maven-centralproxy中央仓库兜底

这个顺序不是随便排的。Nexus 的 group 按列表从上到下逐个查,如果 proxy 排在前面,私有包名正好和中央仓库某个同名构件冲突,就会被远程的旧版本先截胡,这个问题排查起来非常隐蔽。

3.3 本地配置:settings.xml 与 pom.xml 的对应关系

Maven 客户端的约 30 分钟配置,核心是settings.xml里的 mirror 和 server。mirror 把所有对外的 Maven 依赖请求全部拦截,转到 Nexus:

<settings> <servers> <server> <id>maven-releases</id> <username>admin</username> <password>{你的Nexus密码}</password> </server> <server> <id>maven-snapshots</id> <username>admin</username> <password>{你的Nexus密码}</password> </server> </servers> <mirrors> <mirror> <id>nexus</id> <mirrorOf>*</mirrorOf> <url>http://192.168.1.10:8081/repository/maven-public/</url> </mirror> </mirrors> </settings>

mirrorOf=*表示所有依赖请求都撞到 Nexus 一个入口上,配置最简单,适合纯内网环境。如果项目里还有其他独立仓库必须直连,就得把星号改成external:*,否则会把那个仓库的请求也强制代理掉,导致解析失败。server 里 id 必须和 pom 里的仓库 id 一致,这个 id 不是 host,而是认证标识,Nexus 在验证 deploy 请求时按它匹配用户名密码。

发布构件需要项目pom.xml里配上distributionManagement:

<distributionManagement> <repository> <id>maven-releases</id> <url>http://192.168.1.10:8081/repository/maven-releases/</url> </repository> <snapshotRepository> <id>maven-snapshots</id> <url>http://192.168.1.10:8081/repository/maven-snapshots/</url> </snapshotRepository> </distributionManagement>

执行mvn deploy时,Maven 根据项目版本号最后是否带-SNAPSHOT自动选仓库,不需要手工指定。带SNAPSHOT的版本走 snapshotRepository,不带走 repository。如果两个地址都写成同一个 hosted 仓库,轻则出现 release 仓库里混入开发包,重则直接报 400。这个文件是开发者各配各的,不要放到公共 settings.xml 里,因为它描述的每个项目的发布目标和私有属性都不同。

4. NPM 仓库实战:npm publish、版本区分与 registry 指向

4.1 建 NPM 仓库:官方源做 proxy,hosted 收上传

NPM 在 Nexus 里的角色设计和 Maven 一致,但默认仓库一个都没有,全部需要手动建。先建代理仓库:

参数我的取值说明
Namenpm-proxy代理远端 npm 源
Remote Storagehttps://registry.npmjs.org官方源,国内可换成淘宝镜像
Blob Storenpm-blob依赖缓存独立存储
Negative Cachetrue远端 404 也缓存,减少重复请求

再建一个 hosted 仓库,参数较少,但Strict Content Type Validation这个勾选要留意。这个选项开启后,Nexus 会校验上传内容的格式是否符合 npm 规范,避免有人误把临时文件传上来。我建议始终保持勾选,关闭它确实能提升上传兼容性,但也会让仓库里出现各种非 npm 垃圾数据。

最后建 group 仓库,把前两个聚合起来。成员顺序同样把 hosted 放在 proxy 之前,这样私有包@mycompany/utils和公共包lodash在同一个 registry 地址下,npm 客户端不需要切换源。

4.2 npm publish 全流程:init、版本号与 registry 指向

这个步骤回答一个高频疑问:上传组件是先打包还是先执行npm init?答案是先npm init。npm publish会自动把当前目录打包成 tarball 发送上去,不需要手动npm pack之后再传包。发布包的名称和版本号全部来自package.json里的name和version字段,这两个字段才是发布链路的源头。

mkdir my-utils && cd my-utils npm init -y npm pkg set name=@mycompany/utils version=1.0.1 npm login --registry=http://192.168.1.10:8081/repository/npm-hosted/ npm publish --registry=http://192.168.1.10:8081/repository/npm-hosted/

npm login需要输入 Nexus 用户名和密码,成功后会把认证信息写进当前用户的.npmrc文件,后续 publish 不需要重新认证。注意这里 registry 指向的是npm-hosted,而不是 group 地址。hosted 才是唯一接受上传的仓库,group 只读不写入,往里 publish 会直接 403。

版本区分靠package.json的version字段来控制。第一次上传 1.0.1,第二次发版前先改版本号再发布:

npm version patch npm publish --registry=http://192.168.1.10:8081/repository/npm-hosted/

Nexus 对 npm 的版本保护是硬性的:同一个版本号重复发布直接报409 Conflict,提示不能覆盖已发布版本。所以不要靠“重新传一次”来纠正错误,正确做法是在本地先把package.json版本号加一个,然后把修复内容作为新版发布上去。对于正式包,这个约束能保证任何依赖方拿到的版本不可变,不会出现同一个版本号内容却不一样的情况。

4.3 消费侧:.npmrc 的 registry 和认证

开发机安装依赖时,registry 指向 group 地址,这样公共包和私有包走同一个源:

registry=http://192.168.1.10:8081/repository/npm-public/ //192.168.1.10:8081/repository/npm-public/:username=admin //192.168.1.10:8081/repository/npm-public/:_authToken=xxxx

这个文件可以放在项目根目录,也可以放在用户主目录的.npmrc。项目级优先于用户级,用户级优先于全局配置。如果你不想手工编辑,直接执行npm login --registry=http://192.168.1.10:8081/repository/npm-public/,工具会把 username 和 authToken 自动写入.npmrc,输一次密码解决认证问题。

需要注意npm config set registry改的是用户级配置,对全局生效,但也容易被项目级 .npmrc 覆盖。我习惯把 registry 写到项目级文件里,这样同一台开发机上的不同项目可以用不同源,互不干扰。如果哪天依赖拉取时报ETARGET或404,第一反应是看当前目录的 .npmrc,确认 registry 是不是跑到了别的地址上,这是 npm 环境里最容易翻车的一个点。

5. 避坑指南:上传失败与进程挂掉的五个高频问题

5.1 502 Bad Gateway:Jetty 线程池忙不过来

现象:几个同事同时跑npm install或mvn dependency:go-offline,Nexus 页面和 API 请求集体变成 502,重启后恢复,第二天又复现。

原因:3.24 版本默认 Jetty 线程池配置偏保守,并发请求一上来,线程队列直接打满,Jetty 无法继续接收连接。

解决:调整etc/jetty/jetty.xml里线程池的参数。常见做法是把最大线程数调到 200-300:

<Configure id="Server" class="org.eclipse.jetty.server.Server"> <Get name="ThreadPool"> <Set name="maxThreads">300</Set> <Set name="minThreads">10</Set> <Set name="idleTimeout">60000</Set> </Get> </Configure>

改完重启 Nexus。不要一次性拉到 1000,线程太多反而增大上下文切换开销。这个坑排查起来最费时间,因为 502 会被误认为是网络问题或者服务挂掉,实际上 Nexus 进程还活着,只是端口不再接受新连接。

5.2 npm publish 403:发布地址写成了 group 仓库

现象:npm login成功,npm publish却报403 Forbidden,提示当前 registry 不允许写入。

原因:group 仓库是只读聚合入口,上传请求只能落到 hosted 仓库。有人为了省事把.npmrc里的 registry 统一写成了 group 地址,导致所有发布请求都被拒绝。

解决:发布时 registry 指向 hosted,安装时指向 group,两者不能混用。最稳妥的办法是在package.json里写死 publishConfig:

{ "name": "@mycompany/utils", "version": "1.0.2", "publishConfig": { "registry": "http://192.168.1.10:8081/repository/npm-hosted/" } }

这样即使开发者命令行里忘记带--registry参数,发布请求也会自动走 hosted 仓库,安装侧的.npmrc则继续保持 group 地址。

5.3 mvn deploy 400:SNAPSHOT 和 RELEASE 必须分开

现象:mvn deploy报400 Bad Request,后台日志提示 Repository does not allow updating assets。

原因:版本号写成了固定版本如1.0.0,但 pom 里的snapshotRepository配置或 distributionManagement 指向了 release 仓库。Nexus 的 release hosted 仓库默认不允许重复覆盖,同时对快照版本有严格限制。

解决:开发阶段版本号必须带-SNAPSHOT后缀,正式发布前改成不带后缀的固定版本。同时检查distributionManagement里两个 repository URL 是否分离,release 指maven-releases,snapshot 指maven-snapshots。我见过最典型的错误是把两个 URL 写成了同一个地址,开发阶段一直没事,切到正式版第一次构建就 400。

5.4 匿名访问把仓库细节全暴露了

现象:Nexus 管理界面不用登录就能看到所有仓库名称、最后更新时间,甚至能浏览已发布的构件列表。

原因:安装完成后匿名访问默认是开启的,3.24 版本的匿名角色在某些配置下还能执行读取之外的操作。很多内网部署没有主动去关它。

解决:进入 Settings 的 Security 菜单,在 Anonymous Access 里取消勾选允许匿名用户访问,然后到 Roles 里创建一个只读角色,按需分配给服务账号。我现在的习惯是:Nexus 只允许内网 IP 访问,同时匿名访问直接关闭,所有拉取依赖的请求都带账号凭证。这样就算某个开发机的配置泄露出去,影响范围也能控制住。

5.5 启动后进程秒退:JDK 和磁盘都要查

现象:执行nexus start后进程很快消失,ps -ef | grep nexus看不到任何结果,日志文件也只有寥寥几行。

原因:最常见的是 JDK 版本不满足要求。3.24.0-02 需要 JDK 8,用默认的 JDK 11 或更高版本启动时,JVM 直接拒绝加载,进程秒退。其次是 sonatype-work 所在分区磁盘满了,嵌入式数据库初始化失败。

解决:先确认 Java 版本:

java -version

看到版本号不是 1.8 开头,就去bin/nexus脚本里设INSTALL4J_JAVA_HOME指向 JDK 8 安装路径。磁盘空间用df -h看,sonatype-work 分区剩余空间至少要留几个 G。这两个都没问题,就跑前台模式nexus run,把完整异常输出打印出来,比猜日志有用得多。

6. 进阶技巧:用 REST API 给 Nexus 做体检

6.1 一键列出全部仓库:repositories 端点

管理界面右键一个个看仓库效率太低,我部署完或者迁移完会用脚本批量对比。Nexus 3.24 自带 REST API,不需要额外装插件。下面这段脚本列出所有仓库的格式、类型和名称:

#!/bin/bash NEXUS_URL="http://192.168.1.10:8081" NEXUS_USER="admin" NEXUS_PASS="你的密码" curl -s -u "$NEXUS_USER:$NEXUS_PASS" \ "$NEXUS_URL/service/rest/v1/repositories" | \ python3 -c " import sys, json data = json.load(sys.stdin) for d in sorted(data, key=lambda x: (x['format'], x['type'])): print(f\"{d['format']:8s} {d['type']:8s} {d['name']}\") "

这段脚本的返回结果是数组,每个元素包含format、type、name、url等字段。format表示仓库格式,如maven2、npm;type表示仓库类型,如proxy、hosted、group。输出结果一眼就能看出来哪些格式还缺着,尤其是 NPM 这种没有默认仓库的格式,忘了建 proxy 在这个列表里立刻暴露。

6.2 健康检查与版本确认:v1/status 端点

迁移或者升级之后,我会用另一个接口确认当前实例的运行模式:

curl -s -u admin:你的密码 http://192.168.1.10:8081/service/rest/v1/status | python3 -m json.tool

返回的 JSON 里有version字段确认当前版本号,operationMode字段确认运行模式。单节点部署时operationMode是STANDALONE,如果显示成集群模式但实际没有配置集群,说明数据库配置文件有问题,需要马上检查。从那以后我每次部署完 Nexus,都会先跑一遍仓库列表脚本,确认所有格式都建全了再交给团队。NPM 这种默认不带仓库的格式特别容易漏,忘建 proxy 跑一遍 curl 就能发现。这套 REST 检查我换了三个环境都在用,比盯着管理界面翻页靠谱。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询