Sinopia | 从零开始搭建npm仓库

Sinopia | 从零开始搭建npm仓库

使用 Node.js 开发商业项目,其中除了技术选型,最令人纠结的一个问题就是私有NPM怎么托管,有的人说:

我用 git+ssh 这种方式直接引用到 GitHub 项目地址

嗯,这种方式可行,也最简单,但真真的太烂了,姑且不说不能使用 semver,关键还是 url 太丑,如果是强迫症真的没法忍~

我用 cnpm 代理

暂且不论 cnpm 只是作为镜像使用,其实这个方案缺点就挺多的,用的人多,速度不一定快,缓存,关键是不支持发布包以及登陆、注册,再加上配置过于复杂。

那好,我是土豪,我要买 npm on-site

说实在的,我就是从这个方案跳出来的,因为 npm 的服务对于国内团队真的是挺贵,而且还死慢,得不偿失,性价比太低。

好,下面进入正题了,我今天就是要给你们安利新get的神器:Sinopia,首先,要介绍一下这个项目的作者:

是的,看上去是一个大神,也是一只猫~ 往社区内贡献过很多代码,包括 jshttp, markdown-it 等等,也是 Node.js 核心代码库的活跃贡献者。

是的,我今天要安利的项目大家都看到了,就是1779颗星星(✨)的那个项目,不过这里插句题外话,看到项目里面基本都不怎么更新了,不过好在我在使用的过程没怎么遇到 Bug。

首先,我先大概讲讲 Sinopia 的思路,我大概扫过一眼代码,大致有以下三点:

  1. 通过兼容官方的 Registry 的接口来对终端中 NPM 命令的兼容,从而不需要使用像 cnpm 这样的命令

  2. 正是由于 npm 支持诸如 --registry 以及 .npmrc 这样的配置文件,所以才使得上一条可以正常使用,而不需要任何 hacky 的代价

  3. 官方的 npm 使用 CouchDB 作为仓库数据库(大致听说),不过 Sinopia 将直接使用文件系统来作为存储结构,这样可以非常方便我们对缓存以及发布的仓库进行查看

上图就是一个 Sinopia Registry 的仓库截图。

下面就开始搭建 Registry 服务器,其实作者已经将步骤简化到不能再简单了,如果本地搭建,直接通过:

$ npm install sinopia -g

然后再通过:

npm set registry localhost:4873/

来设置客户端使用的npm代理,然后就能正常使用了,接下来,为了可以发布你的私有库,你需要一个用户名:

npm adduser --registry localhost:4873

按照 npm 所给的提示输入完毕后,需要再登陆一次(之前的 adduser 相当于注册用户):

npm login

同样根据提示完成登陆,这个时候,打开 ~/.npmrc 你就应该能看到更新后的配置文件,接着你就可以使用 npm publish 来发布代码库到你的这个私有仓库给你的团队小伙伴使用了。

事情还没完,眼睛尖的小伙伴可能已经发现:

诶?npm adduser 貌似不需要任何验证就能添加,那岂不是所有人都能访问到我的私有仓库代码了吗?

答案是 YES,不过不用着急,奴家这就说说怎么来配置验证与角色权限。

首先你在启动 sinopia 的时候,可以指定一个配置文件,在里面可以设置一些像:

  • storage: 仓库保存的路径

  • web: 是否支持WEB接口

  • auth: 验证相关

  • uplinks: 配置上游的npm服务器,主要是用于请求的仓库不存在时去上游服务器拉取

  • packages: 配置模块/包的发布(publish)、下载(access)的权限等

  • listen: 配置监听端口与主机名

这里着重讲一讲 auth 和 packages 的用法。

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: -1

最后一行特别重要,这里我们将最大用户数设置为-1,表示禁用 npm adduser 命令来创建用户,不过我们仍然可以通过当前目录下的 htpasswd 文件来初始化用户,这里我们可以将团队小伙伴的用户名密码都添加了进来,下面就是一个示例:

yorkie:{SHA}?????????????????=:autocreated 2016-02-05T15:33:46.238Z

weflex:{SHA}????????????????=:autocreated 2016-02-05T15:39:19.960Z

james:{SHA}????????????????=:autocreated 2016-02-05T17:59:05.041Z

scott:{SHA}????????????????=:autocreated 2016-02-05T17:59:05.041Z

naruto:{SHA}??????????????=:autocreated 2016-02-05T17:59:05.041Z

上面的加密算法也很简单,就是简单的SHA1哈稀之后再转换成 Base64 输出就好,后面跟着的只是表示时间。

好,接下来说一下 packages:

packages:

'@weflex/*':

access: $authenticated

publish:

- admin

- yorkie

'*':

access: $all

publish: $authenticated

proxy: npmjs

可以看到上面的配置大致分为两个部分,一个是以 @weflex/* 为开头的,另一个则是通配符 *。

这个当然就是对 package.json 中的 name 字段进行匹配,比如 @weflex/app 将匹配第一个配置,而 express 则匹配第二个。

这里这么配置的意义在于:一般团队或者公司的私有项目,会采用不同的权限控制,于是这里借用了 NPM 的 scoped name 即 @company 的形式,例如 @weflex/app 即表示 WeFlex 下属的 app 项目了。

接下来,每一个命名过滤器(filter)下都有三项基本设置:

  1. access: 表示哪一类用户可以对匹配的项目进行安装(install)

  2. publish: 表示哪一类用户可以对匹配的项目进行发布(publish)

  3. proxy: 如其名,这里的值是对应于 uplinks 的

对于1和2的值,我们通常有以下一些可选的配置:

  1. $all 表示所有人都可以执行对应的操作

  2. $authenticated 表示只有通过验证的人可以执行对应操作

  3. $anonymous 表示只有匿名者可以进行对应操作(通常无用)

  4. 或者也可以指定对应于之前我们配置的用户表 htpasswd 中的一个或多个用户,这样就明确地指定哪些用户可以执行匹配的操作

所以,上面 packages 的配置文件可以解读为:

  1. 验证过的用户可以安装 @weflex 下的包

  2. 名为 admin 或 yorkie 的用户可以发布 @weflex 下的包

  3. 所有人都可以获取到非 @weflex 下的包

  4. 验证过的用户可以发布非 @weflex 下的包

配置完成后,再运行:

$ sinopia -c config.yml

就能放心、安全地使用你的 NPM 包了。配置完成后,如果你设置了 web.enable 为 true 的话,还可以通过网页的方式来浏览你的 Registry 情况。

另外,关于如何托管你的进程,你可以使用 docker, pm2 或者 forever 都可以。不过记住,千万要保存好你的 htpasswd 文件,不要泄漏到任何公有仓库中去。

至此,一个可以完整使用的 NPM Registry 服务器就搭建完成,虽然文章很长,但是整个搭建过程真的很短,很简单,希望可以给各位一个比较好的商业NPM以及NPM翻墙的解决方案。

不过,以上的情况并没有考虑在遇到一些黑客攻击的情况下,所以为了尽量保证代码的安全,可以在前端加一层 Nginx 然后配置 SSH 公钥来作为双层验证。

该文从我的微信公众号拷贝:Sinopia | 从零开始搭建npm仓库

发布于 2016-05-13