简介:这是Nexus 3.30.0.01的Windows 64位安装包,面向需要搭建Maven私服的Java开发团队。它可解决公共仓库访问慢、依赖版本混乱、团队协作发布不便等常见问题,适合具备一定构建经验的开发者快速部署。压缩包约212MB,内含可执行程序与运行数据目录结构,能够支撑本地仓库代理、仓库聚合和组件发布等核心功能。目前已有1791人学习/下载。借助该包可搭建企业级组件仓库环境,其内置的权限控制、构件校验和搜索浏览能力让依赖管理更安全可控;同时支持与Jenkins等CI/CD工具联动,为自动化构建流程提供稳定基础。包内附带的目录结构也有助于理解Nexus的运行机制,便于后续按需调整。
1. nexus-3.30.0-01-win64.zip:先搞清楚你下载的到底是个什么
搜索“nexus”时你会先撞见一堆桌面美化工具和五花八门的官网入口,但nexus-3.30.0-01-win64.zip是另一条赛道上的东西:它是 Sonatype Nexus Repository Manager 3 的 3.30.0-01 版本、Windows 64 位发行压缩包。Nexus 是一个制品仓库管理器,企业里用它统一存放 Maven、npm、NuGet、Docker 等构建产物,对内提供下载,对外代理中央仓库。你拿到这个 zip,本质上拿到的是“一个需要跑在服务器上的服务端程序”,不是双击就能用的桌面软件。它解决的问题很实际:公共仓库慢、依赖被删、团队协作时只靠私有的 Git 存不了编译产物。这次我按自己搭过多次的方案,把这个 zip 从解压到日常维护讲清楚,参数和坑都放在对应的章节里。
2. 装对再谈用:Nexus 3.30 在 Windows 上的安装与首次登录
2.1 环境选型:3.30 为什么卡在 JDK 8
Nexus 3.30.0-01 这个版本对运行时的要求相当明确:需要 JDK 8。不是 11、不是 17,就是 8。我见过有人拿新 JDK 去跑,结果服务进程反复重启,日志里报 UnsupportedClassVersionError,最后绕一圈回来换 JDK 8 才正常。这是设计边界,不是玄学:3.30 是 3.x 中后期版本,它的内核和 OrientDB 数据存储对 JDK 8 依赖很深,官方在这个版本线上也是按 JDK 8 验证的。
装 JDK 8 时别只看 java -version 的输出。Nexus 启动脚本会去找 JAVA_HOME,如果系统里同时装了几个 JDK,脚本优先用 JAVA_HOME 指向的那个。Windows 上常见的问题是 PATH 里有个老的 JRE,而 JAVA_HOME 没配或者配错,最后 Nexus 用的是 JRE 而不是 JDK,某些管理功能就起不来。我的做法是单独给 Nexus 开一个系统环境变量 JAVA_HOME 指向 jdk8 的安装根目录,不依赖 PATH 里的 Java。
另外推荐把 zip 解压到一个不带空格的路径,比如D:\nexus。这算是 Windows 上跑服务的老坑:nexus.exe 在带空格路径下安装 Windows 服务时,参数解析经常翻车,启动脚本也会出现文件找不到。3.30 的安装包解压后是两个目录,一个叫nexus-3.30.0-01(程序本体),另一个叫sonatype-work(数据目录),这两个目录最好保持同级,后续升级和备份都方便。
2.2 从解压 zip 到 8081 端口亮起来的命令序列
先把最小启动路径跑通。3.30 在 Windows 上有两种启动方式:直接跑 bin 下的脚本,或者注册成 Windows 服务。首次验证建议用前台方式,能直接看到日志,排错最快。
cd D:\nexus\nexus-3.30.0-01\bin nexus.bat run跑起来后日志会输出到sonatype-work\nexus3\log\nexus.log。看到类似Started Sonatype Nexus OSS 3.30.0-01的字样,再开浏览器访问http://localhost:8081。日志文件里没有这句话,说明服务还没准备好;这时候别急着刷新页面,回日志里看报错。
前台验证没问题后再装 Windows 服务,这样开机自启、后台运行都省心。用管理员权限打开命令提示符:
cd D:\nexus\nexus-3.30.0-01\bin nexus.exe install nexus.exe startnexus.exe install注册服务,nexus.exe start启动服务。注意这里的 install 不改变目录内容,只是把启动方式挂到 Windows 服务管理器上。如果 install 之后马上 start,服务立刻报启动失败,大多数情况下就是前面说的路径空格问题或者 JDK 版本不对,去 Windows 事件查看器看日志。
端口默认是 8081。这个端口不是写在 nexus.vmoptions 里的,而是在nexus-3.30.0-01\etc\nexus-default.properties文件里。把application-port改成别的值,重启后生效。生产上我通常不会留 8081,换成 18081 之类的端口,少一些扫描器盯上的概率。
2.3 第一次登录:admin.password 文件与初始密码管理
首次访问时 Nexus 的管理员账号是 admin,密码不在界面上,在数据目录里。3.30 会在第一次启动时生成一个随机初始密码,路径是:
D:\nexus\sonatype-work\nexus3\admin.password用文本编辑器打开这个文件,里面就是登录密码。第一次登录后,系统会引导你改密码,改完这个文件会自动删除。如果文件删了而你还没记住改过的密码,那就只能重置了。重置管理员密码在 3.30 上有点折腾:停服,删除sonatype-work\nexus3\db\security目录下的相关数据文件,重启后会重新生成 admin.password。这算是一种后悔药,但会丢掉所有现有用户和权限配置,不是首选项。我一般会在部署当天就把密码改成强密码,并把这个初始密码文件的内容单独存一份到内部密码库,防止被覆盖。
登录首页默认有向导,建议跳过英文向导直接进设置,原因很简单:3.30 默认就在,先把匿名访问关掉,再建仓库,体验更安全。匿名访问这块放第 4 章详细说,这里先记住一点:千万别在公网上用默认配置暴露 8081 端口,3.30 的初始设置对安全并不友好。
3. 把 Maven 和 npm 私服跑起来:仓库类型与最小配置
3.1 Hosted / Proxy / Group 三种仓库的分工
Nexus 3 的仓库模型只有三种:Hosted(本地托管)、Proxy(远程代理)、Group(分组聚合)。很多刚接触的人在这块绕弯子,其实用场景一句话就能说清。Hosted 仓库存公司自己的构建产物,相当于团队的私有盘;Proxy 仓库用来缓存 Maven Central、npmjs 这些公共源,团队里所有人下载依赖都走它,第一次请求还是从公共源拉,之后就走本地缓存,外部网络波动对开发基本无感;Group 仓库是前两者的入口,把多个仓库聚合在一个 URL 后面,客户端只配一个地址就行。
登录后预置的仓库已经够用:maven-central是 Proxy,maven-releases和maven-snapshots是 Hosted,maven-public是 Group。npm 这边默认也有npmjs(Proxy)、npm-hosted(Hosted)、npm-group(Group)。如果团队里同时用 Maven 和 npm,这两种仓库体系互不干扰,同一个 Nexus 实例一起跑就行。
创建仓库时有一组关键参数容易忽略:Hosted 仓库的 Deployment policy。maven-releases 默认是Allow redeploy,maven-snapshots 默认也允许。我的习惯是把 releases 仓库改成Disable redeploy,因为已经发布的正式版本不允许覆盖,能防止开发手滑把同一个版本号传了两份不同内容上去;snapshots 仓库保持允许,因为 SNAPSHOT 本来就是可变的。npm-hosted 那边也有类似策略叫Strict,可以控制同名同版本的覆盖行为,发布规范严格的团队可以打开。
3.2 Maven 私服配置:settings.xml 的 mirror 与 deploy 上传
Maven 客户端接 Nexus 就两个配置文件:settings.xml负责下载,pom.xml负责上传。
下载配置用 mirror 把几乎所有仓库地址都指向 maven-public:
<mirrors> <mirror> <id>nexus</id> <mirrorOf>*</mirrorOf> <url>http://localhost:8081/repository/maven-public/</url> </mirror> </mirrors>mirrorOf写*表示所有仓库都走这个镜像,适用于绝大多数场景。如果有的仓库故意不走私服,可以用*,!central之类的排除写法,但我建议除非有明确理由,否则别这样弄,团队里排查依赖来源时会头大。
上传配置在项目 pom.xml 的 distributionManagement 里:
<distributionManagement> <repository> <id>nexus-releases</id> <url>http://localhost:8081/repository/maven-releases/</url> </repository> <snapshotRepository> <id>nexus-snapshots</id> <url>http://localhost:8081/repository/maven-snapshots/</url> </snapshotRepository> </distributionManagement>这个 id 要和 settings.xml 里的 server id 一一对应,否则上传时认证信息对不上:
<servers> <server> <id>nexus-releases</id> <username>deploy</username> <password>你的密码</password> </server> <server> <id>nexus-snapshots</id> <username>deploy</username> <password>你的密码</password> </server> </servers>发布命令没什么特殊的,就是mvn clean deploy。deploy 时会根据 pom.xml 里的 version 后缀判断走 release 还是 snapshot 仓库:version 带-SNAPSHOT就去快照仓库,不带就去正式仓库。常见的翻车是:版本号不带 SNAPSHOT,却往 maven-snapshots 传,Nexus 直接 400 拒绝,因为 snapshots 仓库不接受非快照版本;反过来也一样。这条规则和 npm 那边类似,细节写法不同但思路一致。
3.3 npm 私服:registry 切换、npm pack 与版本区分
npm 接 Nexus 比 Maven 更轻量。把 registry 指到 npm-group 或者 npm-hosted 就行:
npm config set registry http://localhost:8081/repository/npm-group/下载依赖时用 npm-group,它聚合了 npmjs 代理和 npm-hosted,公共包和内部包都能装。但发布时方向不同:npm publish 只能发到 hosted 仓库,发到 group 会被拒绝。我见过不少人在这一步来回折腾,界面报错也不直观,最后发现 registry 配错了。
发布前先确认一件事:是“先打包还是先 npm init”。这个热词问的人很多,答案是先npm init。因为决定“发布成哪个包的哪个版本”的是 package.json 的name和version字段,而 npm pack 只是按 package.json 生成 tarball。如果跳过 npm init 直接 pack,打出来的包可能没有 name 和 version,或用的是默认值,publish 时要么报错,要么传到 Nexus 上变成无名残包,清理起来很麻烦。
最小发布流程:
mkdir my-lib && cd my-lib npm init -y npm config set registry http://localhost:8081/repository/npm-hosted/ npm publish这里有个细节:npm publish实际发布的是当前目录打出来的包,内容与npm pack生成的 tarball 一致。想发发布前检查,先npm pack --dry-run看一眼文件清单,再决定会不会把 node_modules 或无关文件传上去。如果 package.json 里没写files字段,npm 会把目录下几乎所有文件都打进去,这是另一个常见翻车点。
nexus 上区分同一组件不同版本,完全依赖 package.json 的 version。同一个 npm-hosted 仓库里,同名的包可以存在多个版本,Nexus 默认允许共存,拉取时按语义化版本规则解析。如果只想保留最新版本,可以在仓库设置里打开Remove outdated packages之类的策略,但这会导致旧版本不可用,谨慎开启。
私有包名这块最好统一规范:内部发布的包一律用 scoped 形式,比如@company/logger。scoped 包默认是私有的,配合 Nexus 的权限配置,外部用户拉不到;项目里引用时也不需要改 registry,因为 npm-group 已经把 hosted 仓库聚合进去了。还有个配套参数是.npmrc里的认证信息,发布到 hosted 仓库通常需要登录,命令行执行:
npm login --registry http://localhost:8081/repository/npm-hosted/这个命令会在当前用户的.npmrc里写入一个 base64 编码的_auth字段。如果环境变量或 CI 里没法交互式登录,可以手动拼接认证串:
echo -n "deploy:你的密码" | base64然后把输出写到.npmrc的//localhost:8081/repository/npm-hosted/:_auth=你的base64串。注意这里的 URL 路径不能写错,npm 校验 auth 时会精确匹配 host 和 path 前缀。
4. 资源边界与维护:JVM 内存、blob 存储、备份和权限
4.1 nexus.vmoptions 里的内存和端口参数
Nexus 是一个跑在 JVM 里的服务,内存参数写在nexus-3.30.0-01\bin\nexus.vmoptions里。我拆开看这个文件时,重点只改两个值:
-Xms270m -Xmx270m默认堆内存只有 270MB,个人测试够用,团队规模上来后很容易出现 Full GC 频发、界面操作卡顿、npm 拉包超时。我一般按机器内存的四分之一到三分之一给,比如 8GB 的开发服务器给-Xms2g -Xmx2g,产线 16GB 机器给到 3g。注意 Xms 和 Xmx 最好设成一样的值,避免 JVM 动态扩容带来的性能抖动,这个在 Windows 服务器上尤其明显。
文件末尾还会有一行-Dnexus.port相关的参数吗?实际上 3.30 的端口不在 vmoptions 里,而是前文提到的 nexus-default.properties。容易混的是-Djava.io.tmpdir和-XX:MaxDirectMemorySize。前者控制临时文件位置,默认指到系统临时目录,Nexus 上传大文件时会写临时文件,如果系统临时目录在 C 盘且空间较小,上传几个 G 的包会报磁盘空间不足。我在生产上会显式把它指到数据盘:
-Djava.io.tmpdir=D:\nexus\tmp改完 vmoptions 后重启服务生效。这个文件是纯文本,UTF-8 编码,Windows 上用记事本另存时记得别存成带 BOM 的格式,否则 JVM 启动参数解析会出毛病。
4.2 blob 存储路径与最小可用备份方案
3.30 的制品数据全部存在 blob 里,路径是sonatype-work\nexus3\blobs。每个仓库对应 blobs 目录下的一个子目录,里面是二进制块文件。数据库本身在sonatype-work\nexus3\db,里面是 OrientDB 的库文件。两个目录合起来是 Nexus 的完整数据。
备份这块容易踩坑:直接在线复制 db 目录得到的备份大概率是坏的,因为 OrientDB 写入时文件处于不一致状态。我常用的方案是“停服拷贝”,虽然土,但可靠。半夜执行:
net stop nexus xcopy D:\nexus\sonatype-work D:\backup\nexus-work-20250101 /E /I /H net start nexusWindow 的 xcopy 带上/E才拷贝空目录,/I防止多目录确认提示,/H连隐藏文件一起拷。恢复时把备份目录覆盖回去,再启动服务即可。这个方案适合单体服务器,好在 3.30 本来就是单机部署。
如果想不停服,可以用 Nexus 的 Cleanup 任务配合 blob 压缩,但它不能替代备份。3.30 没有完整的在线全量备份 UI,这是版本边界,别指望有什么神奇的菜单。如果团队对可用性要求高,我的建议是别在 Windows 单机上长期跑 Nexus,把数据目录挂到网络存储上,用快照来做更低频的备份。但要提醒:OrientDB 对底层文件锁很敏感,挂网络盘时如果锁机制不稳定,Nexus 会直接启动失败。
4.3 匿名访问收紧与只读账号
3.30 默认允许匿名用户看仓库列表并下载制品,这对内网开发是便利,对外泄露是风险。收紧的第一步是进入 Administration > Anonymous Access,关闭匿名访问。关闭后,Maven 和 npm 的下载也需要带认证信息,CI 里配置会多一步,但对安全来说是必要的。
更细的做法是建一个只读账号给构建机用,权限只配 Repositories 的 browse 和 read,不给上传。这个账号在 Nexus 的用户管理里创建,角色选nx-anonymous自带权限也可以,但更可控的是自定义角色,只勾选nx-repository-view-*-*-read和nx-repository-view-*-*-browse。这样即使构建机的密码泄露,别人也只能下载不能篡改。
npm 和 Maven 侧对只读账号的配置就是普通账号密码,Maven 在 settings.xml 的 server 段里填,npm 在.npmrc里填。只读账号还有一个好处:Nexus UI 上的操作日志里可以区分谁在下依赖,排障时能看出是哪个构建任务触发的大流量下载。
5. Nexus 3.30 的运行维护避坑清单
5.1 现象:服务启动了,但 8081 打不开
这里的表现是 Windows 服务列表里状态是“正在运行”,netstat -ano也看不到 8081 端口。原因通常有三层:一是防火墙入站规则没放行,本地 localhost 能开但局域网访问不行;二是 Nexus 启动到一半卡住,日志停在某个加载步骤,界面自然是打不开的;三是端口被别的进程占用了,常见的是另一个 Nexus 实例或某个 Tomcat 用 8081。
解决顺序:先看sonatype-work\nexus3\log\nexus.log最后 30 行,确认有没有报错。没有明显报错但一直等,多半是 javaw.exe 进程还挂着,把服务停了杀进程再启。防火墙层面我一般先临时放行一次netsh advfirewall firewall add rule name="Nexus8081" dir=in action=allow protocol=TCP localport=8081,确认通了再写进策略里。端口占用则用netstat -ano | findstr 8081找出 PID,到任务管理器里确认是不是自己的另一个 Java 进程。
5.2 现象:mvn deploy 报 401 或 400
401 是认证没通过,400 多数是仓库类型不匹配。401 我会先检查两个地方:settings.xml 的 server id 是不是和 pom 的 distributionManagement. id 完全一致,大小写都不差;密码里如果有特殊字符,在 XML 里要转义,&写成&。还有一个隐蔽原因:Nexus 的用户到期或被禁用,3.30 默认密码有效期策略是 60 天,如果一开始用 admin 配置的密码超过 60 天没改,账号会被锁定,deploy 一直在 401,UI 上却能登录。遇到这种症状先去用户管理里看账号状态。
400 的典型是往 maven-snapshots 传非 SNAPSHOT 版本,或者反过来。Nexus 的报错信息会写明 “Invalid version” 之类的提示,对照 pom.xml 的 version 字段改后半段即可。
5.3 现象:npm publish 经常失败
npm 在 Nexus 上最容易出的三类状况:一是 registry 配成 group 地址,publish 被拒绝;二是没登录或.npmrc里_auth路径写错,报 401;三是包名不规范,比如没有 scope 且和公共包重名,Nexus 不会校验公共包重名,但后面下载时容易混淆。
解决时先把 registry 切到 npm-hosted 地址,执行npm whoami验证认证是否生效;然后确认 package.json 的 name 带 scope 前缀。发布前先用npm pack --dry-run看清楚包里有什么,再执行npm publish。有的团队在 CI 上会遇到.npmrc写入了,但工作目录里节点的 npm 版本对_auth格式解析不一致的问题,统一 Node 版本可以根治。
5.4 现象:升级后数据目录启动失败,或新版本找不到旧数据
Nexus 3.30 用的存储引擎是 OrientDB,而 4.x 系列换成了 H2,这不是小版本升级能自动平滑的。如果你手里这个 3.30 是要往上升级的,千万别直接用 4.x 的程序指向 3.30 的 sonatype-work,启动时大概率直接报 migration 错误。官方提供的是升级路径,但要在目标版本里执行迁移。这里我建议别在生产上一键升级,先复制一个副本目录,用副本跑一次升级流程,确认数据完整后再切正式。Windows 环境下尤其先确认磁盘剩余空间至少是数据目录的两倍,迁移过程会有大量临时文件。
顺带说一个容易出事的习惯:把自己旧的 maven 仓库目录直接拖进 blob 目录想导入,那是行不通的。Nexus 只会认它自己的 blob 格式,历史版本的依赖要么通过代理仓库重新拉,要么用 mvn deploy 逐个传上去,没有“放进去就能用”的捷径。
6. 冷门但能救命的两个技巧
6.1 用 Cleanup 策略自动清理 snapshot 老版本
3.30 的 UI 里可以配置 Cleanup Policy,很多团队根本不用,结果 snapshot 仓库越来越大,blob 目录膨胀到几十 GB。我一般在 Administration → Cleanup Policies 里建两条策略。一条针对 maven-snapshots,按Last downloaded超过 30 天且Release version是 SNAPSHOT 来清理;另一条针对 npm-hosted,按发布年龄保留最近 20 个版本。策略配好后一定要在仓库设置的 Cleanup Policy 标签页里勾上,否则策略建了不生效。这个操作比手动删制品安全得多,Nexus 会同时清理对应的 blob 块。
6.2 脚本化批量上传:用 REST API 省掉手工点击
如果要从旧仓库批量导包,不要在 UI 里一个个传,用 Nexus 的 REST API 配合 curl 写循环。上传到 Maven 仓库的用法是:
curl -u admin:密码 \ -X POST \ -H "Content-Type: application/octet-stream" \ --data-binary "@my-lib-1.0.jar" \ "http://localhost:8081/service/rest/v1/components?repository=maven-releases"这个接口上传的制品没有 Maven 坐标,Nexus 会把文件名当坐标解析。所以批量脚本里要保证文件名符合groupId/artifactId/version/的目录结构,或者逐个传坐标参数。更省事的做法是针对 Maven 的mvn deploy:deploy-file写循环,把坐标信息作为命令行参数一个个传,但慢一些。我自己处理过一批几百个历史 jar,最后是写了一个 Python 脚本,用 REST API 逐个传并打印状态码,失败的重试三次并记录到日志。这类脚本不复杂,但救急时非常管用。
这两招配合起来,3.30 的日常维护基本就够用了。说到底,这个 zip 解压出来的东西不复杂,复杂的是想清楚怎么用、怎么守、怎么备。我自己的教训是:拿到一个新环境先别急着开匿名访问和改一堆花哨配置,先把 admin 密码改了、备份路径确认了再动仓库。希望帮到你。
本文还有配套的精品资源,点击获取