线上node服务的配置和维护,使用非root账户运行和sudo管理
发布于 4 年前 作者 zstxt1989 8434 次浏览 来自 分享

本人不是运维,无奈公司没有运维,我只能被赶鸭子上架,唉~

之前一直用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 时候就不行了,因为 nvmpm2 都默认安装在 /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 下,并且会在指定的环境变量下运行。

继续摸索

暂且先写到这里,再有什么想法的话还会继续写下去,也欢迎各位大牛提出更好的建议

8 回复

我也是,项目也是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 好的,谢谢!

回到顶部