npm私服搭建

Verdaccio搭建私有npm仓库

参考学习地址:

概述

npm私服是什么

在私有化的服务器上部署的一个支持发布、下载、版本管理等服务的npm仓库。

为什么需要npm私服

  • 官方npmjs下载缓慢,需要设置镜像源

    镜像源:是以一定频率定时同步npm官方仓库,以此代替官方仓库,提高包下载速度,也属于私服的一种

  • 公司自己封装的组件库,不希望在网络上公开。传统方式是在每个项目里复制一遍,但组件库一旦有改动,就需要重新复制一遍,因此就需要有一个私有仓库来管理每一个组件

Verdaccio搭建私有npm仓库

Verdaccio是什么?

Verdaccio是一个 Node.js创建的轻量的私有npm代理注册源(proxy registry)

通过Verdaccio搭建私有npm服务器有着以下优势:

  1. 零配置:无需安装数据库,基于nodejs,安装及运行。
  2. 使用方便:将内部高复用的代码进行提取,方便在多个项目中引用。
  3. 安全性:仓库搭建在局域网内部,只针对内部人员使用。
  4. 权限管理:对发布和下载npm包配置权限管理。
  5. 加速包下载:将下载过的依赖包进行缓存,再次下载加快下载速度。

Verdaccio是sinopia开源框架的一个fork,由于sinopia作者两年前就已经停止更新,坑比较多,因此Verdaccio是目前最好的选择;首先进行全局安装:

bash 复制代码
# 全局安装
npm install -g verdaccio
# 启动服务器
verdaccio

安装verdaccio

js 复制代码
yarn global add verdaccio

执行命令verdaccio启动私服

js 复制代码
verdaccio

启动成功后,浏览器运行如下:

浏览器输入http://localhost:4873/ (默认的地址,verdaccio)

安装完成!

默认安装地址:C:\Users\Administrator\AppData\Roaming\verdaccio
config.yaml配置文件的路径,我们可以进行权限等配置;4873是Verdaccio启动的默认端口,支持在配置文件中进行修改;我们再浏览器中打开localhost:4873就能看到他的管理界面了:

pm2守护verdaccio进程

通过命令行启动的话,如果终端停止了,那我们的服务器也就停止了,因此我们来使用pm2对verdaccio进程进行托管启动。

安装pm2并使用pm2启动verdaccio,使用pm2托管的进程可以保证进程永远是活着的,尝试通过kill -9去杀verdaccio的进程发现杀了之后又自动启起来。推荐使用此种方式启动verdaccio.

js 复制代码
npm install -g pm2
pm2 start verdaccio
pm2 list

这样verdaccio就在后台运行了。

安装

js 复制代码
npm install -g pm2 --unsafe-perm

启动

js 复制代码
pm2 start verdaccio

查看pm2 守护下的进程verdaccio的实时日志

js 复制代码
pm2 show verdaccio          

通过这个命令我们可以从下图中看到所有verdaccio的所有信息,打开 out log path查看进程输出日志,出现错误时候也可以打开error log来查看错误日志。

实时查看该路径下的日志命令:

js 复制代码
tail -f /home/admin/.pm2/logs/verdaccio-out-0.log     

nrm管理镜像源地址

Verdaccio安装好后,我们可以更改npm源为本地地址:

js 复制代码
# 设置npm使用的源为本地私服
npm set registry http://localhost:4873/

或者针对某个依赖安装时选用自己的源地址:

js 复制代码
npm install lodash --registry http://localhost:4873

但是如果我们想再次切换到淘宝或者其他的镜像地址,就不那么方便了;我们可以通过nrm这个工具来管理我们的源地址,可以查看和切换地址;首先还是进行安装:

js 复制代码
npm install -g nrm

安装后我们可以通过nrm add [name] [address]这个命令来新增一个源地址:

js 复制代码
nrm add localnpm http://localhost:4873/

使用nrm ls可以查看我们使用的所有源地址,带*是正在使用的地址;通过nrm use [name]来切换地址:

配置文件

通过配置文件,我们可以对Verdaccio进行更多的自定义设置,默认的配置文件如下:

js 复制代码
# 依赖缓存地址
storage: ./storage
# 插件地址
plugins: ./plugins
 
web:
  title: Verdaccio
 
# 认证信息
auth:
  # 用户账号存储文件
  htpasswd:
    file: ./htpasswd
 
# 上游链接
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
 
# 包管理
packages:
  '@*/*':
    access: $all
    publish: $authenticated
    unpublish: $authenticated
    proxy: npmjs
  '**':
    access: $all
    publish: $authenticated
    unpublish: $authenticated
    proxy: npmjs
 
