01 上线架构与请求流程

1. 开发环境与生产环境

当前工程以开发学习为主,常见启动方式是:

ts-node server.ts

开发时可以让工具实时编译 TypeScript,方便修改和调试。生产环境更推荐:

TypeScript 源码
  → tsc 编译
  → JavaScript 文件
  → PM2 启动 Node.js

例如:

npm run build
pm2 start dist/server.js --name nloop-api

这让“构建是否成功”和“服务是否启动”成为两个明确步骤。

2. 为什么不能只使用 node dist/server.js

下面当然可以启动服务:

node dist/server.js

但直接启动有几个运维问题:

PM2 就是为管理这些长期运行的进程而存在。

3. PM2、Nginx 和 systemd 各自负责什么

PM2

启动 Node.js 应用
记录进程状态
收集 stdout/stderr
应用崩溃后重启
执行 stop/restart/reload
保存待恢复的进程列表

PM2 不是 HTTP 反向代理,也不是 TypeScript 编译器。

Nginx

监听公网 80/443
返回前端静态文件
把 /api/ 转发到 Express
终止 HTTPS
记录访问日志和代理错误

systemd

Linux 启动
  → systemd 启动 PM2 daemon
  → PM2 恢复保存过的 Node.js 应用

在常见 Linux 发行版中,Nginx 本身也由 systemd 管理。

4. 一次请求发生了什么

访问前端:

GET https://example.com/
  → Nginx
  → /var/www/frontend/index.html

访问 API:

GET https://example.com/api/users
  → Nginx :443
  → http://127.0.0.1:8080/api/users
  → Express Router
  → JSON 响应
  → Nginx 返回给浏览器

浏览器不需要知道 Express 实际监听 8080。

5. 为什么 Express 建议只监听本机地址

const host = "127.0.0.1";
const port = 8080;

app.listen(port, host, () => {
  console.log(`Server is listening on ${host}:${port}`);
});

如果 Nginx 与 Express 位于同一台服务器,Express 通常只需要接受本机代理请求。公网只开放 80/443,可以减少不必要的入口。

如果写成:

app.listen(8080, "0.0.0.0");

则 Express 会监听所有网络接口。是否能从公网访问还取决于防火墙和云安全组,但新人阶段没有必要额外暴露这个端口。

6. 数据库由谁管理

PM2 管理的是 Node.js 应用进程。MySQL、Redis 通常分别由它们自己的 systemd 服务、云数据库或容器平台管理:

PM2
  └─ Express / Worker

systemd 或云服务
  ├─ MySQL
  ├─ Redis
  └─ Nginx

不要使用 PM2 启动 MySQL。

7. 第一版目录结构

先使用容易理解的目录:

/var/www/nloop/current/
├── dist/
├── node_modules/
├── package.json
├── package-lock.json
├── ecosystem.config.js
└── .env

日志先使用 PM2 默认目录:

/home/deploy/.pm2/logs/

Nginx 日志通常位于:

/var/log/nginx/

等首次上线稳定后,再引入 releases/current 软链接。

8. 最小上线成功标准

不要在第一天追求“全套高可用”。先保证每一层都能单独验证。

复盘题

  1. PM2、Nginx 和 systemd 分别管理什么?
  2. 为什么 PM2 显示 online 不代表公网一定可以访问?
  3. 为什么同机部署时 Express 可以只监听 127.0.0.1
  4. 浏览器访问 /api/users 时,经过了哪些组件?
  5. MySQL 为什么通常不由 PM2 管理?

官方参考