内部 Maven 仓库(Nexus 3)搭建记录

背景

团队内部需要一套私有 Maven 仓库:托管内部构件(正式版 + 快照),同时代理 Maven 中央仓库、缓存依赖加速构建。选型 Nexus 3(Sonatype,业界标准),Docker 容器化部署,前端由 Caddy 反向代理自动签发 HTTPS 证书。

整体架构

说明:本文涉及的真实域名、服务器 IP、密码均已脱敏,示例中的 repo.example.com 为占位符。

公网 HTTPS ──> Caddy(自动证书)──> Nexus 3 容器(127.0.0.1:8081)
                                  ├─ maven-releases   (hosted  正式版)
                                  ├─ maven-snapshots  (hosted  快照版)
                                  ├─ maven-central    (proxy   中央仓库代理)
                                  └─ maven-public     (group   日常统一入口)

仓库设计

仓库类型用途写策略
maven-releaseshosted正式版本发布ALLOW(允许重复发布)
maven-snapshotshosted快照版本发布ALLOW(允许重复发布)
maven-centralproxy代理 Maven 中央仓库,内容永久缓存、元数据 24h 刷新
maven-publicgroup分组(本地仓库优先),日常构建只依赖这一个地址

分组顺序为 [maven-releases, maven-snapshots, maven-central],本地构件优先于中央仓库同名构件。

账号与权限(已脱敏)

  • admin:管理员账号,初始密码在容器内 /nexus-data/admin.password,首次登录后必须修改(修改后文件自动删除)。
  • deploy:团队发布账号,绑定自定义角色 maven-deploy,仅授 releases / snapshots 的上传与读取、public 读取权限,无删除、无管理权限(删除构件由 admin 负责)。
  • 匿名访问默认关闭,所有读写需携带账号;如需开放匿名读,在 Settings → Security → Anonymous 中开启。

客户端接入

1. ~/.m2/settings.xml(下载依赖)

<settings>
  <servers>
    <server><id>internal-releases</id><username>deploy</username><password>********</password></server>
    <server><id>internal-snapshots</id><username>deploy</username><password>********</password></server>
  </servers>

  <mirrors>
    <mirror>
      <id>internal-mirror</id>
      <url>https://repo.example.com/repository/maven-public/</url>
      <mirrorOf>*</mirrorOf>
    </mirror>
  </mirrors>
</settings>

2. 项目 pom.xml(发布构件)

<distributionManagement>
  <repository>
    <id>internal-releases</id>
    <url>https://repo.example.com/repository/maven-releases/</url>
  </repository>
  <snapshotRepository>
    <id>internal-snapshots</id>
    <url>https://repo.example.com/repository/maven-snapshots/</url>
  </snapshotRepository>
</distributionManagement>

版本号不带 -SNAPSHOT 走 releases,带 -SNAPSHOT 走 snapshots,均执行 mvn deploy

部署踩坑记录

  1. EULA 未接受导致全部 403:新版 Nexus(3.7x+)首次启动后必须接受终端用户许可协议,否则所有仓库读写返回 403(响应体有明确提示)。通过 REST API 接受:先 GET /service/rest/v1/system/euladisclaimer 原文,再 POST /service/rest/v1/system/eula 提交 {"accepted":true,"disclaimer":"<原文>"}(缺少 disclaimer 会报 Invalid EULA disclaimer)。
  2. 预置仓库是空壳:默认模板生成的仓库配置为空(GET 单仓库只有 attributes:{},写策略缺失),admin 上传也 403。解决:删除后用 API 重建(DELETE /repositories/{name}POST /repositories/maven/hosted|proxy|group)。
  3. 先建账号后重建仓库导致授权失效:在重建仓库之前创建的发布用户,角色权限引用旧仓库权限对象,全部 403。解决:删除用户和角色重新创建。
  4. 严格内容校验(Tika 嗅探):上传 .jar 必须是真正的 ZIP 结构,纯文本伪装成 jar 会返回 400 “Detected content type [text/plain]”。
  5. DNS 未生效导致证书申请失败:Caddy 申请证书时域名还没解析,报 NXDOMAIN 后进入 20 分钟自动重试。DNS 生效后手动 systemctl reload caddy 可立即触发重试,无需等待。

日常运维

  • 日志:docker logs nexus --tail 100,详细日志 docker exec nexus tail -f /nexus-data/log/nexus.log
  • 备份(官方方式):docker run --rm -v nexus-data:/data -v /backup:/backup alpine tar czf /backup/nexus-$(date +%F).tar.gz /data
  • 内存:Nexus 是 Java 应用,低配机器务必限制 JVM(本例 -Xms256m -Xmx512m -XX:MaxDirectMemorySize=256m -XX:MaxMetaspaceSize=256m),实测运行占用约 500M。
  • 清理:建议在 UI 配置清理策略,定期删除长期未使用的快照构件。