server:
  keepAliveTimeout: 60
 
# 插件开启
middlewares:
  audit:
    enabled: true
 
# 日志管理
logs:
  - { type: stdout, format: pretty, level: http }

Verdaccio默认只能本机访问,我们可以在配置文件最后加入监听的端口,让局域网访问:

js 复制代码
# 监听的端口,不配置这个,只能本机能访问
listen: 0.0.0.0:4873
# 界面默认设为中文
i18n:
  web: zh-CN

所有的账号密码都会保存在htpasswd这个文件中,我们可以通过在线htpasswd生成器生成加密的密码文件,或者通过命令行的形式来添加用户

js 复制代码
# 新增用户
npm adduser --registry http://localhost:4873/

上游链接uplinks表示如果在本地找不到依赖包,去上游哪个地址获取包;我们可以配置多个地址,每个地址都有一个唯一的key值:

js 复制代码
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
    timeout: 10s
  yarn:
    url: https://registry.yarnpkg.com/
    timeout: 10s
  taobao:
    url: https://registry.npm.taobao.org/
    timeout: 10s
 
packages:
  '@*/*':
    proxy: taobao yarn
  '**':
    proxy: taobao

官方的地址会比较慢,一般建议配置淘宝的地址:配置好上游链接后我们就可以将包的代理指向链接,支持多个链接地址,请求失败时会向后面的链接进行尝试。

如果本地源没有会向外网去寻找下载,配置外网的npm是找到config.yaml配置文件找到uplinks,填写上一级npm仓库的地址,如下所示:

js 复制代码
# a list of other known repositories we can talk to
uplinks:
  npmjs:
    url: https://registry.npmjs.org/

令牌

verdaccio@4.0.0开始支持配置自定义令牌签名,要启用JWT签名,我们需要将jwt添加到api部分:

js 复制代码
security:
  api:
    jwt:
      sign:
        expiresIn: 15d
        notBefore: 0
  web:
    sign:
      expiresIn: 7d

packages包管理

packages字段中,我们可以对每个域下面的包进行管理,在verdaccio中有三种身份:所有人、匿名用户、认证(登陆)用户(即"anonymous", "$authenticated"),默认情况下所有人都有访问的权限(access),认证的用户才有包的发布权限(publish)和撤回权限(unpublish)。

除此之外,我们可以对包进行更进一步的划分,比如公司的包和个人的包,通过@scope的方式进行访问控制:

js 复制代码
packages:
  '@company/*':
    access: $authenticated
    publish: $authenticated
    unpublish: $authenticated
    proxy: npmjs
  '@my/*':
    access: $authenticated
    publish: $authenticated
    unpublish: $authenticated
    proxy: npmjs

默认情况下,任何用户都可以通过npm adduser来向我们的服务器注册用户;如果我们的npm服务器部署在外网的话是不利的,我们还可以通过max_users为-1来禁止注册用户,如果在内网的话,可以设置某个具体的值来限制用户的数量:

js 复制代码
auth:
  htpasswd:
    file: ./htpasswd
  max_users: -1

配置Verdaccio

在刚刚创建的软链接目录/home/verdaccio/conf下,可以看到默认的config.yaml,现在可以做一些配置更改:

js 复制代码
# 包含所有包的目录的路径
storage: /verdaccio/storage/data
# 包含插件的目录路径
plugins: /verdaccio/plugins

# 完整的webui配置查看 https://verdaccio.org/docs/webui
web:
  enable: true
  title: npm仓库
  logo: https://lichong.work/logo
  favicon: https://lichong.work/logo
  # 主题色
  primary_color: '#8794AF'
  # gravatar头像支持
  gravatar: true
  # 包默认的排序方式
  sort_packages: asc
  # 默认用户界面转换为暗黑主题
  darkMode: false
  # html缓存
  html_cache: false
  # 默认显示所有功能
  login: true
  # 是否显示右上角verdaccio项目的相关信息
  showInfo: false
  # 是否显示右上角设置
  showSettings: true
  # 结合 darkMode 可以切换主题
  showThemeSwitch: true
  # 是否显示页脚
  showFooter: false
  # 是否可以搜索
  showSearch: true
  # 是否展示包的原始清单
  showRaw: true
  # 是否可以下载压缩包
  showDownloadTarball: true
  #  HTML tags injected after manifest <scripts/>
  # scriptsBodyAfter:
  #    - '<script type="text/javascript" src="https://my.company.com/customJS.min.js"></script>'
  #  HTML tags injected before ends </head>
  #  metaScripts:
  #    - '<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>'
  #    - '<script type="text/javascript" src="https://browser.sentry-cdn.com/5.15.5/bundle.min.js"></script>'
  #    - '<meta name="robots" content="noindex" />'
  #  HTML tags injected first child at <body/>
  #  bodyBefore:
  #    - '<div id="myId">html before webpack scripts</div>'
  #  Public path for template manifest scripts (only manifest)
  #  publicPath: http://somedomain.org/

