Skip to content

Nest 使用 PM2 部署

本章内容

  • 使用 PM2 部署 Nest.js 应用程序

  • HTTPS 证书配置

  • nginx 配置

  • nginx 检查

PM2 部署与配置

bash

pm2 start ecosystem.config.js --env=production
pm2 list # 查看pm2列表
pm2 delete|stop|restart|start [ID编号||all] #操作
pm2 logs # 检查是否正常启动
pm2 monit #监控  未下载:pm2 install monit
pm2 reload ecosystem.config.js --env production # 不停机重启

ecosystem.config.js

  • 项目根目录新建 ecosystem.config.js
ts
module.exports = {
  apps: [
    {
      name: "你自己的名字", //名称
      script: "./dist/main.js",
      instances: 2, //核心数4,如果是fork就设置成1即可
      //启动应用程序的模式,可以是“cluster”或“fork”,默认fork
      exec_mode: "cluster", //集群模式
      watch: false, //路劲不存在会cpu100% 无限重启
      ignore_watch: [
        // 可以设置不用监听的文件,watch设置为true才有效
        "node_modules",
        "public",
        "logs",
      ],
      //分钟 (0-59)、小时 (0-23)、一个月中的第几天 (1-31)、月份 (1-12) 、星期几 (0-6) (星期天 为0)
      //设置定时重启,具体可以看文档,一般用来解决重启能解决的问题
      //例如:老程序内存泄露,一定时间会爆内存,但程序员跑路了,为了保持稳定运行只能重启
      // "cron_restart": '0 0 * * *',
      // 启用/禁用应用程序崩溃或退出时自动重启,默认为true, 发生异常的情况下自动重启
      autorestart: true,
      //设置日志路径,可以方便我们查看一些错误原因或者其他信息,服务器上需要有对应文件或者读写权限
      // "error_file" : "./log/err.log",
      // "out_file" : "./log/out.log",
      log_date_format: "YYYY-MM-DD HH:mm Z", //日期格式
      //集群状态下合并日志
      merge_logs: true,
      //环境变量,我们前面的 .env 服务端会被忽略,可以注入这里面的环境变量,可以避免正式服务器信息泄露
      //pm2 start ecosystem.config.js --env develop

      env: {
        NODE_ENV: "development",
        HOST: "192.168.1.1", //出现在程序的host环境变量
        PORT: "8080",
      },
      //pm2 start ecosystem.config.js --env test
      env_test: {
        NODE_ENV: "test",
      },
      //pm2 start ecosystem.config.js --env production,可以选择环境变量
      env_production: {
        NODE_ENV: "production",
        HOST: "0.0.0.0", //出现在程序的host环境变量
        PORT: "8080",
      },
      instance_var: "INSTANCE_ID", // 实例标识,可以在main.ts
      max_memory_restart: "800M", // 单实例内存上限(防泄漏)
    },
  ],

  //不会用
  deploy: {
    production: {
      user: "root",
      host: "127.0.0.1",
      ref: "origin/master",
      repo: "GIT_REPOSITORY",
      path: "DESTINATION_PATH",
      "pre-deploy-local": "",
      "post-deploy":
        "npm install && pm2 reload ecosystem.config.js --env production",
      "pre-setup": "",
    },
  },
};

NestJS 中计算端口

ts
// 动态计算端口:3000 + PM2 实例ID
const basePort = parseInt(process.env.PORT || "8080");
const instanceId = process.env.INSTANCE_ID
  ? parseInt(process.env.INSTANCE_ID)
  : 0;
const port = basePort + instanceId;
await app.listen(port, "0.0.0.0");

NestJs 设置 https(一般不用)

ts
const httpsOptions = {
  key: fs.readFileSync("./src/config/daysmatters.top.key"),
  cert: fs.readFileSync("./src/config/daysmatters.top_bundle.pem"),
};
const app = await NestFactory.create<NestFastifyApplication>(
  AppModule,
  // new FastifyAdapter({ logger: true })
  new FastifyAdapter({
    https: httpsOptions, // https 配置
  }),
  // new ExpressAdapter(),
  {
    // httpsOptions, //express https 配置
    cors: true, // 开启跨域访问
    snapshot: true, // 启用内存优化
    autoFlushLogs: true, // 自动刷新日志
    // keepAliveTimeout: 60_000   // 长连接保活
  }
);

nginx 配置

bash

