用 PM2 运行 Strapi
🌐 Running Strapi with PM2
Page summary:构建管理面板,在一个
ecosystem.config.js文件中描述你的应用,并将NODE_ENV设置为production,然后用pm2 start启动它。运行pm2 startup和pm2 save,这样应用在重启后会自动恢复。
从 npm run start 开始,Strapi 会在前台运行,当你关闭终端或者进程崩溃时就会停止。使用进程管理器可以让它持续运行:它会在应用失败时重启应用,重启后恢复运行,并收集日志。PM2 是 Node.js 应用中常见的选择。本指南介绍了如何安装 PM2,如何向它描述一个 Strapi 应用,以及之后的一些操作任务。
🌐 Started with npm run start, Strapi runs in the foreground and stops when you close the terminal or when the process crashes. A process manager keeps it running instead: it restarts the application on failure, brings it back after a reboot, and collects its logs. PM2 is a common choice for Node.js applications. This guide covers installing PM2, describing a Strapi application to it, and the operational tasks that follow.
安装 PM2
🌐 Install PM2
全局安装 PM2,这样 pm2 命令就可以在你的终端和启动脚本中使用了:
🌐 Install PM2 globally so the pm2 command is available to your shell and to the startup script:
- Yarn
- NPM
yarn global add pm2
npm install -g pm2
确认安装:
🌐 Confirm the installation:
pm2 --version
搭建管理面板
🌐 Build the admin panel
管理员面板是一个静态包,必须在生产环境中服务器启动前构建。使用 NODE_ENV 设置为 production 来构建,这样构建就会使用你的生产配置:
🌐 The admin panel is a static bundle that must be built before the server starts in production. Build it with NODE_ENV set to production, so the build uses your production configuration:
- Yarn
- NPM
NODE_ENV=production yarn build
NODE_ENV=production npm run build
把 NODE_ENV=production 设置在构建命令本身上,而不是整个 shell 会话。提前导出它再安装依赖会让包管理器跳过构建需要的 devDependencies。
🌐 Set NODE_ENV=production on the build command itself rather than for the whole shell session. Exporting it before installing dependencies makes the package manager skip devDependencies, which the build needs.
创建一个生态系统文件
🌐 Create an ecosystem file
PM2 可以从命令行启动应用,但配置文件可以将设置纳入版本控制,并使每次部署都可重复。在你的 Strapi 项目根目录下创建该文件:
🌐 PM2 can start an application from the command line, but a configuration file keeps the settings under version control and makes each deployment repeatable. Create the file at the root of your Strapi project:
module.exports = {
apps: [
{
name: 'strapi',
cwd: '/srv/strapi',
script: 'npm',
args: 'start',
env: {
NODE_ENV: 'production',
HOST: '0.0.0.0',
PORT: 1337,
},
},
],
};
这些选项有以下用途:
🌐 The options serve the following purposes:
| 选项 | 作用 |
|---|---|
name | 你传给其他 PM2 命令的名字,比如 pm2 restart strapi。 |
cwd | 项目的绝对路径。PM2 会相对于它解析 script,这样无论你从哪个目录运行 pm2,应用都能正确启动。 |
script 和 args | PM2 执行的命令。使用包管理器而不是文件路径可以保持行为与手动启动 Strapi 一样。 |
env | 进程的环境变量。NODE_ENV 必须是 production,这样 Strapi 才能加载生产配置。 |
如果生态系统文件会被提交到版本控制,不要把像 APP_KEYS、ADMIN_JWT_SECRET 或数据库凭证这样的秘密放进去。把它们保存在服务器的 .env 文件里,Strapi 会在启动时读取,或者从你的部署工具中注入(参见 环境配置)。
🌐 Do not put secrets such as APP_KEYS, ADMIN_JWT_SECRET, or database credentials in the ecosystem file if it is committed to version control. Keep them in the server's .env file, which Strapi reads on startup, or inject them from your deployment tooling (see environment configuration).
用 PM2 启动 Strapi
🌐 Start Strapi with PM2
从生态系统文件启动应用:
🌐 Start the application from the ecosystem file:
pm2 start ecosystem.config.js
检查一下它是否显示出来了:
🌐 Check that it came up:
pm2 list
Strapi 条目应该显示 online 状态。显示 errored 状态,或者重启次数持续增加,意味着进程正在失败并退出。查看日志以了解原因:
🌐 The Strapi entry should show a status of online. A status of errored, or a restart count that keeps climbing, means the process is failing and exiting. Read the logs to find out why:
pm2 logs strapi --lines 100
重启后保持 Strapi 运行
🌐 Keep Strapi running after a reboot
PM2 本身无法在重启后继续运行。它需要一个初始化脚本,以及一个保存了要启动的应用的快照。
🌐 PM2 does not survive a reboot on its own. It needs an init script, and a saved snapshot of which applications to start.
-
生成初始化脚本。该命令会打印第二个命令,为你的初始化系统和用户预先填好:
pm2 startup -
按照它打印出来的命令运行,完全照着打印的执行。就是那个需要
sudo的命令。 -
保存当前的进程列表,这样 PM2 就知道要恢复什么:
pm2 save
每当你添加、删除或重命名应用时,请再次运行 pm2 save。如果不这样做,PM2 会将列表恢复到上次保存时的状态。
🌐 Run pm2 save again whenever you add, remove, or rename an application. Without it, PM2 restores the list as it was at the last save.
管理日志
🌐 Manage logs
PM2 会把每个应用的输出写入 ~/.pm2/logs/ 文件中。这些文件会无限增长,所以安装日志轮转模块:
🌐 PM2 writes each application's output to files in ~/.pm2/logs/. These files grow without limit, so install the log rotation module:
pm2 install pm2-logrotate
设置大小限制以及要保留的轮换文件数量:
🌐 Set a size limit and how many rotated files to keep:
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7
更新正在运行的部署
🌐 Update a running deployment
每当你的代码或管理员配置发生变化时,都必须重新构建管理面板打包包,并且重建必须在进程重启之前完成。按照这个顺序部署:
🌐 The admin panel bundle must be rebuilt whenever your code or admin configuration changes, and the rebuild has to happen before the process restarts. Deploy in this order:
-
去服务器上获取新代码。
-
安装依赖。
-
用
NODE_ENV=production搭建管理面板。 -
重启应用:
pm2 restart strapi --update-env
--update-env 标志会让 PM2 重新读取环境,而不是重复使用进程第一次启动时的值。如果没有它,对你的 .env 文件或生态系统文件的更改将会被忽略。
🌐 The --update-env flag makes PM2 re-read the environment rather than reusing the values from when the process first started. Without it, changes to your .env file or ecosystem file are ignored.
PM2 仅在集群模式下执行零停机的 pm2 reload,此时它会在淘汰旧工作进程之前先启动替换的工作进程。在上面使用的单进程 fork 模式下,进程会停止然后重新启动,因此会有一个短暂的时间窗口内请求会失败。如果你想在这个时间窗口内控制访客看到的内容,可以在 Strapi 前面放一个反向代理,具体操作可以参考 Nginx、Caddy、HAProxy 和 Traefik 指南。
🌐 PM2 only performs a zero-downtime pm2 reload in cluster mode, where it starts replacement workers before retiring the old ones. In the single-process fork mode used above, the process stops and starts again, so there is a short window where requests fail. Put a reverse proxy in front of Strapi if you need to control what visitors see during that window, as covered in the Nginx, Caddy, HAProxy, and Traefik guides.
运行多个实例
🌐 Run more than one instance
PM2 可以通过其集群模式运行应用的多个副本,使用同一个端口。集群模式基于 Node.js 的 cluster 模块,需要一个 JavaScript 入口点。本指南前面使用的 script: 'npm' 值运行的是二进制文件,而 PM2 只能在 fork 模式下管理二进制文件。
🌐 PM2 can run several copies of an application with its cluster mode, sharing one port. Cluster mode builds on the Node.js cluster module, which needs a JavaScript entry point. The script: 'npm' value used earlier in this guide runs a binary, and PM2 can only manage a binary in fork mode.
在你项目的根目录添加一个入口点,直接启动 Strapi:
🌐 Add an entry point at the root of your project that starts Strapi directly:
const strapi = require('@strapi/strapi');
strapi.createStrapi(/* {...} */).start();
对于 TypeScript 项目,将 distDir 选项传给 createStrapi,这样服务器就会从编译后的输出启动(参见 使用 createStrapi 工厂)。
🌐 For a TypeScript project, pass the distDir option to createStrapi so the server starts from the compiled output (see using the createStrapi factory).
把生态系统文件指向那个文件并选择集群模式:
🌐 Point the ecosystem file at that file and select cluster mode:
module.exports = {
apps: [
{
name: 'strapi',
cwd: '/srv/strapi',
script: './server.js',
exec_mode: 'cluster',
instances: 'max',
env: {
NODE_ENV: 'production',
HOST: '0.0.0.0',
PORT: 1337,
},
},
],
};
Strapi 在这种模式下运行,但各实例之间没有协调,所以一些行为会发生变化。在启用之前先阅读这一部分。
🌐 Strapi runs in this mode, but it has no coordination between instances, so several behaviors change. Read this section before enabling it.
Strapi 会在启动时运行它的模式同步,每个进程执行一次,并且实例之间没有共享锁。如果重启时内容类型没有改变是安全的,因为同步会检测到模式没变并且不会做任何操作。
🌐 Strapi runs its schema synchronization on startup, once per process, with no lock shared between instances. A restart that leaves the content-types unchanged is safe, because the synchronization detects an unchanged schema and does nothing.
在两种情况下同步是不安全的:一种是会更改内容类型的发布,另一种是有待处理迁移的发布。实例一起启动后,会对同一个数据库发起并发的架构更改和迁移。
🌐 The synchronization is not safe in 2 cases: a release that changes content-types, and a release with pending migrations. Instances starting together then issue concurrent schema changes and migrations against the same database.
对于这些版本,先启动或运行一个实例,让它完成启动后再启动下一个。这是对同一个数据库运行多个进程的特性,所以把实例分散到不同主机上也无法避免。
🌐 For those releases, start or roll a single instance first and let it finish booting before the next one starts. This is a property of running several processes against one database, so spreading the instances across separate hosts does not avoid it.
运行多个实例还有另外三个值得了解的后果:
🌐 Running several instances has 3 other consequences worth knowing:
- CRON 任务 是在每个 Strapi 进程中调度的,所以一个任务是每个实例运行一次,而不是总共运行一次。设置为每晚运行的任务将根据你的实例数量运行多次。如果你的项目将
cron.enabled设置为true,要么把任务移出 Strapi,要么只在一个实例上保留它们。 - Strapi 里的任何内存数据都只属于一个实例,因为每个实例都是一个独立的进程。Strapi 核心中没有东西会在它们之间同步状态。
- 默认的本地上传提供商会将文件写入实例自己的磁盘。共享同一台机器和项目目录的实例会共享该磁盘,但不同机器或不同容器中的实例不会。在这种情况下,请使用由对象存储支持的媒体库提供商之一。
在这些限制下,先从一个放在反向代理后的实例开始。只有在你测量发现一个不够用时,再添加实例,并按照上面描述的顺序进行部署。
🌐 Given these constraints, start with a single instance behind a reverse proxy. Add instances once you have measured that one is not enough, and sequence those deployments as described above.
确认应用正在运行
🌐 Verify the application is running
确认应用正在运行并且可以访问:
🌐 Confirm the application is running and reachable:
-
运行
pm2 list并检查 Strapi 条目是否显示online,重启次数没有增加。 -
请求健康检查路径,当服务器准备就绪时会返回 HTTP
204 No Content:curl -I http://localhost:1337/_health -
重启服务器。
-
再次运行
pm2 list。应用应该是online,即使你没有启动它。
故障排除
以下每个症状都指向一个特定的原因。症状以粗体显示,后面是引起它的原因以及需要改变的内容:
🌐 Each of the following symptoms points at a specific cause. The symptom is in bold, followed by what causes it and what to change:
- 该过程在
pm2 list中显示errored。 阅读pm2 logs strapi --lines 100。 缺少的构建、无法访问的数据库或缺失的环境变量通常是原因。 - PM2 循环重启 Strapi。 应用启动后立即退出。日志里写了原因。在修复之前,用
pm2 stop strapi停止循环,而不是让它不断重试。 - Strapi 在重启后没有恢复。
pm2 startup打印的命令要么从未运行过,要么在添加应用后没有运行pm2 save。请重复这两个步骤。 - 对环境变量的更改没有效果。 PM2 会重用进程最初启动时的环境。使用
pm2 restart strapi --update-env重启。 - 部署后管理员面板显示的是旧版本。 管理员包没有重新构建。使用
NODE_ENV=production运行构建,然后重启。
下一步
🌐 Next steps