next项目部署到服务器pm2进程守护

博客地址:http://blog.poetries.top/2018/11/18/react-ssr-next-deploy/

关注公众号获取更多资讯

一、 npm run export导出文件上传到CDN

在项目中执行npm run export后导出outCDN文件上传到CDN

// scripts/upload.js

const fs = require('fs');
const path = require('path');
const OSS = require('ali-oss');

const filePath = path.join(__dirname,'../outCDN');
const excludeFiles = ['index.html']

const client = new OSS({
  region: 'oss-cn-shenzhen',
  accessKeyId: '',
  accessKeySecret: '',
  bucket: ''
});

// 遍历文件夹中所有文件
async function uploadFile(filePath){
    //根据文件路径读取文件,返回文件列表
    fs.readdir(filePath,async function(err,files){
        if(err){
            console.warn(err)
        }else{
            //遍历读取到的文件列表
            files.forEach(async function(filename){
                //获取当前文件的绝对路径
                const filedir = path.join(filePath,filename);
                //根据文件路径获取文件信息,返回一个fs.Stats对象
                fs.stat(filedir,async function(eror,stats){
                    if(eror){
                        console.warn('获取文件stats失败');
                    }else{
                        const isFile = stats.isFile();//是文件
                        const isDir = stats.isDirectory();//是文件夹
                        if(!excludeFiles.includes(filename) && isFile){
                            const fileKey = `${filedir.split('outCDN/').pop()}`

                            try {
                                // object表示上传到OSS的Object名称,localfile表示本地文件或者文件路径
                                let data = await client.put(fileKey,filedir);

                                console.error('upload success: %j', data);
                            } catch(err) {
                                console.error('upload failed: %j', err);
                            }
                        }
                        if(isDir){
                            uploadFile(filedir);//递归,如果是文件夹,就继续遍历该文件夹下面的文件
                        }
                    }
                })
            });
        }
    });
}


uploadFile(filePath)

二、处理next build后的文件

执行next build以后,把.nextpackage.jsonserver.jsnext.config.jsecosystem.json 拷贝到一个文件夹统一管理,最后部署这个文件夹下的内容即可

// scripts/copyFiles.js

const fs = require( 'fs' ),
    stat = fs.stat;

const path = require('path')

const includeFiles = ['package.json','server.js','next.config.js','ecosystem.json']

/*
 * 复制目录中的所有文件包括子目录
 * @param{ String } 需要复制的目录
 * @param{ String } 复制到指定的目录
 */
const readDir = function( src, dst ){
    // 读取目录中的所有文件/目录
    fs.readdir( src, function( err, paths ){
        if( err ){
            throw err;
        }
        paths.forEach(function( filename ){
            var _src = src + '/' + filename,
                _dst = dst + '/' + filename,
                readable, writable;

            stat( _src, function( err, st ){
                if( err ){
                    throw err;
                }
                // 判断是否为文件
                if( st.isFile()){
                    // 创建读取流
                    readable = fs.createReadStream( _src );
                    // 创建写入流
                    writable = fs.createWriteStream( _dst );
                    // 通过管道来传输流
                    readable.pipe( writable );
                }
                // 如果是目录则递归调用自身
                else if( st.isDirectory()){
                    copyDir( _src, _dst, readDir );
                }
            });
        });
    });
};

// 在复制目录前需要判断该目录是否存在,不存在需要先创建目录
const copyDir = function( src, dst, callback ){
    fs.exists( dst, function( exists ){
        // 已存在
        if( exists ){
            callback( src, dst );
        }
        // 不存在
        else{
            fs.mkdir( dst, function(){
                callback( src, dst );
            });
        }
    });
};

const copyFile = ()=>{
  includeFiles.forEach(filename=>{
    fs.createReadStream(path.join(__dirname,'../'+filename)).pipe(fs.createWriteStream(path.join(__dirname,'../deployBuildFiles',filename)))
    console.log('拷贝完成!')
  })
}

// 复制目录
copyDir( '.next', 'deployBuildFiles/.next', readDir);

// 拷贝文件
copyFile()

三、pm2之ecosystem部署项目

PM2部署应用流程,通过pm2的配置文件来部署
http://pm2.keymetrics.io/docs/usage/deployment/

3.1 配置部署脚本文件

在项目根目录添加pm2的部署脚本文件 ecosystem.json

部署文档详情:http://pm2.keymetrics.io/docs/usage/deployment/