# 定义后端服务负载均衡
upstream nest_backend {
  # 配置策略加权轮询(weight=3的实例获得60%流量)
  server 127.0.0.1:8080;
  server 127.0.0.1:8081;
  keepalive 32;  # 保持连接复用
}
server {
  # 监听80端口(HTTP)
  listen 80;
  # 绑定域名(无域名用_)
  server_name baidu.com;
  # 强制HTTP跳转HTTPS(推荐)
  return 301 https://$host$request_uri;
}

server {
  # 监听443端口 (HTTPS)
  listen 443 ssl;
  server_name baidu.com;
  # SSL证书配置
  ssl_certificate /www/nest-server/src/config/daysmatters.top_bundle.pem;
  ssl_certificate_key /www/nest-server/src/config/daysmatters.top.key;

  # SSL优化参数
  #ssl_protocols TLSv1.2 TLSv1.3;
  #ssl_prefer_server_ciphers on;
  #ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';


  location ^~ /admin/static/ {
    alias /www/admin/dist/static/;
    # 确保 Nginx 有目录访问权限
    disable_symlinks off;
    # 长期缓存
    expires 1y;
    access_log off;
    add_header Cache-Control "public, immutable";

    #disable_symlinks off;  # 允许符号链接
    # 确保处理所有文件类型
    types {
      application/javascript js;
      text/css css;
      image/png png;
      image/jpeg jpg;
      image/svg+xml svg;
      application/font-woff woff;
      application/font-woff2 woff2;
    }
  }

  location /admin/ {
    alias /www/admin/dist/;
    index index.html;

    # 处理 Vue 路由
    try_files $uri $uri/ /admin/index.html;

    # 添加 MIME 类型定义
    types {
      text/html html;
      application/javascript js;
      text/css css;
      image/png png;
      image/jpeg jpg jpeg;
      image/gif gif;
      image/svg+xml svg;
      application/font-woff woff;
      application/font-woff2 woff2;
      application/vnd.ms-fontobject eot;
      font/ttf ttf;
    }
    # 缓存设置
    expires 1h;
    access_log off;

    #禁止自动索引
    #autoindex off;
  }


  # 静态资源直返(绕过Node节省资源)
  location ~* \.(js|css|png|jpg|webp)$ {
    # 静态文件存放路径
    root /var/www/static;
    # 客户端缓存30天
    expires 30d;
    # 关闭日志减少磁盘IO
    access_log off;
  }

  # API请求转发规则
  location / {
    # 指向后端服务器组
    proxy_pass https://nest_backend;

    # 必须的HTTPS代理参数
    proxy_ssl_verify off;              # 关闭证书验证(测试用)
    proxy_ssl_trusted_certificate /www/daysmatter/daysmatters_nestjs/nest-admin/server/src/config/daysmatters.top_bundle.crt;  # 生产环境应验证证书
    # HTTP协议升级(WebSocket必须)
    proxy_http_version 1.1;
    #proxy_set_header Upgrade $http_upgrade;
    #proxy_set_header Connection 'upgrade';
    # 透传客户端信息
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # 超时控制(按需调整)
    proxy_connect_timeout 75s;  # 连接后端超时
    proxy_send_timeout 600s;    # 发送请求超时
    proxy_read_timeout 600s;    # 读取响应超时

        # 缓冲优化(防内存溢出)
        proxy_buffering on;
        proxy_buffer_size 4k;       # 单缓冲区大小
        proxy_buffers 8 16k;        # 缓冲区数量*大小
        proxy_busy_buffers_size 32k;
    }


    # 2. 限流保护(防CC攻击)
    #limit_req_zone $binary_remote_addr zone=api_rate:10m rate=100r/s;
    location /api/ {
        #limit_req zone=api_rate burst=50 nodelay;
        proxy_pass https://nest_backend/api/;
    }


    error_page 503 @maintenance;
    location @maintenance {
        root /www;
        rewrite ^(.*)$ /maintenance.html break;
    }
}

nginx 检查

bash

#1.需要保证前端文件权限
sudo chmod -R 755 /var/www/xxx
# 修正所有权和权限
sudo -u www-data ls /path/to/file
#验证构建输出路径
ls -l /full/path
#2.需保证安全组开放端口,并且服务器开放防火墙
sudo ufw allow 端口号
# 重启防火墙使规则生效
sudo ufw reload
 # 查看端口是否已开放
sudo ufw status
#sudo ufw allow from 客户端IP to any port xxxxx  # 仅允许特定 IP 访问

#3.nginx需要保证文件无误并重启
#验证配置
sudo nginx -t
sudo nginx -t -c /var/file/xxx.conf #需要在主文件中引入
#检查错误日志
sudo tail -f /var/log/nginx/error.log
#重启生效
sudo systemctl restart nginx