npm私服搭建与包发布

需求与背景

需求

  • 公司开发环境与外网隔绝,须要搭建内网私有npm库,确保私密性
  • 确保npm服务快速、稳定,减小开发人员和CI服务器的重复下载量并提升下载速度
  • 控制npm模块质量和安全,对于下载、发布npm包有对应的权限管理

当下流行的解决方案

  • 使用 Nexus 搭建 npm 私服

    Nexus仓库管理平台支持范围普遍,可用于maven、npm等仓库。目前Nexus Repository Manager更新到了3,查看官方文档html

  • 使用 Sinopia 搭建 npm 私服

    Sinopia是一个零配置的私有的带缓存功能的npm包管理工具。前端

搭建过程

使用Nexus

  • 下载解压

    官方下载连接](help.sonatype.com/repomanager…),执行:java

    $ wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz #下载
    $ sudo mv latest-unix.tar.gz /opt/nexus3.tar.gz #移动到 /opt 目录
    $ sudo tar -xzvf nexus3.tar.gz #解压
    复制代码

    注意运行Nexus须要Java 8 运行时环境(JRE),请自行安装。node

  • 建立运行用户

    单首创建一个 nexus 用户用来运行linux

    # 建立用户、指定用户目录、受权
    $ sudo useradd -d /home/nexus -m nexus
    $ sudo chown -R nexus:nexus /home/nexus
    $ sudo chown -R nexus:nexus /opt/nexus-3.15.2-01
    $ sudo chown -R nexus:nexus /opt/sonatype-work/
    复制代码

    修改运行用户配置项:修改 /opt/nexus-3.15.2-01/bin 目录下的配置文件nexus.rc为 run_as_user="nexus"android

  • 运行

    修改端口指8073并开放iptables防火墙,对/opt/sonatype-work/nexus3/etc/nexus.properties文件进行修改:git

    # Jetty section 
    application-port=8073
    application-host=0.0.0.0                                                                 # nexus-args=${jetty.etc}/jetty.xml,${jetty.etc}/jetty-http.xml,${jetty.etc}/jetty-requestlog.xml 
    # nexus-context-path=/ # Nexus section # nexus-edition=nexus-pro-edition # nexus-features=\ # nexus-pro-feature 
    复制代码

    启动服务,如下为nexus服务命令:github

    # 启动 nexus 服务
    $ sudo service nexus start
    # 重启 nexus 服务
    $ sudo service nexus restart
    # 中止 nexus 服务
    $ sudo service nexus stop
    # 查看 nexus 服务状态
    $ sudo service nexus status 
    复制代码

    查看日志检查服务状态:docker

    $ tail -f /opt/sonatype-work/nexus3/log/nexus.log
    复制代码

    至此,nexus 服务已搭建完毕!可以使用默认帐号admin/admin123 登陆ip:8073后对npm仓库进行管理npm

  • 仓库管理

    建立仓库,npm 仓库有三种,这三种咱们都须要建立

  1. npm(proxy) - 代理npm仓库

    将公共 npm 服务器的资源代理缓存,减小重复下载,加快开发人员和CI服务器的下载速度。

    建立时需填写Name(npm-external)和Remote Storage(公有库地址,填写官方或淘宝镜像,https://registry.npmjs.org/)。

    该仓库地址为:http://ip:8073/repository/npm-external/

  2. npm(hosted) - 私有npm仓库

    用于 上传本身的npm包 以及第三方npm包。

    建立时只需填写Name(npm-internal)。

    该仓库地址为:http://ip:8073/repository/npm-internal/

    请注意:发布包时请将registry设为该地址。

  3. npm(group) - npm仓库组

    用于将多个内部或外部 npm 仓库统一为一个 npm仓库。能够新建一个npm仓库组将 上面两个刚刚建立的两个 npm 仓库都添加进去。这样能够经过这个 npm仓库组,既能够访问 公有npm仓库 又能够访问本身的 私有npm仓库。

    建立时需填写Name(npm-all),而后选择须要添加到组里的 其余 npm 仓库(npm-externalnpm-internal)。

    该仓库地址为:http://ip:8073/repository/npm-all/

    请注意:安装包以及卸载包时请将registry设为该地址。

  • 用户管理

    将包发布到nexus npm仓库须要设置一下 Nexus Repository Manager 的权限。不然没法登录到咱们的私服。在Security->Realms栏目里,将npm Bearer Token Realm 选入Active。

以后咱们须要在Security->Users栏目里添加用户,只有这样添加的用户才能够发布包。经测试,在客户端使用 npm adduser 建立的用户没有发布权限。

使用Sinopia

  • 服务器上安装node

    Node 官网已经把 linux 下载版本更改成已编译好的版本了,咱们能够直接下载解压后使用,下载连接

    咱们选择node-v11.9.0-linux-x64.tar.gz这个版本:

    $ wget https://nodejs.org/dist/v11.9.0/node-v11.9.0-linux-x64.tar.gz   #下载
    $ tar xf node-v11.9.0-linux-x64.tar.gz       #解压
    $ cd node-v11.9.0-linux-x64/                 #进入解压目录
    $ ./bin/node -v                              #执行node命令 查看版本
    v11.9.0
    复制代码

    使用ln命令设置软连接到/usr/local/bin目录,/usr/local/bin是给用户放置本身的可执行程序的地方:

    ln -s /usr/local/node-v11.9.0-linux-x64/bin/npm   /usr/local/bin/ 
    ln -s /usr/local/node-v11.9.0-linux-x64/bin/node   /usr/local/bin/
    复制代码
  • 服务器上安装Sinopia

    使用默认npmjs.org registry,在服务器上安装sinopia:

    $ npm install -g sinopia
    $ sinopia                    
    -bash: sinopia: command not found     #测试sinopia命令,此时会报找不到命令
    复制代码

    找不到命令,缘由在于环境变量没设置,修改/etc/profile文件,在末尾添加如下内容:

    export NODE_HOME=/usr/local/node-v11.9.0-linux-x64  #Node所在路径
    export PATH=$NODE_HOME/bin:$PATH
    复制代码

    执行命令 source /etc/profile使生效,再次运行sinopia:

    $ Sinopia doesn't need superuser privileges. Don't run it under root.
     warn  --- config file  - /root/.config/sinopia/config.yaml
     warn  --- http address - http://localhost:4873/
    复制代码

    修改iptables设置,开放4873端口:

    $ iptables -I INPUT 4 -p tcp -m state --state NEW -m tcp --dport 4873  -j ACCEPT        #容许 4873 端口
    $ service iptables save                         #保存 iptables 规则
    复制代码

    【坑1】访问虚拟机的npm仓库地址被拒绝

    除了开放iptables的4873端口外,还须要在sinopia的配置文件末尾加上:

    listen: 0.0.0.0:4873
    复制代码

    从新启动

    $ Sinopia doesn't need superuser privileges. Don't run it under root.
     warn  --- config file  - /root/.config/sinopia/config.yaml
     warn  --- http address - http://0.0.0.0:4873/
    复制代码

    这样咱们就能经过本身虚拟机的ip:4873访问了

配置文件在/root/.config/sinopia/config.yaml,相关配置字段意义在文件中都有注释

  • 使用守护进程启动(pm2)

​ 安装:npm install -g pm2 启动:pm2 start sinopia

  • 用户管理

    配置文件中关于鉴权的默认配置为:

    auth:
      htpasswd:
        file: ./htpasswd   //保存用户的帐号密码等信息
        # Maximum amount of users allowed to register, defaults to "+inf".
        # You can set this to -1 to disable registration.
        max_users: 1000  //默认为1000,改成-1后,禁止注册
    复制代码

    添加用户的方法:在客户端终端运行 npm adduser --registry http://xxxxx:4873/ ,设置相应的用户名、密码、邮箱后便可登陆、发布包。

    若是将配置项max_users设为-1,表示禁用 npm adduser 命令来建立用户,需手动在htpasswd文件中添加用户信息来初始化用户。

客户端使用

使用 nrm 管理registry

$npm install -g nrm
 
$ nrm ls
* npm ---- https://registry.npmjs.org/
  cnpm --- http://r.cnpmjs.org/
  taobao - https://registry.npm.taobao.org/
  nj ----- https://registry.nodejitsu.com/
  rednpm - http://registry.mirror.cqupt.edu.cn/
  npmMirror  https://skimdb.npmjs.com/registry/
  edunpm - http://registry.enpmjs.org/
  
$ nrm add ynpm http://XXXXXX:4873 # 添加私服的npm镜像地址
$ nrm use ynpm # 使用私服的镜像地址
复制代码

安装包

npm install lodash # sinopia发现本地没有 lodash包,就会从 官方镜像下载
npm --loglevel info install lodash  # 设置loglevel 可查看下载包时的详细请求信息
复制代码
[storage]$ ls      
#下载过以后,私服的storage目录下回缓存安装包
[storage]$ ls                                                                                   
lodash
复制代码
rm -rf node-modules # 删除目录
npm insatll lodash # 第二次安装就会从缓存下载了,速度很快
复制代码

发布包与撤销发布包

在项目根目录下运行$ npm publish发布新包。

运行$ npm unpublish 包名 --force撤销发布包。

$ npm publish
+ @shawn280/ly-cli@1.0.0
复制代码

查看发布的包,已成功发布:

做用域scope管理发布包

常常有看到@xxx/yyy类型的开源npm包,缘由是包名称不免会有重名,若是已经有人在 npm 上注册该包名,再次 npm publish 同名包时会告知发布失败,这时能够经过 scope 做用域来解决

  • 定义做用域包

    修改package.json中包名称:

    {
         "name": "@username/project-name"
    }
    复制代码

    须要注意的是,若是是发布到官方registry,scope必定要是本身注册的用户名,而若是是发布到本身的npm私服,scope能够不是用户名

  • 发布做用域包

    做用域模块默认发布是私有的

    发布到官方registry时,直接npm publish会报错,缘由是只有付费用户才能发布私有 scope 包,免费用户只能发布公用包,所以须要添加 access=public 参数;

    发布到本身的npm私服时,不加access=public参数也能够发布

    npm publish --access=public
    复制代码
  • 使用做用域包

    npm install @username/project-name
    var projectName = require('@username/project-name')
    复制代码

总结

  • 以上的状况并无考虑在遇到一些黑客攻击的状况下,因此为了尽可能保证代码的安全,能够在前端加一层 Nginx 而后配置 SSH 公钥来做为双层验证。

  • 两种解决方案的对比:

    1. 都缓存了从proxy仓库下载过的包,没有同步整个proxy仓库的包。
    2. 存储方式:nexus使用blob store,sinopia直接保存包文件到storage目录。
    3. nexus管理界面能够清缓存;sinopia貌似没有命令和工具,可是能够删除经过删除storage目录下包目录的方式清除缓存。
    4. 使用nexus时,发布包安装、卸载包须要设置不一样的registry,而Sinopia一直用同一个就能够。
    5. nexus管理页面上展现了更多的包信息,相比而言sinopia也就是nodejs风格的包主页上信息较少。
    6. sinopia更适合前端工程,优势是配置简单,对环境依赖少(仅node就够了),而且支持在windows系统下运行;nexus支持仓库种类最多,是用户群体最大的一个仓库平台,maven、docker、npm、gradle均支持,java须要maven仓库、android须要gradle仓库、运维须要docker仓库,前端须要npm仓库,若是公司已有nexus平台管理这些仓库,接入新的仓库会较方便。
    7. sinopia 的权限管理比较弱,对用户权限,发布权限,下载权限控制不是很驾轻就熟;缓存优化不足,常常会在安装共有包的时候处于挂起状态

One more thing...

sinopia 在15年的时候就中止更新了,继而由 verdaccio 提供更新升级,二者用法基本上都是一致的。对于企业级的应用来讲,技术选型时请慎重选择sinopia,建议选择verdaccio。

参考文档

juejin.im/entry/5bceb…

zhuanlan.zhihu.com/p/35907412

segmentfault.com/a/119000000…

www.cnblogs.com/LittleSix/p…

huang-x-h.github.io/2016/06/09/…

segmentfault.com/a/119000001…

相关文章
相关标签/搜索