私有包管理
在企业级开发中,通常需要管理内部私有包。这些包可能包含专有代码、内部工具或敏感配置,不适合发布到公共仓库。本节介绍如何搭建和使用私有 npm 仓库。
为什么需要私有仓库?
安全性
内部代码可能包含敏感信息,如 API 密钥、加密算法、业务逻辑等,不能暴露到公共仓库。
效率
私有仓库可以作为公共仓库的缓存代理,加速依赖下载,减少网络延迟。
稳定性
不依赖外部网络,即使公共仓库不可用,内部开发也能正常进行。
控制力
可以控制哪些包可以使用,阻止有安全漏洞的包进入项目。
私有仓库方案
1. npm 官方私有包
npm 官方提供私有包服务,适合小型团队。
特点
- 无需搭建服务器
- 与 npm 生态无缝集成
- 支持团队协作
限制
- 需要付费订阅
- 私有包数量有限制
使用方式
# 创建 scoped 包
npm init --scope=@mycompany
# 发布私有包
npm publish --access restricted
# 发布公开 scoped 包
npm publish --access public
2. Verdaccio
Verdaccio 是一个轻量级的私有 npm 代理仓库,开源免费。
特点
- 零配置启动
- 支持代理公共仓库
- 内置 Web 界面
- 支持认证和权限管理
- Docker 部署简单
安装和启动
# 全局安装
npm install -g verdaccio
# 启动服务
verdaccio
# 默认运行在 http://localhost:4873
配置文件
配置文件位于 ~/.config/verdaccio/config.yaml:
# 存储路径
storage: ./storage
# 插件路径
plugins: ./plugins
# 认证配置
auth:
htpasswd:
file: ./htpasswd
max_users: 100
# 上游仓库配置
uplinks:
npmjs:
url: https://registry.npmjs.org/
taobao:
url: https://registry.npmmirror.com
# 包访问规则
packages:
# 私有包
'@mycompany/*':
access: $authenticated
publish: $authenticated
unpublish: $authenticated
proxy: npmjs
# 公共包代理
'**':
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: npmjs taobao
# 日志配置
logs:
- { type: stdout, format: pretty, level: warn }
# 监听地址
listen: 0.0.0.0:4873
用户管理
# 添加用户
npm adduser --registry http://localhost:4873
# 登录
npm login --registry http://localhost:4873
Docker 部署
# 拉取镜像
docker pull verdaccio/verdaccio
# 运行容器
docker run -it --rm --name verdaccio \
-p 4873:4873 \
-v ~/verdaccio/storage:/verdaccio/storage \
-v ~/verdaccio/config:/verdaccio/conf \
verdaccio/verdaccio
# 使用 docker-compose
# docker-compose.yml
version: '3'
services:
verdaccio:
image: verdaccio/verdaccio
ports:
- "4873:4873"
volumes:
- ./storage:/verdaccio/storage
- ./config:/verdaccio/conf
3. Nexus Repository
Sonatype Nexus 是企业级的仓库管理器,支持多种包格式。
特点
- 支持 npm、Maven、Docker、PyPI 等多种格式
- 企业级安全和权限管理
- 高可用和集群支持
- 详细的审计日志
Docker 部署
# 运行 Nexus
docker run -d --name nexus \
-p 8081:8081 \
-v nexus-data:/nexus-data \
sonatype/nexus3
# 访问 http://localhost:8081
# 默认用户: admin
# 默认密码: admin123 或查看 /nexus-data/admin.password
创建 npm 仓库
- 登录 Nexus Web 界面
- 进入 Repository → Repositories
- 创建 npm 仓库:
- npm (proxy):代理公共仓库
- npm (hosted):托管私有包
- npm (group):组合多个仓库
配置 npm 使用 Nexus
# 设置镜像源
npm config set registry http://localhost:8081/repository/npm-group/
# 或在 .npmrc 中配置
registry=http://localhost:8081/repository/npm-group/
4. JFrog Artifactory
JFrog Artifactory 是另一个企业级仓库管理器。
特点
- 支持所有主流包格式
- 高级缓存和复制功能
- 与 CI/CD 工具集成
- 企业级安全功能
Docker 部署
# 运行 Artifactory
docker run -d --name artifactory \
-p 8081:8081 -p 8082:8082 \
-v artifactory-data:/var/opt/jfrog/artifactory \
releases-docker.jfrog.io/jfrog/artifactory-oss:latest
# 访问 http://localhost:8082
5. GitHub Packages
GitHub 提供内置的包注册表服务。
特点
- 与 GitHub 仓库集成
- 支持多种包格式
- 使用 GitHub Token 认证
- 免费额度充足
配置使用
# 创建 .npmrc 文件
@mycompany:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
# 或使用 npm config
npm config set @mycompany:registry https://npm.pkg.github.com
npm config set //npm.pkg.github.com/:_authToken ${GITHUB_TOKEN}
发布包
{
"name": "@mycompany/my-package",
"publishConfig": {
"registry": "https://npm.pkg.github.com"
}
}
npm publish
6. GitLab Package Registry
GitLab 也提供内置的包注册表。
配置使用
# .npmrc
@mycompany:registry=https://gitlab.com/api/v4/projects/<project_id>/packages/npm/
//gitlab.com/api/v4/projects/<project_id>/packages/npm/:_authToken=${GITLAB_TOKEN}
配置私有仓库
项目级配置
在项目根目录创建 .npmrc 文件:
# 默认镜像源
registry=https://registry.npmmirror.com
# 私有包使用私有仓库
@mycompany:registry=https://npm.mycompany.com
# 认证令牌
//npm.mycompany.com/:_authToken=${NPM_TOKEN}
# 另一个 scope
@internal:registry=https://npm.mycompany.com
用户级配置
在用户目录创建 .npmrc 文件:
# ~/.npmrc
# 私有仓库认证
//npm.mycompany.com/:_authToken=npm_xxxx
# GitHub Packages
//npm.pkg.github.com/:_authToken=ghp_xxxx
使用环境变量
避免在配置文件中硬编码敏感信息:
# .npmrc
//npm.mycompany.com/:_authToken=${NPM_TOKEN}
# 设置环境变量
export NPM_TOKEN=npm_xxxx
# 或在 CI/CD 中设置
# GitHub Actions
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# GitLab CI
variables:
NPM_TOKEN: $CI_JOB_TOKEN
多仓库配置
当需要同时使用多个私有仓库时:
# .npmrc
registry=https://registry.npmjs.org
@company-a:registry=https://npm.company-a.com
//npm.company-a.com/:_authToken=${NPM_TOKEN_A}
@company-b:registry=https://npm.company-b.com
//npm.company-b.com/:_authToken=${NPM_TOKEN_B}
发布私有包
创建私有包
{
"name": "@mycompany/utils",
"version": "1.0.0",
"private": false,
"publishConfig": {
"registry": "https://npm.mycompany.com",
"access": "restricted"
}
}
发布流程
# 登录私有仓库
npm login --registry=https://npm.mycompany.com
# 发布前检查
npm pack --dry-run
# 发布
npm publish
# 发布到指定仓库
npm publish --registry=https://npm.mycompany.com
使用 CI/CD 发布
GitHub Actions 示例
name: Publish Package
on:
release:
types: [created]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://npm.mycompany.com'
scope: '@mycompany'
- run: npm ci
- run: npm run build
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
GitLab CI 示例
publish:
stage: deploy
script:
- npm config set @mycompany:registry https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm/
- npm config set //gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken ${CI_JOB_TOKEN}
- npm publish
only:
- tags
安全最佳实践
1. 使用令牌认证
避免使用用户名密码,使用令牌更安全:
# 创建令牌
npm token create --registry=https://npm.mycompany.com
# 查看令牌
npm token list --registry=https://npm.mycompany.com
# 撤销令牌
npm token revoke <token-id> --registry=https://npm.mycompany.com
2. 限制令牌权限
创建只读令牌用于 CI/CD:
npm token create --read-only --registry=https://npm.mycompany.com
3. 使用 .npmignore
排除敏感文件:
# .npmignore
.env
.env.local
*.key
*.pem
secrets/
credentials/
4. 审计依赖
定期检查私有包的安全问题:
npm audit --registry=https://npm.mycompany.com
5. 启用双因素认证
npm profile enable-2fa auth-and-writes --registry=https://npm.mycompany.com
常见问题
1. 认证失败
# 检查认证配置
npm config list
# 重新登录
npm logout --registry=https://npm.mycompany.com
npm login --registry=https://npm.mycompany.com
2. 包找不到
# 检查 scope 配置
npm config get @mycompany:registry
# 检查包是否存在
npm view @mycompany/my-package --registry=https://npm.mycompany.com
3. 发布失败
# 检查权限
npm access list packages @mycompany --registry=https://npm.mycompany.com
# 检查包名是否已存在
npm view @mycompany/my-package --registry=https://npm.mycompany.com
4. 网络问题
# 使用代理
npm config set proxy http://proxy.company.com:8080
npm config set https-proxy http://proxy.company.com:8080
# 或在 .npmrc 中配置
proxy=http://proxy.company.com:8080
https-proxy=http://proxy.company.com:8080
noproxy=localhost,127.0.0.1,npm.mycompany.com
私有仓库对比
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| npm 官方 | 小型团队 | 无需维护 | 付费 |
| Verdaccio | 中小型团队 | 轻量、开源 | 功能有限 |
| Nexus | 企业级 | 功能全面 | 配置复杂 |
| Artifactory | 企业级 | 高级功能 | 商业许可 |
| GitHub Packages | GitHub 用户 | 集成方便 | 绑定 GitHub |
| GitLab Registry | GitLab 用户 | 集成方便 | 绑定 GitLab |
了解更多
- Verdaccio 官网:https://verdaccio.org
- Nexus 官网:https://www.sonatype.com/products/nexus-repository
- Artifactory 官网:https://jfrog.com/artifactory
- GitHub Packages 文档:https://docs.github.com/en/packages
- GitLab Package Registry:https://docs.gitlab.com/ee/user/packages/package_registry