Linux入门教程:在 CentOS 7 平台使用 cnpmjs.org 搭建 npm 私有仓储, 2、修改默认 yu
Linux入门教程:在 CentOS 7 平台使用 cnpmjs.org 搭建 npm 私有仓储, 2、修改默认 yu
一、安装系统并配置编译环境
1、下载 CentOS 7 系统镜像并安装,选择基本开发环境。
2、修改默认 yum 源为阿里云源,并添加 EPEL 源。
# 如提示 wget 不存在,可使用 curl 下载
# 备份默认源
sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
# 修改为阿里源
sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
# 添加 EPEL 源
sudo wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
3、安装 gcc 编译环境
sudo yum install gcc-c++ make
4、验证安装结果
# 验证 g++ 版本
g++ -v
使用内建 specs。
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
目标:x86_64-redhat-linux
配置为:../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
线程模型:posix
gcc 版本 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
# 验证 make 版本
make -v
GNU Make 3.82
Built for x86_64-redhat-linux-gnu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
二、监测环境并安装 node.js
1、执行环境检测脚本,下载 node 在相应环境的已编译包
curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
2、安装 node 和 npm
sudo yum -y install nodejs
3、验证安装结果
# 验证 node 版本
node -v
v8.9.4
# 验证 npm 版本
npm -v
5.6.0
三、安装并配置 cnpmjs.org
1、安装 cnpmjs.org依赖
# 安装 cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 安装 node-pre-gyp
cnpm install -g node-pre-gyp
# 安装 sqlite3 直接安装会报错 node-pre-gyp: 未找到命令
cnpm install -g sqlite3
# 安装 cnpmjs.org
cnpm install -g cnpmjs.org
# 创建配置目录 ~/.cnpmjs.org
cnpmjs.org start
2、验证安装结果
# 验证 cnpm 版本
cnpm -v
cnpm@5.2.0 (/usr/lib/node_modules/cnpm/lib/parse_argv.js)
npm@5.7.1 (/usr/lib/node_modules/cnpm/node_modules/npm/lib/npm.js)
node@8.9.4 (/usr/bin/node)
npminstall@3.3.0 (/usr/lib/node_modules/cnpm/node_modules/npminstall/lib/index.js)
prefix=/usr
linux x64 3.10.0-327.el7.x86_64
registry=https://registry.npm.taobao.org
# 验证 node-pre-gyp 版本
node-pre-gyp -v
v0.6.39
# 验证 sqlite3 版本
sqlite3 -version
3.7.17 2013-05-20 00:56:22 118a3b35693b134d56ebd780123b7fd6f1497668
# 验证 cnpmjs.org 版本
cnpmjs.org --version
2.19.4
3、添加防火墙例外
# 检查防火墙状态
systemctl status firewalld
# 启动防火墙,未启动会报错 FirewallD is not running
systemctl start firewalld
# 添加 7001 端口
firewall-cmd --zone=public --add-port=7001/tcp --permanent
# 添加 7002 端口
firewall-cmd --zone=public --add-port=7002/tcp --permanent
# 根据需要,关闭防火墙
systemctl stop firewalld
四、修改 cnpmjs.org 配置
1、修改 /root/.cnpmjs.org/config.json (实际使用中必须删除注释,否则 json 格式错误)
{
"registryPort": 7001, // cnpmjs.org web 站点端口
"webPort": 7002, // cnpmjs.org register 端口
"bindingHost": "0.0.0.0", // 允许外部访问
"handleSyncRegistry": "http://127.0.0.1:7001", // 同步源
"registryHost": "registry.npm.xxxxxx.work", // cnpmjs.org register 域名
"scopes": [
"@xxxxxx" // 私有包 scope 名称
],
"enablePrivate": false, // 允许所有登录用户发布私有包
"syncModel": "none", // 不同步公共包
"alwaysAuth": false, // 不强制用户认证
"customReadmeFile": "/root/.cnpmjs.org/docs/web/readme.md", // 自定义首页
"userService": "/root/.cnpmjs.org/services/custom_user_service.js", // 自定义用户认证
"admins": {
"admin": "admin@xxxx.com" // cnpmjs.org 管理员
},
"database": { // cnpmjs.org 数据库
"db": "cnpmjs_test", // 数据库名称
"username": "root", // 数据库用户名
"password": "", // 数据库密码
"dialect": "sqlite", // 数据库类型
"host": "127.0.0.1", // 数据库 IP
"port": 3306, // 数据库端口
"storage": "/root/.cnpmjs.org/data.sqlite" // sqlite 数据库位置
}
}
2、修改 cnpmjs.org 源码
/usr/lib/node_modules/cnpmjs.org/services/user.js
11 + if(typeof(config.userService) === 'string') {
12 + var CustomUserService = require(config.userService);
13 + config.userService = new CustomUserService();
14 + }
3、自定义首页 /root/.cnpmjs.org/docs/web/readme.md
# 公司 npm 私有仓储
[npm.xxxxxx.work](http://npm.xxxxxx.work) 基于 [cnpmjs.org](https://github.com/cnpm/cnpmjs.org) 搭建,使用 @xxxxxx 作为私有仓储的 [scope](https://docs.npmjs.com/getting-start)
仅用于托管公司私有包,不同步公共包,可使用 npm 或 cnpm 客户端。
## npm 或 cnpm 客户端配置
1. 拦截 @xxxxxx 作用域下所有操作至私有仓储,可安装公司私有包。
``bash
# 或替换为 cnpm 命令
$ npm config set @xxxxxx:registry http://registry.npm.xxxxxx.work
``
2. 使用 [git.xxxxxx.work](http://git.xxxxxx.work) 用户名和[个人访问令牌](http://git.xxxxxx.work/profile/personal_access_tokens)登录,可发布公司私有包。
``bash
# 或替换为 cnpm 命令
$ npm login --scope=@xxxxxx --registry=http://registry.npm.xxxxxx.work
Username: zhangsan # 用户名
Password: xxxxxxxxxxxxxxxxxxxx # 个人访问令牌(需勾选 Scopes 中 api 选项)
Email: (this IS public) zhangsan@xxxx.com # 邮箱
``
## 更多信息请查看[使用说明](http://xxxxxx.wiki/pages/viewpage.action?pageId=8524381)
**此处粘贴 /usr/lib/node_modules/cnpmjs.org/docs/web/readme.md 文件内容**
4、自定义用户认证 /root/.cnpmjs.org/services/custom_user_service.js
const http = require('http');
const isAdmin = require('cnpmjs.org/lib/common').isAdmin;
const config = require('cnpmjs.org/config');
// User: https://github.com/cnpm/cnpmjs.org/wiki/Use-Your-Own-User-Authorization#user-data-structure
// {
// "login": "fengmk2",
// "email": "fengmk2@gmail.com",
// "name": "Yuan Feng",
// "html_url": "http://fengmk2.github.com",
// "avatar_url": "https://avatars3.githubusercontent.com/u/156269?s=460",
// "im_url": "",
// "site_admin": false,
// "scopes": ["@org1", "@org2"]
// }
const emailDomain = '@xxxx.com';
const defaultToken = 'xxxxxxxxxxxxxxxxxxxx';
function convertToUser(gitUser) {
let user = {
login: gitUser.username,
email: gitUser.email || `${gitUser.username}${emailDomain}`,
name: gitUser.name,
html_url: gitUser.web_url,
avatar_url: gitUser.avatar_url,
im_url: '',
site_admin: isAdmin(gitUser.username),
scopes: config.scopes,
};
return user;
}
function gitHttp(api, token) {
return new Promise((resolve, reject) => {
let options = {
method: 'GET',
port: 80,
hostname: 'git.xxxxxx.work',
path: `/api/v4${api}`,
headers: {
'PRIVATE-TOKEN': token
}
};
let req = http.request(options, (res) => {
if (res.statusCode === 200) {
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => {
rawData += chunk;
});
res.on('end', () => {
try {
let parsedData = JSON.parse(rawData);
console.log(`[CustomUserService] [${api}] [${token}] JSON.parse: success`, parsedData);
resolve(parsedData);
} catch (e) {
reject(`[CustomUserService] [${api}] [${token}] JSON.parse: ${e.message}`, e);
}
});
}
else {
reject(`[CustomUserService] [${api}] [${token}] statusCode: ${res.statusCode}`);
}
});
req.on('error', (e) => {
reject(`[CustomUserService] [${api}] [${token}] error: ${e.message}`, e);
});
req.end();
});
}
function* gitAuth(username, token) {
let data = yield gitHttp('/user', token);
let gitUser = null;
if (data && data.username === username) {
gitUser = data;
}
return gitUser;
}
function* gitGet(username) {
let data = yield gitHttp(`/users?username=${encodeURIComponent(username)}`, defaultToken);
let gitUser = null;
if (data && data.length > 0 && data[0].username === username) {
gitUser = data[0];
}
return gitUser;
}
function* gitList(usernames) {
let gitUsers = [];
if (usernames && usernames.length > 0) {
for (let i = 0; i < usernames.length; i++) {
let username = usernames[i];
let gitUser = yield gitGet(username);
if (gitUser) {
gitUsers.push(gitUser);
}
}
}
return gitUsers;
}
function* gitSearch(query, limit) {
let data = yield gitHttp(`/users?search=${encodeURIComponent(query)}&per_page=${limit}`, defaultToken);
let gitUsers = [];
if (data && data.length > 0) {
gitUsers = data;
}
return gitUsers;
}
function CustomUserService() { }
const proto = CustomUserService.prototype;
/**
* Auth user with login name and password
* @param {String} login login name
* @param {String} password login password
* @return {User}
*/
proto.auth = function* (login, password) {
console.log(`[CustomUserService] [auth]`, login, password);
let user = null;
try {
let gitUser = yield gitAuth(login, password);
if (gitUser) {
user = convertToUser(gitUser);
}
}
catch (e) {
console.log(`[CustomUserService] [auth]`, e);
}
return user;
};
/**
* Get user by login name
* @param {String} login login name
* @return {User}
*/
proto.get = function* (login) {
console.log(`[CustomUserService] [get]`, login);
let user = null;
try {
let gitUser = yield gitGet(login);
if (gitUser) {
user = convertToUser(gitUser);
}
}
catch (e) {
console.log(`[CustomUserService] [get]`, e);
}
return user;
};
/**
* List users
* @param {Array<String>} logins login names
* @return {Array<User>}
*/
proto.list = function* (logins) {
console.log(`[CustomUserService] [list]`, logins);
let users = [];
try {
let gitUsers = yield gitList(logins);
gitUsers.forEach((gitUser) => {
users.push(convertToUser(gitUser));
});
}
catch (e) {
console.log(`[CustomUserService] [list]`, e);
}
return users;
};
/**
* Search users
* @param {String} query query keyword
* @param {Object} [options] optional query params
* - {Number} limit match users count, default is `20`
* @return {Array<User>}
*/
proto.search = function* (query, options) {
console.log(`[CustomUserService] [search]`, query, options);
let users = [];
try {
options = options || {};
options.limit = parseInt(options.limit);
if (!options.limit || options.limit < 0) {
options.limit = 20;
}
let gitUsers = yield gitSearch(query, options.limit);
gitUsers.forEach((gitUser) => {
users.push(convertToUser(gitUser));
});
}
catch (e) {
console.log(`[CustomUserService] [search]`, e);
}
return users;
};
module.exports = CustomUserService;
5、验证自定义配置
export NODE_PATH=/usr/lib/node_modules && /usr/bin/cnpmjs.org start
Starting cnpmjs.org ...
cluster: false
admins: {"admin":"admin@xxxx.com"}
scopes: ["@xxxxxx"]
sourceNpmRegistry: https://registry.npm.taobao.org
syncModel: none
[Tue Mar 06 2018 17:05:20 GMT+0800 (CST)] [worker:8004] Server started, registry server listen at 0.0.0.0:7001, web listen at 0.0.0.0:7002, cluster: false
五、开机启动 cnpmjs.org 并配置域名和定期备份
1、创建服务并开机自启 /usr/lib/systemd/system/cnpmjs.org.service
[Unit]
Description=cnpmjs.org
After=network.target
[Service]
Type=simple
User=root
Environment=NODE_PATH=/usr/lib/node_modules
ExecStart=/usr/bin/cnpmjs.org start
ExecStop=/usr/bin/cnpmjs.org stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target
2、应用并启动 cnpmjs.org 服务
# 刷新服务守护进程
systemctl daemon-reload
# 启动 cnpmjs.org 服务
systemctl start cnpmjs.org.service
# 设置开机启动
systemctl enable cnpmjs.org.service
# 查看启动日志
journalctl -u cnpmjs.org.service
3、配置 nginx 反向代理
# cnpmjs.org registry
server {
listen 80;
server_name registry.npm.xxxxxx.work;
location / {
#proxy_redirect off;
proxy_pass http://192.168.21.23:7001;
}
}
# cnpmjs.org web
server {
listen 80;
server_name npm.xxxxxx.work;
location / {
#proxy_redirect off;
proxy_pass http://192.168.21.23:7002;
}
}
4、验证域名配置
curl npm.xxxxxx.work
curl registry.npm.xxxxxx.work
5、创建备份脚本 /root/.cnpmjs.org/backup/backup.sh
由于 cnpmjs.org 使用文件方式存放已发布的包,因此只用备份 sqlite 数据库即可。
#!/bin/sh
# 当前时间
var_dateTime=$(date +%Y%m%d%H%M)
# cnpmjs.org 配置目录
var_workDir="/root/.cnpmjs.org"
# 备份目录
var_backupDir=${var_workDir}"/backup/"${var_dateTime}
# 创建备份目录
mkdir -p ${var_backupDir}
# 数据库源位置
var_dataSource=${var_workDir}"/data.sqlite"
# 数据库目标位置
var_dataTarget=${var_backupDir}"/data.sqlite"
# 备份数据库
sqlite3 ${var_dataSource} ".backup ${var_dataTarget}"
6、验证备份脚本
# 修改备份脚本执行权限
chmod a+x /root/.cnpmjs.org/backup/backup.sh
# 执行备份脚本
/root/.cnpmjs.org/backup/backup.sh
# 检查是否已经生成备份
ls -l /root/.cnpmjs.org/backup/
7、配置定时任务
# 编辑定时任务文件 /var/spool/cron/root
crontab -e
# 每周日 00:00 执行备份
0 0 * * 0 /root/.cnpmjs.org/backup/backup.sh
# 如果未正常进行,检查以下文件
cat /var/log/cron
cat /var/spool/mail/root
六、【非服务端】npm 或 cnpm 客户端配置
1、拦截 @xxxxxx 作用域下所有操作至私有仓储,可安装公司私有包。
# 或替换为 cnpm 命令
npm config set @xxxxxx:registry http://registry.npm.xxxxxx.work
2、使用 git.xxxxxx.work 用户名和个人访问令牌登录,可发布公司私有包。
# 或替换为 cnpm 命令
npm login --scope=@xxxxxx --registry=http://registry.npm.xxxxxx.work
Username: zhangsan # 用户名
Password: xxxxxxxxxxxxxxxxxxxx # 个人访问令牌(需勾选 Scopes 中 api 选项)
Email: (this IS public) zhangsan@xxxx.com # 邮箱
评论暂时关闭