资讯详情

Nexus Windows免安装搭建Maven私服:仓库配置与运维

📅 2026/10/29 2:31:01 | 华诺云谱 👁 阅读
Nexus Windows免安装搭建Maven私服:仓库配置与运维
简介Nexus 3.45.0-01 Windows 64 位版是面向 Java 开发、DevOps 与企业研发团队的 Maven 私服搭建包用于集中管理内部组件、第三方依赖及公共仓库缓存缓解直连中央仓库的速度与安全问题。压缩包共 690 个文件、约 240.62MB含 420 个 jar 核心库、82 个 dll 与 22 个 exe 运行组件以及 29 个 xml、19 个 properties 等配置目录区分 nexus-3.45.0-01 程序文件与 sonatype-work 运行数据后者包含配置、日志和存储内容。已有 417 人学习下载适合需要落地本地私服、理解仓库代理/发布/权限控制机制并维护目录结构的开发者参考。1. 内网里那堆 jar总得有个地方放第一次见到这个包是在一台 Windows 构建机上几个项目共用同一批内部 jar每个人本地拿mvn install:install-file装一遍版本对不齐就开始互相甩锅有人升了 0.3.2 有人还是 0.3.0打出来的包跑起来行为都不一样。想搭个 maven 私服又不想为这点事在内网里折腾一台 Linux 加容器编排于是就有了 nexus-3.45.0-01-win64 这种 Windows 免安装包——解压、改两行配置、注册成服务8081 端口起来之后代理中央仓库、存内部构件、对外聚合成一个地址三件事一次办完。它适合的场景很具体内网团队、Windows 机器承担构建、人数在几人到几十人之间、暂时没有独立的构件管理平台。下面按我实际落地的顺序,从解包一路写到备份和升级。2. 从 zip 到 8081 端口Windows 上的启动顺序2.1 解压位置和 Java 前置检查Windows 上最容易翻车的第一步不是配置是解压到哪。放到C:\Program Files\下面会同时踩两个坑路径带空格部分脚本调用时参数被截断目录受 UAC 保护注册成服务后以系统账户跑写sonatype-work时权限不对。我一般的做法是单独建一个盘符目录比如D:\nexus\包解开之后同级会多出一个sonatype-work所有数据、日志、blob 都在里面这个目录将来就是备份对象。Java 是硬前置。3.45 这条线上 Java 8 和 Java 11 都能跑我倾向 11主要是 GC 行为和 TLS 握手在新一点的环境里更省心。注意必须是 JDK 而不是 JRE也不要把JAVA_HOME指到bin子目录。# 机器级和用户级分开看注册成服务后读的是机器级 [Environment]::GetEnvironmentVariable(JAVA_HOME,Machine) [Environment]::GetEnvironmentVariable(JAVA_HOME,User) # 解压到无空格路径 Expand-Archive -Path .\nexus-3.45.0-01-win64.zip -DestinationPath D:\nexus Get-ChildItem D:\nexus # 验证 java 能被 JDK 目录下的可执行文件拉起 $env:JAVA_HOME\bin\java.exe -version[Environment]::GetEnvironmentVariable的第二个参数是关键Machine读的是系统变量User读的是当前登录用户变量。这两者经常不一致命令行里java -version正常服务却起不来原因就是服务以 LocalSystem 身份运行看不到你个人账户下的变量。Expand-Archive之后Get-ChildItem应该能看到nexus-3.45.0-01这个目录bin、etc、lib、public都在里面。2.2 nexus.vmoptions 里值得改的四个参数bin\nexus.vmoptions是 JVM 启动参数的落点默认堆给得比较足小机器上直接跑会把系统内存吃光然后开始频繁 GC表现为 Web 界面点一下转三秒。需要看的是四项参数默认量级调整依据-Xms/-Xmx同值约 2.7G机器 8G 内存给 2G 左右16G 以上可以维持默认-XX:MaxDirectMemorySize与堆同值必须和-Xmx一起调否则大文件上传会 OOM-Djava.io.tmpdir系统临时目录指到本地数据盘别指网络盘或内存盘-Dkaraf.data相对路径多实例部署时才改单实例保持默认-Xms和-Xmx设成一样是为了避免运行期反复扩堆Nexus 这种常驻服务启动完基本就稳定在某个水位。MaxDirectMemorySize管的是堆外直接内存构件上传下载走的是 NIO堆外不够时报的错往往是OutOfMemoryError: Direct buffer memory看着像堆的问题其实跟-Xmx没关系这是血泪经验。-Djava.io.tmpdir指向网络盘或 RAM disk上传大 jar 时容易出半截文件排起来非常费劲。# D:\nexus\nexus-3.45.0-01\bin\nexus.vmoptions节选 -Xms2048m -Xmx2048m -XX:MaxDirectMemorySize2048m -XX:UnlockDiagnosticVMOptions -Djava.io.tmpdirD:\\nexus\\tmp注意 ini 文件里 Windows 路径要写双反斜杠或者正斜杠单反斜杠会被当成转义。改完这个文件必须重启进程才生效热改没用。2.3 先前台跑通再注册成服务我见过太多人上来就nexus.exe /install服务装上了、起不来、日志也找不到然后开始怀疑包有问题。正确顺序是先前台跑看到 Jetty 起监听再加服务。前台模式的好处是所有启动日志直接打在控制台出错一眼能看见。cd D:\nexus\nexus-3.45.0-01\bin # 前台启动CtrlC 退出 .\nexus.exe /run # 看到 Started Sonatype Nexus 之后再开另一个窗口验证 Invoke-WebRequest -Uri http://localhost:8081/ -UseBasicParsing/run是前台参数进程退出即服务停止适合调试。确认能起来之后用管理员权限的 PowerShell 执行注册# 注册服务服务名默认 nexus .\nexus.exe /install nexus # 启动 / 查询 / 停止 .\nexus.exe /start nexus Get-Service nexus .\nexus.exe /stop nexus # 彻底卸载 .\nexus.exe /uninstall nexus/install后面的名字是服务显示名多实例共存时必须区分开。注册完之后服务的启动账户默认是 LocalSystem如果你前面只配了用户级JAVA_HOME这里就会失败。改法是系统属性里加机器级变量或者在服务属性里把登录账户改成你自己的账户——后者在需要访问网络共享存储时才需要。服务起来以后命令行窗口可以关掉日志改到sonatype-work\nexus3\log\nexus.log里看。2.4 首次登录和端口的三处确认浏览器打开http://机器IP:8081/右上角登录账号admin密码不在任何文档里它被写在数据目录的一个一次性文件里# 首次登录密码位置 Get-Content D:\nexus\sonatype-work\nexus3\admin.password # 改完密码后把这个文件删掉 Remove-Item D:\nexus\sonatype-work\nexus3\admin.password这个密码文件用完即删留着等于给自己留后门。端口如果被占用Windows 上 8081 经常被别的调试工具占了改etc\nexus-default.propertiesapplication-port8081 application-host0.0.0.0application-host改成0.0.0.0才能被局域网其他机器访问默认只监听本机时同事会报连接超时。改完同样要重启服务。还有一处是防火墙Windows Defender 防火墙默认拦入站需要给 8081 开一条入站规则否则本机通了、别人不通。注意端口、host、防火墙三处必须同时确认。只改一处然后排查半天是最常见的时间浪费。3. 仓库三分法proxy、hosted、group 各管什么3.1 proxy 仓库把公共依赖搬到内网proxy 仓库的定位是「缓存转发」。它自己不产生构件只在你第一次请求某个 jar 时去远端拉拉回来存一份第二次同版本请求直接命中本地缓存。这一步对构建速度的提升非常直接一条mvn clean package里可能有几十次下载缓存之后基本只剩元数据校验。新建路径是Server administration and configuration → Repository → Repositories → Create repository → maven2 (proxy)。关键参数只有三个参数含义取值建议Remote storage远端仓库地址公共 Maven 仓库根地址结尾带斜杠Maximum component age元数据缓存时长1440 分钟太短会频繁回源Auto blocking enabled远端持续失败时自动熔断开启避免构建被远端拖死Remote storage填的是仓库根不是某一个 jar 的地址末尾斜杠不能省。Maximum component age决定了多久去远端确认一次有没有新版本设成 0 等于每次构建都回源缓存就白做了。Auto blocking在远端不可用时把该 proxy 标记为不可用请求直接走下一个成员这个开关在内网出口不稳的环境里能省掉大量超时等待。如果团队有内网可达的公共镜像站可以把Remote storage换成镜像地址同步速度会明显好一些没有就直连公共仓库日常使用差别主要在首次预热。3.2 hosted 仓库release 和 snapshot 必须分家hosted 仓库放的是自己团队产出的构件。这里有个绕不开的原则发布版和快照版要建两个仓库不要塞在一起。原因在于两者的元数据语义完全不同。快照版本允许同一个版本号反复覆盖仓库要保留时间戳目录和maven-metadata.xml里的多次记录发布版本要求版本号唯一且不可变覆盖就意味着依赖方拿到的内容和昨天不一样构建结果不可复现。混在一个仓库里Maven 解析时容易把快照的元数据当成发布的出现「明明改了代码拉下来的还是旧包」这种玄学问题。建两个 maven2 (hosted)参数差异如下参数maven-releasesmaven-snapshotsVersion policyReleaseSnapshotDeployment policyDisallow redeployAllow redeployLayout policyStrictStrictVersion policy是仓库层面的版本类型断言Strict布局策略会校验路径结构必须符合 Maven 约定。Disallow redeploy意味着同版本号第二次上传会被拒绝这是有意为之——它逼着你升版本号而不是悄悄覆盖。快照仓库反过来必须允许覆盖否则迭代阶段每次都要改版本。3.3 group 仓库顺序决定了解析优先级客户端不应该同时配三个仓库地址。正确做法是建一个 maven2 (group)把 proxy 和两个 hosted 都拉进来对外只暴露这一个 URL。成员顺序是有语义的Nexus 按顺序查找前一个找到就不再往后走。常规排法是「自家发布 → 自家快照 → 远端代理」这样同名构件优先命中内部产出避免内部包和公共包版本号撞车时拉错。maven-public (group) ├── maven-releases (hosted, Release) ├── maven-snapshots (hosted, Snapshot) └── maven-central (proxy)调整顺序在 group 的配置页面上拖拽即可改完不需要重启但客户端侧有缓存需要执行一次缓存失效Invalidate cache才能立刻看到效果。这一步很多人漏掉然后以为顺序没生效。3.4 权限给发布账号单独开一条路不要用 admin 去跑 CI 发布。Nexus 的权限模型是基于角色Role的最小可用配置是建一个角色只授予两个 hosted 仓库的 browse、read、add、edit 权限再把角色赋予一个专用用户。权限串的形态是nx-repository-view-maven2-仓库名-动作比如nx-repository-view-maven2-maven-releases-add。只读用户只给read和browse发布用户再加add和edit。管理员账号只用于配置变更不进任何流水线变量这是一条底线。4. 避坑与排查五个真会卡住人的地方4.1 服务注册成功但启动失败现象Get-Service nexus显示 Stopped/start之后过几秒又回到 Stopped事件查看器里有一条 1053 超时。原因基本是两个一是系统级JAVA_HOME没配服务进程找不到 Java二是nexus.vmoptions里-Xmx设得比物理内存还大JVM 直接拒绝启动。解决先在服务属性里确认启动账户再用该账户的环境跑一次java -version把-Xmx降到物理内存的一半以内。日志在sonatype-work\nexus3\log\nexus.log服务启动失败时这个文件里通常有一行明确的Error: Could not create the Java Virtual Machine。4.2 deploy 报 401 或 403现象mvn deploy提示Return code is: 401, ReasonPhrase: Unauthorized或者 403 Forbidden。原因分三层看401 是认证没过通常是settings.xml里server的id和pom.xml里distributionManagement的id对不上Maven 找不到对应的账号密码403 是认证过了但没权限多为角色少了add动作或者目标仓库的Deployment policy是Disallow redeploy而你重复发布了同版本。解决先把两个 id 打印出来比对注意大小写和空格再确认该用户所属角色对目标仓库有add权限最后看是不是改版本号就能过。提示密码写在 settings.xml 里时建议用mvn -ep生成加密串配合settings-security.xml明文密码进版本库是另一个层面的坑。4.3 快照拉不下来日志里一堆 404现象依赖xxx-1.0.0-SNAPSHOT解析失败Nexus 日志里能看到对快照元数据的 404。原因通常是快照仓库没被加进 group或者 group 里快照仓库排在 release 后面、而中间某一步的缓存把 404 记住了。Nexus 对「未找到」也会缓存一段时间标错之后即使配置改对了短时间内仍然返回 404。解决确认 group 成员包含快照仓库执行Invalidate cache清掉负缓存再在本地删掉~/.m2/repository下对应的快照目录重试。如果还不行直接看该仓库的 Browse 页面里maven-metadata.xml是否存在文件不在就是发布端压根没传上去。4.4 磁盘被 blob 撑满现象某天突然所有上传返回 500日志里No space left on device一看sonatype-work目录几十个 G。原因Nexus 删除组件走的是软删除blob store里的数据块不会立即回收快照仓库每天覆盖几十次几个月下来体积非常可观。解决建 Cleanup Policy 挂到快照仓库上规则设成「保留最近 N 个版本、超过 X 天未下载的删掉」再排一个Compact blob store的定时任务真正回收空间。手工删组件只能减小索引不会减 blob这一点很多人误解。4.5 路径空格和网络盘引发的怪问题现象上传大文件时偶发失败或者启动时报Could not resolve path。原因安装路径含空格、-Djava.io.tmpdir指到网络共享、karaf.data指到 UNC 路径这三类都会导致文件锁或路径解析异常。Windows 上文件锁的语义和 Linux 差别不小网络盘上尤其明显。解决安装目录和数据目录一律放本地盘、不含空格tmpdir单独建一个本地目录并确保服务账户有写权限。这条没有技术含量但出问题时的排查成本极高属于提前规避比事后定位划算的典型。5. 客户端接入从 settings.xml 到离线构建5.1 mirror 和 repository 的取舍客户端接私服有两种写法配mirror把某个仓库的请求整体重定向或者配repository直接声明仓库地址。团队统一场景下我倾向 mirror因为它在settings.xml里配置不依赖每个项目的 pom改一处全员生效。mirrorOf的取值很关键值效果适用*所有仓库请求都走私服全内网团队公共仓库不可直连central只拦中央仓库私服只是加速其他仓库仍需直连external:*拦所有外部仓库本地仓库除外兼顾灵活性的折中用*的前提是 group 里已经把需要的远端仓库都代理进来了否则会出现「某个依赖以前能下接了私服反而下不了」。这是切私服时最高频的翻车点。5.2 一份能直接抄的 settings.xmlsettings mirrors mirror !-- 名字随意只用于本地识别 -- idnexus-local/id mirrorOf*/mirrorOf urlhttp://192.168.1.20:8081/repository/maven-public//url /mirror /mirrors servers !-- id 必须与 pom 中 distributionManagement 的 id 一致 -- server idnexus-releases/id usernamedeploy-user/username password******/password /server server idnexus-snapshots/id usernamedeploy-user/username password******/password /server /servers profiles profile idnexus/id repositories repository idnexus-public/id urlhttp://192.168.1.20:8081/repository/maven-public//url releasesenabledtrue/enabled/releases snapshotsenabledtrue/enabled/snapshots /repository /repositories pluginRepositories pluginRepository idnexus-public/id urlhttp://192.168.1.20:8081/repository/maven-public//url /pluginRepository /pluginRepositories /profile /profiles activeProfiles activeProfilenexus/activeProfile /activeProfiles /settingsmirrors负责重定向profiles负责声明可解析位置两者都指向 group 地址。pluginRepositories单独列一份是因为插件解析走的通道和依赖不同漏了它会出现「依赖能下、插件下不了」。activeProfiles里的 id 是 profile 的id不是仓库的id这两个名字经常被搞混。对应 pom 侧的发布配置distributionManagement repository idnexus-releases/id urlhttp://192.168.1.20:8081/repository/maven-releases//url /repository snapshotRepository idnexus-snapshots/id urlhttp://192.168.1.20:8081/repository/maven-snapshots//url /snapshotRepository /distributionManagementid与settings.xml的serverid严格一一对应这是 401 的根源。url指向具体仓库而不是 groupgroup 是只读聚合不能往里 deploy。5.3 验证依赖到底走没走私服改完配置不能凭感觉。三个验证手段从轻到重# 1) 看解析日志里下载源 mvn -X dependency:resolve 21 | grep -i Downloading from # 2) 清掉单个 artifact 的本地缓存再拉 rm -rf ~/.m2/repository/com/example/demo mvn dependency:get -Dartifactcom.example:demo:1.0.0 # 3) 构造离线场景验证 group 缓存是否真的生效 mvn -o clean package第一条命令输出里如果出现Downloading from nexus-local或 group 地址说明 mirror 生效了。第二条用来排除「本地已经有缓存所以看着像通了」的假象。第三条-o是离线模式它不访问任何远端能成功说明所需构件都在本地仓库里——但它验证不了私服缓存只能验证上一次解析是否完整别把它当成私服联通性测试。更直观的办法是去 Nexus 界面 Browse 对应 group看构件是否出现在列表里以及在 Search 里查maven-metadata.xml的时间戳。5.4 Gradle 和老项目顺带接上不是所有项目都用 Maven。Gradle 侧的写法要注意新版本对 HTTP 仓库的限制repositories { maven { url http://192.168.1.20:8081/repository/maven-public/ allowInsecureProtocol true // 走 HTTP 时必须显式开启 } } publishing { repositories { maven { url http://192.168.1.20:8081/repository/maven-releases/ credentials { username project.findProperty(repoUser) password project.findProperty(repoPass) } } } }allowInsecureProtocol在较新的 Gradle 里是强制项缺了会直接报仓库不安全而拒绝解析报错信息不明显容易误判成网络问题。凭据用project.findProperty从gradle.properties或命令行读不要写死在build.gradle里。前端项目的 npm 源也可以挂在同一个实例上建一个 npm (proxy) 加一个 npm (hosted) 再聚合成 groupnpm config set registry指过去就行思路和 Maven 完全一致只不过换了个仓库格式。6. 备份、清理与升级让这套东西能长期跑下去搭起来只是开始真正消耗精力的是三个月后的磁盘告警和半年后的一次迁移。先说备份Nexus 的备份有两块元数据和 blob 数据。界面上Tasks里建一个Admin - Export databases for backup的定时任务它会周期性把数据导到sonatype-work\nexus3\backup下生成带时间戳的目录。但导出任务只覆盖元数据blob store 里的实际文件不在里面。# 每日增量导出任务落盘后整体同步到备份盘 $src D:\nexus\sonatype-work\nexus3 $dst E:\backup\nexus\$(Get-Date -Format yyyyMMdd) robocopy $src $dst /MIR /R:1 /W:1 /XD $src\elasticsearch /LOG:E:\backup\robocopy.log/MIR是镜像模式会删除目标端多余文件配合日期目录使用才有意义直接对同一个目标目录长期/MIR会把历史备份一起抹掉。/XD排除 elasticsearch 索引目录这个目录可以在恢复后重建没必要占备份空间。/R:1 /W:1把重试压到最低避免备份任务在网络抖动时挂住几个小时。清理这块3.45 已经支持 Cleanup Policy比早期手工删组件省事得多。策略写在Repository → Cleanup Policies里规则组合一般是「保留最近 N 个快照版本」加「超过 X 天未被下载的删除」然后把策略挂到快照仓库上。挂完之后不会立刻释放磁盘还要配一个Compact blob store任务它负责真正回收未被引用的数据块。这两个任务建议错开时间跑别同时占用 IO。注意配了清理策略不等于立刻见效第一次运行前建议先确认策略命中的组件数量避免把还在用的基线版本清掉。升级是最后一块。3.x 的升级路径是停服务、备份整个sonatype-work、解压新版本包到新目录、把旧etc下的定制配置nexus-default.properties、nexus.vmoptions拷过去、让新版本指到同一份数据目录。数据目录默认在同级如果分开了靠bin\nexus.vmoptions里的-Dkaraf.data指定。# 升级前的三步停、备、验版本 .\nexus.exe /stop nexus Copy-Item D:\nexus\sonatype-work D:\backup\pre-upgrade -Recurse Get-Content D:\nexus\sonatype-work\nexus3\version.txtversion.txt里记着当前数据格式版本新版启动时会做一次不可逆的数据迁移所以「先备份再启动」不是流程洁癖是唯一的后悔药。迁移完成之后不能再用旧版程序去读这份数据回滚只能靠备份恢复。健康检查我习惯挂一个最简单的探针比翻日志快得多curl -s -o /dev/null -w %{http_code} http://192.168.1.20:8081/service/rest/v1/status返回 200 表示服务在返回 503 说明处于启动中或维护状态两者都能被监控系统直接消费。从那以后我每次动这个实例之前都会强制走一遍「停服务、整目录拷贝、看 version.txt」这三步哪怕只是改一行nexus.vmoptions。吃过一次亏内存参数改错导致启动失败数据目录里的索引没来得及刷盘虽然最后靠重建索引恢复了但那半天全组人都在等。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