本人不是运维,无奈公司没有运维,我只能被赶鸭子上架,唉~
之前一直用root+pm2跑node服务,现在觉得这样不好,随着应用越来越复杂,万一被人黑了咋办,所以开始尝试使用最小权限来运行node服务。
第一步,使用非root账户运行node进程
切换用户,使用 www 用户来运行node进程,这个比较简单,只需要在 app.js 里加上下面一句
//指定运行用户
if (process.env.NODE_USER) {
console.log("run as "+process.env.NODE_USER)
process.setuid(process.env.NODE_USER)
}
然后在 pm2 配置文件 process.json 的env中加上 “NODE_USER”:“www”,或者执行命令的时候在命令前面加,就像
NODE_USER=www pm2 start process.json
然后node进程就会以 “www” 用户来运行了,那么我只需要把 www 设置为 /sbin/nologin 就可以了,应用目录权限也相应做一些调整。
第二步,使用sudo管理pm2
由于使用了 ‘gogs’ ,可以通过git钩子实现自动部署,而gogs是用的git用户来运行的,当需要自动 pm2 reload
时候就不行了,因为 nvm
和 pm2
都默认安装在 /root/.nvm
下面。
那么git用户只能通过sudo来执行pm2了,于是经过 visudo
配置,给 git 用户开通sudo权限,但是发现 sudo pm2
的时候会提示 pm2命令不存在
。
这是因为sudo不会继承当前 PATH 环境变量,看sudo配置是这样的
Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin
而我们的 pm2 命令在
/root/.nvm/versions/node/v6.0.0/bin/pm2
那么把 /root/.nvm/versions/node/v6.0.0/bin
目录加到sudo的 secure_path 是个办法,但是万一哪天切换node版本的话,很可能会忘了同步修改这个路径,而且 pm2 的运行时文件也保存在 /root/.pm2,总之东西全都在 /root 下面,这样总感觉很不好。
于是我决定重新安装 nvm,首先我安装nvm时通过指定环境变量 export NVM_DIR="/usr/local/nvm"
这样就可以把nvm安装到 /usr/local
下面。
之后安装cnpm,node,pm2,这些也都会在 /usr/local/nvm/versions/node/.../bin
下面。
安装好后,修改用户的 .bashrc
或者 /etc/profile
添加
export NVM_DIR="/usr/local/nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
原来 /root/.bashrc 里面也有类似的,把 nvm_dir 改一下就行。
接下来是PM2的问题,pm2默认运行目录是取当前用户的 $HOME/.pm2 ,这就造成每个用户都会启动一个新的 pm2 守护进程,也无法看到别的用户运行的node进程,总而言之,git用户即使使用 sudo pm2 list
也无法看到root启动的pm2 进程。
这个问题通过查手册也解决了,可以通过指定一个环境变量 PM2_HOME
来指定 .pm2
的位置,我把它指定到 /var/run/pm2
方便所有用户访问,同样在 /etc/profile
或者类似功能的脚本中加上 export PM2_HOME="/var/run/pm2"
即可。
然后将原来的进程杀掉 PM2_HOME=/root/.pm2 pm2 kill
,再启动新的pm2进程即可,注意为了让环境变量生效,需要先执行 source /etc/profile
。
接下来还要解决一个问题,就是之前提到的,在 sudo 配置文件中写死 PATH 可能导致以后切换node版本出问题,为了解决这个问题,我通过写一个shell脚本来初始化环境变量并执行目标命令,比如
sudo /home/git/sv pm2 list
‘/home/git/sv’ 就是这个shell脚本内容很简单
#/bin/sh
export PM2_HOME="/var/run/pm2"
export NVM_DIR="/usr/local/nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
export PATH=$PATH:"/usr/local/nvm/versions/node/`nvm current`/bin"
$@
前面几行就是初始化环境变量,会自动通过 nvm current
获取node版本号,并生成对应版本的 bin 目录,最后一行 $@
就是将 ./sv 后面的参数作为命令来执行,比如前面的命令中 $@ 就等同于执行 pm2 list
,唯一的区别就是它会在 sudo 下,并且会在指定的环境变量下运行。
继续摸索
暂且先写到这里,再有什么想法的话还会继续写下去,也欢迎各位大牛提出更好的建议
docker
我也是,项目也是root+PM2运行的,也没有运维。linux这块也不是很熟。最近用了nvm后,发现在执行npm install的时候提示要超级权限,用了sudo npm install命令后发现command not found。
@chloe 现在用docker的越来越多了,是时候来一波了
@imhered 重新安装吧,不要安装到/root下面
@zstxt1989 就是不用root用户安装?还是安装的时候能选?
@imhered 用不用root都一样,只是安装到全局,比如/usr/local/nvm,安装之前先设置一下环境变量 export NVM_DIR="/usr/local/nvm"
这样就可以把nvm安装到 /usr/local
下面
@imhered 其他用户之所以没有权限是因为你安装到root用户的home目录里了
@zstxt1989 好的,谢谢!