# 认证相关完整配置查看 https://verdaccio.org/docs/configuration#authentication
auth:
  htpasswd:
    file: /verdaccio/storage/htpasswd
    # Maximum amount of users allowed to register, defaults to "+infinity".
    # You can set this to -1 to disable registration.
    # max_users: 1000
    # Hash algorithm, possible options are: "bcrypt", "md5", "sha1", "crypt".
    # algorithm: bcrypt # by default is crypt, but is recommended use bcrypt for new installations
    # Rounds number for "bcrypt", will be ignored for other algorithms.
    # rounds: 10

# 上游链路完整配置查看 https://verdaccio.org/docs/configuration#uplinks
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
  npmmirror:
    url: https://registry.npmmirror.com/

# 了解如何保护包查看 https://verdaccio.org/docs/protect-your-dependencies/
# packages完整配置查看 https://verdaccio.org/docs/configuration#packages
packages:
  '@*/*':
    access: $all
    publish: $authenticated
    unpublish: $authenticated
    proxy: npmmirror
    
  '**':
    # 可以指定用户名/组名(取决于使用的身份验证插件)和三个关键字:"$all"、"$anonymous"、"$authenticated"

    # 允许所有用户(包括未经身份验证的用户)阅读和发布所有包
    access: $all
    # 允许所有已知用户发布/发布包
    publish: $authenticated
    unpublish: $authenticated
    # 如果包在本地找不到,将请求到"npmmirror"代理去查找
    proxy: npmmirror

# To improve your security configuration and  avoid dependency confusion
# consider removing the proxy property for private packages
# https://verdaccio.org/docs/best#remove-proxy-to-increase-security-at-private-packages

# https://verdaccio.org/docs/configuration#server
# You can specify HTTP/1.1 server keep alive timeout in seconds for incoming connections.
# A value of 0 makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout.
# WORKAROUND: Through given configuration you can workaround following issue https://github.com/verdaccio/verdaccio/issues/301. Set to 0 in case 60 is not enough.
server:
  keepAliveTimeout: 60
  # Allow `req.ip` to resolve properly when Verdaccio is behind a proxy or load-balancer
  # See: https://expressjs.com/en/guide/behind-proxies.html
  # trustProxy: '127.0.0.1'

# https://verdaccio.org/docs/configuration#offline-publish
# publish:
#   allow_offline: false

# https://verdaccio.org/docs/configuration#url-prefix
# url_prefix: /verdaccio/
# VERDACCIO_PUBLIC_URL='https://somedomain.org';
# url_prefix: '/my_prefix'
# // url -> https://somedomain.org/my_prefix/
# VERDACCIO_PUBLIC_URL='https://somedomain.org';
# url_prefix: '/'
# // url -> https://somedomain.org/
# VERDACCIO_PUBLIC_URL='https://somedomain.org/first_prefix';
# url_prefix: '/second_prefix'
# // url -> https://somedomain.org/second_prefix/'

# https://verdaccio.org/docs/configuration#security
# security:
#   api:
#     legacy: true
#     jwt:
#       sign:
#         expiresIn: 29d
#       verify:
#         someProp: [value]
#    web:
#      sign:
#        expiresIn: 1h # 1 hour by default
#      verify:
#         someProp: [value]

# https://verdaccio.org/docs/configuration#user-rate-limit
# userRateLimit:
#   windowMs: 50000
#   max: 1000

# https://verdaccio.org/docs/configuration#max-body-size
# max_body_size: 10mb

# https://verdaccio.org/docs/configuration#listen-port
# listen:
# - localhost:4873            # default value
# - http://localhost:4873     # same thing
# - 0.0.0.0:4873              # listen on all addresses (INADDR_ANY)
# - https://example.org:4873  # if you want to use https
# - "[::1]:4873"                # ipv6
# - unix:/tmp/verdaccio.sock    # unix socket

# The HTTPS configuration is useful if you do not consider use a HTTP Proxy
# https://verdaccio.org/docs/configuration#https
# https:
#   key: ./path/verdaccio-key.pem
#   cert: ./path/verdaccio-cert.pem
#   ca: ./path/verdaccio-csr.pem

# https://verdaccio.org/docs/configuration#proxy
# http_proxy: http://something.local/
# https_proxy: https://something.local/

