Node.js 生产环境完整部署指南
Node.js生产环境完整部署指南
项目上线之前的最后一步,生产环境搭建、代码部署,在一些公司可能是运维同事在做这些事,但是做为一名Developer掌握如何进行服务部署也是你通往全栈工程师的必经之路。本文编程语言主要讲解了Node.js,对于用户权限管理、服务器安全等级增强、MongoDB生产部署、Nginx映射等不论你使用Java、PHP、Python等编程语言在进行部署时都是可以应用到的。
快速导航
用户权限管理及登陆服务器
- 创建用户
- 用户查找
- 用户删除
- 登录远程服务器
增强服务器安全等级
- 修改端口号
- 设定iptables规则
- 设置fail2ban
Node.js生产环境部署
- 安装相关依赖模块
- nvm版本管理
- nvm安装指定Node.js版本
- demo验证
- Nginx映射
Mongodb生产环境部署
- Mongodb安装
- 防火墙中加入mongodb端口号
- 更改MongoDB默认端口号
- 开启MongoDB服务
代码部署
- 选择代码托管仓库
- 实现服务器与第三方仓库的关联
- PM2部署代码到服务器
- pm2发布遇到的一些问题
用户权限管理及登陆服务器
创建用户
-
创建用户名:
adduser demo_manager之后会提示设置密码 和一些信息 -
修改用户权限:
gpasswd -a demo_manager sudo
成功之后会出现一个添加user的提示
Adding user demo_manager to group sudo
- 编辑文件:
sudo visudo
找到
root ALL=(ALL:ALL) ALL在这段代码下面添加 这个刚创建的user ```bash demo_manager ALL=(ALL:ALL) ALL
#demo_manager 指我们新增的这个用户 以上这些规则对这个用户生效
#第一个ALL 这些规则对所有用户生效
#第二个ALL demo_manager可以任意用户来执行命令
#第三个ALL demo_manager 可以以任何的组来执行命令
#第四个ALL 这个适用于所有命令
``` ```
* 重启配置:``` service ssh restart
用户查找
- 查看用户:
cat /etc/passwd - 查看用户组:
cat /etc/group - 查看当前活跃的用户列表:
w - 查看指定用户:
cat /etc/passwd|grep root - 查看当前服务用户:
whoami
用户删除
userdel 是一个底层用于删除用户的工具。在 Debian 上,我们通常会使用 deluser 命令。userdel 会查询系统账户文件,例如 /etc/password 和 /etc/group。那么它会删除所有和用户名相关的条目。在我们删除它之前,用户名必须存在。
- 删除用户:
userdel testuser - 完全删除用户家目录:
userdel -r testuser
登录远程服务器
-
方法1:
ssh root@ip地址 -
方法2:
- 安装
zsh并编辑配置文件subl .zshrc```
通过软链接加入命令
alias ssh_demo="ssh root@ip地址"
- 安装
* 重载配置文件 `source .zshrc`
* 控制台输入`ssh_demo`将自动调用上面配置好的这个命令
* 方法3:
> 如果有多台服务器,每次都需要输入密码 这样还是有些繁琐的 适合通过私钥认证的方式来,实现无密码登录。
>
> 先确定本地有没生成过秘钥,如果之前生成过就不要在生成,这样会覆盖你之前的电脑上的秘钥,也许会影响到你的其他程序。
* 进入 .ssh 目录执行以下配置秘钥命令: ```
ssh-keygen -t rsa -b 4096 -C "demo_manager@qq.com"
``` 将会生成 id_rsa id_rsa.pub 两个文件, `cat id_rsa` 查看内容
进入.ssh目录,开启ssh代理 `eval "$(ssh-agent -s)"`
进入.ssh目录,将ssh key加入这个代理中 `ssh-add ~/.ssh/id_rsa`
以上操作是在本地电脑上生成私钥,同样现在我们登入服务器,按照上面的步骤在服务器上生成私钥,如果已经有了,就不需要了。
进入服务器,如果没有生成过密钥,重复上述步骤在服务器端生成密钥,进入.ssh目录,创建一个授权文件 `vim authorized_keys`,将本地电脑生成的公钥放入这个授权文件里 现在服务器已经持有了某台电脑的上的公钥,此时这台电脑就可不需输入密码来登录这台服务器
修改授权文件权限 `chmod 600 authorized_keys`
重启ssh服务 `sudo service ssh restart`
采用了密钥登录,如果本地链接还需要输入密码,可参考这个解决方案 [`[issue]`](https://github.com/Q-Angelo/summarize/issues/2)
## 增强服务器安全等级
#### 修改端口号
服务器默认端口是22, 出于基本的安全考虑也是需要来修改这个端口号的
修改配置文件 `vim /etc/ssh/sshd_config` 执行此命令会提示输入密码
修改port端口号 范围为1 到 65536, 0 1024之间的可能会被系统所占用,因此最好采用1024之外的
Port 39999 # 此时将会禁用22端口
UseDNS no # 此处确保为 no
加入我们为这个服务创建的用户
AllowUsers demo_manager
出去安全层面考虑 可以关闭root密码登录
PermitRootLogin no
已经配好了秘钥登录的 可以将下面是是否允许密码登录(授权) 给关掉
PasswordAuthentication no
是否允许空密码
PermitEmptyPasswords no
重启ssh服务,使端口生效 `sudo service ssh restart`
#### 设定iptables规则
清空掉所有的iptables 规则 `sudo iptables -F`
修改配置文件 `sudo vim /etc/iptables.up.rules`
*filter
允许所有建立起来的链接
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
允许所有出去的流量, 此处也可以设置一些特定的流量规则
-A OUTPUT -j ACCEPT
允许https协议下的请求链接
-A INPUT -p tcp --dport 443 -j ACCEPT
所有的网站访问一台服务器都是从80端口进去的,因此让80端口的流量可以进出
-A INPUT -p tcp --dport 80 -j ACCEPT
通过这条设定 我们登录服务器就只能通过这个端口,如果是别的防火墙就会拦截
-A INPUT -p tcp -m state --state NEW --dport 39999 -j ACCEPT
允许外网来ping这台服务器
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
记录下被拒绝的这些请求
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied:" --log-level 7
对一些恶意的请求做一些拦截 ,下面的例子意思是 如果一个ip在60内对80端口 发出了150次请求 我们就认为他是恶意请求
-A INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --set -A INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 150 -j DROP
reject all other inbound 拒绝所有其他的进入到这台服务器的流量
-A INPUT -j REJECT -A FORWARD -j REJECT
COMMIT
告诉iptables 配置文件的位置 `sudo iptables-restore < /etc/iptables.up.rules`
查看防火墙的状态 `sudo ufw status`
如果为 inactive 表示没被激活,执行此命令来激活(如果激活状态为 active) `sudo ufw enable`
设置防火墙开机自启动 `sudo vim /etc/network/if-up.d/iptables`
!/bin/sh
iptables-restore /etc/iptables.up.rules
给予这个脚本执行的权限 `sudo chmod +x /etc/network/if-up.d/iptables`
#### 设置fail2ban
Fail2Ban可以看做是个防御型的动作库,通过监控系统的日志文件,根据检测到的任何可疑的行为,可以触发不同的环境动作
安装 `sudo apt-get install fail2ban`
安装过程中出现以下错误,执行 `sudo apt-get update` 更新下源即可
Reading package lists... Done Building dependency tree Reading state information... Done E: Unable to locate package fail2ban
进入配置文件 `sudo vim /etc/fail2ban/jail.conf`
bantime 可以设置的稍微大点
bantime = 3600
destemail 可以设置为我们自己的邮箱
destemail = 2105324852@qq.com
定义下action
action = %(action_mw)s
查看fail2ban的运行状态 `sudo service fail2ban status`
停掉fail2ban服务 `sudo service fail2ban stop`
开启fail2ban服务 `sudo service fail2ban start`
## nodejs生产环境部署
#### 安装相关依赖模块
`sudo apt-get install vim openssl build-essential libssl-dev wget curl git`
#### nvm版本管理
可以使用[nvm](https://github.com/creationix/nvm)`https://github.com/creationix/nvm`这个工具来安装nodejs 方便后面的升级与管理
在控制台执行命令,安装nvm `wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash`
nvm安装成功,控制台 nvm 找不到命令,解决办法 [`[issue]`](https://github.com/Q-Angelo/summarize/issues/1)
查看所有node版本 `nvm ls-remote`
查看本地node版本 `nvm ls-remote`
#### node安装
安装nodejs版本为v6.9.5 `nvm install v6.9.5`
把这个版本指定下 `nvm use v6.9.5`
设定系统的默认版本为 v6.9.5 `nvm alias default v6.9.5`
查看node版本 `node -v`
配置npm源为国内的淘宝源 `npm --registry=https://registry.npm.taobao.org install -g npm`
增加一个系统的文件监控树 `echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p`
为了保障更快更稳定的速度,此处采用cnpm来替代npm `npm --registry=https://registry.npm.taobao.org install -g cnpm`
查看cnpm版本 `cnpm -v`
在网络不是太慢或者连不上的情况下 还是推荐使用 npm,如果有些模块如果实在拿不到我们可以通过cnpm sync 同步到npm 上 例如koa `cnpm sync koa`
安装一些常用的工具包 `npm i pm2 webpack gulp grunt-cli -g`
#### demo验证
> 到此有关nodejs的环境已安装完毕,下面给个例子来测试,上面的安装是否成功。
新建一个`app.js` `vim app.js`
const http = require('http');
http.createServer( (req, res) => { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World!'); }).listen(8081);
// 注意:如果设置了防火墙,需要在防火墙强的规则里面添加8081这个端口-A INPUT -p tcp --dport 8081 -j ACCEPT
console.log('Server Runing at http://120.26.89.1:8081');
到此Node.js的环境已安装完毕,如果想要通过不带端口号的`ip`或者域名直接来访问到服务器的`80`端口, 下一步则需要配置`Nginx`反向代理,来实现。
## nginx映射
> 新购买的服务器一般都会预装apache如果用户可以删除, 此处给出关于删除apache的命令。
sudo service apache2 stop
sudo service apache stop
删除apache2
update-rc.d -f apache2 remove
移出apache2
sudo apt-get remove apache2
安装nginx `sudo apt-get install nginx`
查看版本 `nginx -v`
进入 `etc/nginx/conf.d` 创建配置文件 `sudo vim yuming-com-8081.conf`
upstream yuming { server 127.0.0.1:8081; }
server { listen 80;
# 当通过这个ip地址来访问,服务器的server_name会匹配到这个地址,向这个地址发起请求的所有流量 都转发到上面的 upstream yuming 里面去 server_name 服务器IP地址;
location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forward $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Nginx-Proxy true;
//配置指令实现代理 把域名代理到集群(这个应用的名字上面)
proxy_pass http://yuming;
proxy_redirect off; //关闭
}
# 如果有css 图片 等 需要设置下 location ~* ^.+.(jpg|jpeg|gif|png|ico|css|js|pdf|txt){ root /www/boyi_api/pro/current/public; } }
进入 `etc/nginx/` 找到 `vim nginx.conf` 这个配置文件查看以下两个配置是否打开
加载conf.d下面的所有.conf文件
include /etc/nginx/conf.d/*.conf;
加载sites-enabled下面的所有文件
include /etc/nginx/sites-enabled/*
查看上面写的配置文件是否正确 `sudo nginx -t`
重启nginx `sudo nginx -s reload`
在浏览器中会显示我们的nginx服务器版本信息 如果不想显示 进入 `etc/nginx/nginx.conf` 将 `server_tokens off` 注释打开
## mongodb
#### mongodb安装
打开[mongodb](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/)官网,可以根据自己的系统环境安装,此处介绍ubuntu安装步骤
导入key `sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6`
为mongodb的配置文件创建一个列表 `echo "deb [ arch=amd64 ] http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list`
更新本地包 `sudo apt-get update`
安装mongodb `sudo apt-get install -y mongodb-org`
因为mongodb的源在国外,可能会很慢,可以按下ctrl+c中断操作来修改源,进入目录 `cd /etc/apt/sources.list.d` 编辑文件 `sudo vim mongodb-org-3.4.list`
将现有的源 http://repo.mongodb.org 改为 阿里云的 http://mirrors.aliyun.com/mongodb
修改完成之后更新下源 `sudo apt-get update`
在重新安装,这时会从阿里云镜像来安装,将会快很多 `sudo apt-get install -y mongodb-org`
开启服务 `sudo service mongod start`
重启服务 `sudo service mongod restart`
#### 防火墙中加入mongodb端口号
如果设置了防火墙 打开配置文件加入27017mongodb这个端口号 `sudo vim /etc/iptables.up.rules`
-A INPUT -s 127.0.0.1 -p tcp --destination-port 27017 -m state --state NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -d 127.0.0.1 -p tcp --source-port 27017 -m state --state ESTABLISHED -j ACCEPT
重新载入 `sudo iptables-restore < /etc/iptables.up.rules`
通过mongo连接实例 看是否成功 `mongo`
#### 更改MongoDB默认端口号
目前安装已经成功,但是全世界的人都知道mongodb的默认端口跑在27017端口,出于最基本的考虑,改掉这个端口号,编辑此文件 `sudo vim /etc/mongod.conf`
找到port 修改为29999
net: port: 29999
注意:修改mongodb默认端口号之后 还要更新下防火墙中设置的端口号
#### 开启MongoDB服务
重启mongodb ``` sudo service mongod restart ````通过mongo链接 mongo —port 29999
#### 演示如何向线上的数据库导入初识数据
//todo:
## 本地代码同步第三方仓库进行生产部署
#### 选择代码托管仓库
> 使用git仓库托管代码,可以选择github或者码云等等都可以,注册一个账号,创建一个项目,与本地的项目进行一个关联
进入本地电脑的.ssh 目录 找到id_rsa.pub文件,拷贝内容,进入码云个人中心里面找到ssh公钥,粘贴本地电脑拷贝的id_rsa内容。
进入本地的项目文件夹,如果是一个干净的项目,执行以下`Git`命令:
git init git add . git remote add origin # 远程仓库地址 git push
到此已经实现了本地项目与第三方仓库的关联。
#### 实现服务器与第三方仓库的关联
同样需要做的是,在服务上如果生成过.ssh 将 id_rsa.pub 公钥放到码云的后台
现在建立project文件夹 `mkdir project`
进入project 目录 ,拉取远程仓库代码到服务器
git clone 远程仓库地址
#### PM2部署代码到服务器
通过上面这些操作实现了本地代码推送到私有仓库,服务器也可下载私有仓库的内容,下面开始用pm2管理工具,来管理我们的代码同步更新,服务重启,可参考pm2的文档里面很详细的讲解了从部署到每个参数的设置 [pm2](http://pm2.keymetrics.io/)
下面简单介绍使用 pm2 部署代码到服务器之上
首先建立一个 ecosystem.json 文件
“apps” : [{ “name” : ”Website“, //站点名称 “script” : ”app.js“, //启动脚本,就是入口文件 “env”: { //启动时候需要传入的变量 “COMMON_VARIABLE”: ”true“ }, //生产环境的变量 “env_production” : { “NODE_ENV”: ”pro“ } }], //设置部署 “deploy” : { “production” : { // 服务器上我们用户发布部署的user “user” : ”root“, // 服务器,如果有多台主机可以数组形式来写 “host” : [”212.83.163.1“, “212.83.163.2”, ”212.83.163.3“], // 端口 “port” : 22, // 分支 “ref” : ”origin/master“, // 仓库地址 “repo” : ”git@github.com:repo.git“, // 项目部署到服务器哪个目录下面的地址 “path” : ”/var/www/website“, // key校验给取消掉 “ssh_options”: ”StrictHostKeyChecking=no“, // 设置环境 “env” : { “NODE_ENV”: ”pro“ } }
在发布前需要在服务器创建website文件,且给予可写的权限
mkdir /var/www/website
sudo chmod 777 website
如果是第一次发布,执行以下命令,让pm2连上我们的服务器,从服务器里面来创建我们发布项目所需要的文件夹
pm2 deploy ecosystem.json pro setup
之后每次修改后将不需要setup 使用命令 `pm2 deploy ecosystem.json pro` 就可以发布啦,到此一个简单的项目发布就已经完成了,有问题可以提issues.
#### pm2发布遇到的一些问题
* bash: pm2: command not found
$ pm2 deploy ecosystem.json pro
--> Deploying to pro environment
--> on host 116.62.222.30
○ deploying origin/master
○ executing pre-deploy-local
○ hook pre-deploy
○ fetching updates
Fetching origin
○ resetting HEAD to origin/master
HEAD is now at 4092462 modify ecosystem.json
○ executing post-deploy pm2 startOrRestart ecosystem.json --env pro
bash: pm2: command not found
post-deploy hook failed
Deploy failed
会发现在服务器上无法找到pm2命令,但是确实已经安装了呢,原因在于pm2在服务器上使用的是一个非交互式的ssh链接方式,回到服务器的用户根目录下编辑文件.bashrc `vim ~/.bashrc`
找到以下命令加以注释,不让其提前返回
[ -z “$PS1” ] && return
执行命令 重新加载 `source ~/.bashrc`
* bash: npm: command not found
和上面问题一样编辑.bashrc文件
注释掉下面四行
If not running interactively, don‘t do anything
case $- in
i) ;;
*) return;;
esac
```
执行命令 重新加载 source ~/.bashrc
补充:df -h 查看硬盘使用情况