{
  "apps": [
      {
        "name": "goodsapp", //pm2运行的应用名称
        "script": "server.js",//服务启动入口
        "env":{
            "COMON_VARIABLE": "true"
        },
        "env_production": {
            "NODE_ENV": "production", //env
            "HOST": "localhost"
        }
      }
  ],
  "deploy": {
      // 最后这样使用 pm2 deploy ecosystem.json production
      "production": {
          "user": "user_00",// 服务器用户名
          "host": ['192.68.1.201'],//服务器ip地址 可写多个
          "ref": "origin/master",//从指定分支拉取代码
          "repo": "http://p.yesdat.com/diffusion/49/goodsh.git",
          "path": "/data/poetry/testDir/prev-goods.yesdat.com", //上传本地目录到服务器
          "ssh_options": "StrictHostKeyChecking=no",
          "post-deploy": "npm install --registry=https://registry.npm.taobao.org && npm install && pm2 startOrRestart ecosystem.json --env production",//部署脚本
          "env": {
              "NODE_ENV": "production"
          }
      }
  }
}

或者简单scp上传到服务器

scp -P36000  -r deployBuildFiles/.next user_00@192.168.1.201:/home/data/services/goods-prev.yesdat.com/

更多详情 http://blog.poetries.top/2018/12/03/linux-scp

3.2 部署Nginx配置规则

nginx安装目录下的vhost中新建一个xx-3000.conf的配置文件

  • 在Nginx目录/etc/nginx下执行 sudo /usr/sbin/nginx -t 检测配置文件是否成功
image.png
upstream goodsapp { // website项目的目录名称
  server 127.0.0.1:3000; // 服务器上的本地启动入口,端口对应项目中server.js中的端口
}

// 配置server
server {
    listen 80;
    server_name prev-goods.yesdat.com; //指向的域名

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Nginx-Proxy true;

        proxy_pass http://goodsapp; // 请求将会转发到goodsapp的node服务下
        proxy_redirect off;
    }

    // 处理静态资源
    location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|js|pdf|txt) {
        root /data/goodsapp/static; //请求转发到静态资源路径
    }
}

更多配置参考 https://github.com/poetries/poetry-configure/blob/master/nginx.conf

3.3 本地项目根执行的命令

  • pm2 deploy ecosystem.json goodsapp setup 初始化
  • pm2 deploy ecosystem.json goodsapp 部署

3.4 部署到阿里云

第一步:配置Nginx

查看Nginx安装路径 which nginx 注意/etc/nginx/usr/local/nginx/下的nginx区别

# 切换到Nginx当前目录下
/usr/local/nginx/conf/

# 创建vhost
mkdir vhost

# 创建goodsapp-3001.conf,内容如下

server {
    listen 8080; 
    server_name 39.108.74.36;# 在ifconfig的拿到的ip地址或者是公网ip,这里填公网ip,如果是域名阿里云需要备案才可以正常访问

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Nginx-Proxy true;

        proxy_pass http://127.0.0.1:3001;# 把172.16.0.223:8080的请求转发代理到本机的3001端口
    }
}

# 在/usr/local/nginx/sbin/nginx/conf/nginx.conf下include创建的vhost文件
include /etc/nginx/vhost/*.conf; # 在文件最后include配置文件

# 在/usr/local/nginx/sbin/nginx/conf/nginx.conf下执行检测配置文件
sudo /usr/local/nginx/sbin/nginx -t

# 重新加载Nginx配置
/usr/local/nginx/sbin/nginx -s reload

一些注意事项

  • server_name可以是域名,也可以是ipip可以是本地,也可以是公网ip

本机ip

image.png

公网ip

image.png
  • 阿里云防火墙规则设置

这里访问了 8080需要在阿里云后台配置一下

image.png

第二步:pm2部署到服务器

首先在服务端全局安装pm2npm node并且建立软链

npm i pm2 -g

重要:请注意:

一定要做建立软链这步,否则出现如下问题

image.png
image.png

建立npm 软链

image.png

建立node 软链

image.png

建立pm2 软链

image.png

正式部署

  • 根目录执行pm2 deploy deploy-app.json production setup 初始化服务端环境
  • 根目录执行pm2 deploy deploy-app.json production --force 输入服务端用户root密码,部署即可

来到/home/production目录查看上传的文件

{
    "apps": [
        {
          "name": "goodsapp-prev",
          "script": "server.js",# 根目录server.js文件
          "env":{
              "COMON_VARIABLE": "true"
          },
          "env_production": {
              "NODE_ENV": "production"
          }
        }
    ],
    "deploy": {
        "production": {
            "user": "root",//用户名
            "host": ["39.108.74.36"], //公网ip
            "ref": "origin/master",
            "repo": "https://gitee.com/Poetries1/goods-prev.yesdat.com.git",
            "path": "/home/production",
            "ssh_options": ["StrictHostKeyChecking=no", "PasswordAuthentication=no"],
            "post-deploy": "npm install && pm2 startOrRestart deploy-app.json --env production",
            "pre-deploy-local": "echo 'Deploy Done!'",
            "env": {
                "NODE_ENV": "production"
            }
        }
    }
  }

更多配置信息 http://pm2.keymetrics.io/docs/usage/deployment/

  • pm2 list查看启动的项目
image.png
  • pm2 logs查看启动日志
image.png

然后在浏览器访问http://39.108.74.36:8080(http://公网ip:端口)即可看到,到此部署结束

3.5 部署更多参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容