# webhook通知完整配置查看 https://verdaccio.org/docs/configuration#notifications
# notify:
#   method: POST
#   headers: [{ "Content-Type": "application/json" }]
#   endpoint: https://usagge.hipchat.com/v2/room/3729485/notification?auth_token=mySecretToken
#   content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}'

middlewares:
  audit:
    enabled: true

# https://verdaccio.org/docs/logger
# log settings
logs: { type: stdout, format: pretty, level: http }
#experiments:
#  # support for npm token command
#  token: false
#  # enable tarball URL redirect for hosting tarball with a different server, the tarball_url_redirect can be a template string
#  tarball_url_redirect: 'https://mycdn.com/verdaccio/${packageName}/${filename}'
#  # the tarball_url_redirect can be a function, takes packageName and filename and returns the url, when working with a js configuration file
#  tarball_url_redirect(packageName, filename) {
#    const signedUrl = // generate a signed url
#    return signedUrl;
#  }

# 国际化配置
i18n:
  web: zh-CN

配置完成后重启 Verdaccio 即可生效

配置文件在 /root/.config/verdaccio/config.yaml (如果找不到配置文件,请先运行 verdaccio )。这里需要修改在最后一行添加监听端口,不配置的话,只能服务器本机访问。
通过浏览器访问 verdaccio 启动页,如果服务器 ip+4873 不能访问,请先放行 4873端口,以下是启动后的界面
在配置文件config.yaml的末尾添加 listen: 0.0.0.0:4873,配置此选项则是允许任何外部的所有IP都可以访问到此服务

修改npm仓库的实际存储位置. 如: D:/npm-repo

js 复制代码
# path to a directory with all packages
storage: D:/npm-repo

npm私服如何使用

链接到npm私服

通常在一个项目中既有公共的开源组件也有公司的私有组件,利用配置.npmrc可以实现从不同的镜像源下载,但是这样做会很麻烦,举个例子如下:

react包从淘宝镜像源下载,@company-plus/util包从私服下载,需要配置.npmrc

js 复制代码
# 淘宝镜像源
registry=https://npmmirror.com
# 私有源
@company-plus:registry=http://192.168.103.37:5000

当然这样做有时也会有好处,就是如果你是在公司外网(通过VPN等方式)访问私服的话可能网络带宽没那么大,下载包会很慢,这时候这种分开镜像源的优势就会有所体现了。

我比较推荐的方式,还是利用npm私服的上行链路功能,把多个仓库聚合成一个下载入口,上面的例子.npmrc只需要配置一个私服地址registry=http://192.168.103.37:5000就可以了。

注册私服账号

执行命令输入用户名、密码、邮箱即可:

js 复制代码
npm adduser --registry http://192.168.103.37:4873/

npm 9.x及以上版本同学,执行npm adduser时需要使用--auth-type=legacy进行兼容,官方回应是9.x之后版本开始将会使用register和login命令,开始废弃adduser(目前register功能还未开发完成,所以需要使用兼容模式的adduser)

js 复制代码
npm adduser --registry http://192.168.103.37:5000/ --auth-type=legacy

发布组件到私服

npm login登录后在需要发布组件的文件夹内执行:

js 复制代码
npm publish --registry http://192.168.103.37:5000/

当前源若指向私服地址,或,在项目文件.npmrc配置一个私服地址registry=http://192.168.103.37:5000,则直接npm publish即可。

我们登录上面注册的用户,输入用户名、密码以及邮箱等

js 复制代码
# 登录账号
npm login

也可以通过npm logout退出登录,以及npm who am i查看当前登录的用户名;登录成功后就可以将我们的包进行发布了:

js 复制代码
# 发布依赖包
npm publish
相关推荐
ice___Cpu11 分钟前
Linux 基本使用和 web 程序部署 ( 8000 字 Linux 入门 )
linux·运维·前端
JYbill13 分钟前
nestjs使用ESM模块化
前端
加油吧x青年32 分钟前
Web端开启直播技术方案分享
前端·webrtc·直播
吕彬-前端1 小时前
使用vite+react+ts+Ant Design开发后台管理项目(二)
前端·react.js·前端框架
小白小白从不日白1 小时前
react hooks--useCallback
前端·react.js·前端框架
恩婧1 小时前
React项目中使用发布订阅模式
前端·react.js·前端框架·发布订阅模式
mez_Blog2 小时前
个人小结(2.0)
前端·javascript·vue.js·学习·typescript
珊珊而川2 小时前
【浏览器面试真题】sessionStorage和localStorage
前端·javascript·面试
森叶2 小时前
Electron 安装包 asar 解压定位问题实战
前端·javascript·electron
drebander2 小时前
ubuntu 安装 chrome 及 版本匹配的 chromedriver
前端·chrome