云计算百科
云计算领域专业知识百科平台

Redwood 自托管(Serverful)部署实战:使用 PM2 与 Nginx 在 Linux 服务器上运行完整应用

  • 后端
  • 前端
  • Web框架
  • 开发工具

【免费下载链接】redwood

RedwoodGraphQL

项目地址:
https://gitcode.com/gh_mirrors/re/redwood

点击查看 免费下载

本指南基于 Redwood 官方 4.x 版本文档中的《Self-hosting Redwood (Serverful)》手册,讲解如何以传统"服务器托管"(Serverful)方式,在自有 Linux 服务器上通过 PM2 进程守护与 Nginx 反向代理,将一个完整的 Redwood 应用(Web 端 + API 端 + Postgres 数据库)部署上线。读完本文,你将掌握从应用配置、服务器环境准备、Nginx 站点配置、PM2 进程管理到一键发布与数据库迁移的完整 Serverful 部署链路,并理解 yarn rw serve 与 apiUrl 在其中的底层作用。

说明:本文主体对应仓库中的 self-hosting-redwood.md(4.x 版本),并辅以 Baremetal 部署文档、CLI 命令参考 及 serve 命令源码 进行纵深佐证。

一、为什么需要 Serverful 自托管

Redwood 默认面向 Serverless 架构(如 Netlify、Vercel 上的函数式部署),但并不是所有团队都喜欢 Serverless 的约束。如果你希望拥有传统、可预期、完全可控的部署形态——把代码部署到自己的 VPS 或物理服务器上,让 Node 进程常驻运行,由 Nginx 对外提供 Web 服务——Redwood 同样支持。

本手册给出的方案核心是:

  • PM2 作为进程守护与发布工具,负责拉取代码、执行构建与数据库迁移、重启服务并保证进程崩溃后自动恢复;
  • Nginx 作为生产级 Web 服务器,负责托管前端静态文件(web/dist),并将 /api/ 路径的请求反向代理给后端 API 进程;
  • Postgres 作为生产数据库,通过 .env 中的 DATABASE_URL 注入应用。

注意:该文档在后续版本中已被 Baremetal 部署文档(即 docs/docs/deploy/baremetal.md)取代。Baremetal 方案将本手册的流程封装为 yarn rw deploy baremetal 一条命令,但其底层仍是 SSH + PM2 + Nginx 这一套机制。理解本文的手动配置,能帮助你更好地理解 Baremetal 自动化做了什么。

二、前置要求

在开始之前,你应当对以下工具具备基本的使用经验:

  • PM2:Node.js 进程管理器,用于守护、重启、日志与发布;
  • Nginx:高性能 Web 服务器与反向代理;
  • Linux:服务器操作系统基本操作(用户、权限、SSH);
  • Postgres:生产数据库的创建与连接。

三、应用侧配置

在动手配置服务器之前,需要先对你的 Redwood 项目做三处调整。

1. 添加 PM2 依赖

在项目根目录把 PM2 安装为开发依赖:

yarn add -D pm2

2. 创建 PM2 生态配置文件

使用 PM2 自带的初始化命令生成生态配置文件,并建议将其重命名为更清晰的 pm2.config.js:

yarn pm2 init
mv ecosystem.config.js pm2.config.js

pm2.config.js 是后续所有发布与进程管理动作的枢纽:它既定义了本地"运行哪些进程、怎么运行",也定义了远程"从哪个仓库拉代码、部署到哪里、发布后执行什么命令"。

3. 修改 API 端点地址

Redwood 应用默认把 API 挂载在 /.redwood/functions(Serverless 函数路径)。在 Serverful 场景下,我们希望通过 Nginx 将 /api 前缀反向代理到本地 API 端口,因此需要修改项目根目录的 redwood.toml:

– apiUrl = "/.redwood/functions"
+ apiUrl = "/api"

从配置语义上看,apiUrl 决定了 Web 端向 API 发起请求的地址。根据 app-configuration-redwood-toml.md 的说明,apiUrl 既可以是相对 URL(此时它相当于一个代理路径),也可以是完整 URL;其默认值为 '/.redwood/functions',GraphQL 端点会推导为 ${apiUrl}/graphql。改为 /api 后,浏览器请求会发往 /api/graphql,再由 Nginx 转发给后端进程。

4. 可选:添加发布脚本

为了方便,可在顶层 package.json 中添加两个发布相关的脚本:

"scripts": {
"deploy:setup": "pm2 deploy pm2.config.js production setup",
"deploy": "pm2 deploy pm2.config.js production deploy"
}

其中 deploy:setup 用于在服务器上首次初始化目录结构,deploy 用于正式发布。即使你不把它们写进 package.json,也应记住这两条命令——后续部署流程会用到它们。

四、服务器侧准备

你的 Linux 服务器应当有一个专门用于部署的系统用户,并通过 SSH 密钥授权访问生产环境。本手册中该用户名为 deploy。

基本要求:

  • 服务器可被你的开发机通过 SSH 免密登录(建议将本地公钥加入服务器 ~/.ssh/authorized_keys);
  • deploy 用户对应用部署目录拥有读写权限;
  • 服务器上已安装 Node.js、yarn、PM2(全局或项目级均可)与 Postgres。

五、Nginx 配置详解

典型做法是把站点配置放在 /etc/nginx/sites-available/redwood-pm2,然后通过符号链接启用它:

sudo ln -s /etc/nginx/sites-available/redwood-pm2 /etc/nginx/sites-enabled/redwood-pm2

配置文件内容如下:

server {
server_name redwood-pm2.example.com;
listen 80;

location / {
root /home/deploy/redwood-pm2/current/web/dist;
try_files $uri /index.html;
}

location /api/ {
proxy_pass http://localhost:8911/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

各部分的职责:

配置段作用
location / 以 web/dist 为站点根目录,用 try_files $uri /index.html 实现 SPA 前端路由回退:所有未命中真实文件的请求都交给 index.html,由前端路由接管
location /api/ 将 /api/ 前缀的请求反向代理到本机 8911 端口上的 Redwood API 进程
proxy_set_header Upgrade / Connection 'upgrade' 支持 WebSocket 升级,对 GraphQL 订阅等实时特性是必需的
proxy_set_header Host $host 保持原始 Host 头,保证后端生成 URL 与日志中的域名正确
proxy_cache_bypass $http_upgrade 避免对升级为 WebSocket 的连接做缓存

关键细节:proxy_pass 结尾的斜杠至关重要。 当写为 proxy_pass http://localhost:8911/;(带尾斜杠)时,Nginx 会用匹配到的 location /api/ 之后的部分拼接目标地址,即 /api/graphql 会被映射为后端的 /graphql,从而正确匹配 Redwood API 的函数路由;如果去掉尾斜杠,/api/graphql 会被原样转发为 http://localhost:8911/api/graphql,导致 404。这是本配置中最容易踩坑的地方。

六、PM2 配置详解

现在填充前面生成的 pm2.config.js。文件顶部集中定义了最关键的变量,其中端口只在服务器本地使用,并且必须与 Nginx 配置中的代理端口保持一致:

const name = 'redwood-pm2' // Name to use in PM2
const repo = 'git@github.com:njjkgeerts/redwood-pm2.git' // Link to your repo
const user = 'deploy' // Server user
const path = `/home/${user}/${name}` // Path on the server to deploy to
const host = 'example.com' // Server hostname
const port = 8911 // Port to use locally on the server
const build = `yarn install && yarn rw build && yarn rw prisma migrate deploy`

module.exports = {
apps: [
{
name,
node_args: '-r dotenv/config',
cwd: `${path}/current/`,
script: 'yarn rw serve api',
args: `–port ${port}`,
env: {
NODE_ENV: 'development',
},
env_production: {
NODE_ENV: 'production',
},
},
],

deploy: {
production: {
user,
host,
ref: 'origin/master',
repo,
path,
ssh_options: 'ForwardAgent=yes',
'post-deploy': `${build} && pm2 reload pm2.config.js –env production && pm2 save`,
},
},
}

逐个拆解关键配置项:

配置项含义
apps[0].script 要运行的命令,这里为 yarn rw serve api,即只启动 Redwood 的 API 端(Web 端由 Nginx 托管静态文件)
apps[0].args 传给命令的参数,–port ${port} 将 API 端口固定为 8911。根据 CLI 命令参考 中 serve 一节,–port 的默认值正是 8911,此处显式声明以保证与 Nginx 严格一致
apps[0].node_args: '-r dotenv/config' 在进程启动前预加载 dotenv/config,使服务器上 current 目录中的 .env 文件能被自动读取(这是 DATABASE_URL 等环境变量生效的关键)
apps[0].cwd 进程工作目录为 ${path}/current/,即 PM2 部署机制维护的"当前版本"符号链接
env / env_production 不同环境下的 NODE_ENV。发布时通过 –env production 选择生产环境变量
deploy.production.ref 要发布的 Git 分支引用,本例为 origin/master
deploy.production.ssh_options: 'ForwardAgent=yes' 开启 SSH Agent 转发,服务器可借用本地开发机的 SSH 凭证去拉取仓库(对私有仓库尤其必要)
deploy.production['post-deploy'] 代码更新后在服务器上依次执行:安装依赖 → 构建 → 应用数据库迁移 → 以生产环境重载 PM2 进程 → 保存进程列表

关于构建命令中的数据库迁移:yarn rw build 会同时构建 Web 与 API 两侧(产物分别位于 web/dist 与 api/dist);yarn rw prisma migrate deploy 用于在生产数据库上应用已提交的迁移文件(注意它是非交互式命令,适合自动化场景)。

首次部署需要初始化数据库种子数据时,可以改用 yarn redwood prisma migrate dev 完成,它会为你在生产数据库上应用迁移(同时也可执行种子逻辑)。

⚠️ 已知坑(Caveat): Redwood 的 API 进程在 PM2 下似乎只能以 fork 模式运行,而不能使用 cluster 模式。这意味着本配置中不要给该进程设置 instances/exec_mode: 'cluster',否则服务可能无法正常工作。这一限制与 Baremetal 文档中默认生成的 ecosystem.config.js(使用 instances: 'max' + exec_mode: 'cluster')不同——Baremetal 方案会配合 wait_ready 与 listen_timeout 使用集群模式,而本手册的手动方案保持默认的单进程 fork 模式即可。

七、部署流程

1. 初始化服务器目录

在开发机上执行:

yarn install
yarn deploy:setup

yarn deploy:setup 实际执行的是 pm2 deploy pm2.config.js production setup,它会在服务器上按 path 变量创建部署目录骨架(通常包括 current 符号链接与存放各次发布版本的目录)。此时服务器目录结构已就绪,但还没有环境变量。

2. 配置环境变量

SSH 登录服务器,在部署目录的 current 子目录中创建 .env 文件:

vim /home/deploy/redwood-pm2/current/.env

至少需要一个 DATABASE_URL,例如:

DATABASE_URL=postgres://postgres:postgres@localhost:5432/redwood-pm2

由于 PM2 配置中启用了 node_args: '-r dotenv/config',这个 .env 会在进程启动时被自动加载。请确保该连接串指向的 Postgres 数据库已创建,且账号有权限执行迁移(需要 DDL 权限)。

3. 一键发布

回到开发机,执行:

yarn deploy

即 pm2 deploy pm2.config.js production deploy。这一条命令会依次完成:

  • 通过 SSH 连接服务器;
  • 按 ref(origin/master)拉取最新代码到新的版本目录;
  • 执行 post-deploy 钩子:yarn install 安装依赖 → yarn rw build 构建 → yarn rw prisma migrate deploy 应用数据库迁移 → pm2 reload pm2.config.js –env production 以生产环境重载 API 进程 → pm2 save 保存进程列表(保证服务器重启后 PM2 能恢复这些进程)。
  • 发布完成后,Nginx 负责对外提供 web/dist 下的静态页面,并把所有 /api/ 请求反向代理到 8911 端口的 Redwood API 进程,整个应用便处于 Serverful 运行状态。

    八、原理纵深:yarn rw serve api 在做什么

    理解这条被 PM2 守护的命令,有助于排查部署问题。从 serve 命令源码 可以看到:

    • rw serve 是子命令式结构,支持 serve(默认同时服务 Web 与 API)、serve api、serve web 三种形态;
    • 启动前中间件会做一系列前置校验:例如 serve web 要求 web/dist 下存在 index.html,serve api 要求已执行 yarn rw build api(即 api/dist 存在);若缺少构建产物会直接报错退出。这正是部署脚本中先执行 yarn rw build 的原因;
    • 若进程启动时未设置 NODE_ENV,命令会将其补为 production(见 serve.js 中 process.env.NODE_ENV = 'production' 的逻辑),所以生产环境下无需显式设置该变量;
    • serve api 的 –port 默认值 8911,与本文 Nginx 配置中的 proxy_pass http://localhost:8911/ 完全对应。

    从架构角度,yarn rw serve api 启动的是一个 Fastify 服务器来承载 GraphQL 端点与自定义函数;yarn rw serve web 则负责托管 web/dist 静态资源(也可通过 –apiHost 把 API 请求转发到远端)。本手册选择"只让 PM2 跑 API、让 Nginx 托管静态文件"的组合,是生产环境中最稳的模式——因为 Redwood 内置的 Web 服务器(Fastify)并不是为高流量静态文件托管而设计的,专业 Web 服务器 Nginx 更适合承担这一角色。

    九、从手动配置到 Baremetal 自动化

    本手册的手动方案是理解 Serverful 部署的最佳起点。如果你想进一步自动化,仓库的 Baremetal 部署文档 提供了官方的一体化方案:

    • 一条命令即可完成发布:yarn rw deploy baremetal production –first-run(首次)与 yarn rw deploy baremetal production(后续);
    • 它内部复用了 PM2:默认生成 ecosystem.config.js 运行 yarn rw serve(同时服务两端,Web 默认 8910 端口),并支持拆分为仅服务 API 的配置配合 Nginx;
    • 同样需要 Nginx 反向代理,Baremetal 文档给出了 nginx.conf 的完整示例,其中 location ~ /api(.*) + rewrite ^/api(.*) $1 break 的做法与本文 proxy_pass 尾斜杠技巧异曲同工,都是把对外路径剥掉前缀后映射到后端;
    • Baremetal 还支持 –rollback 回滚、–maintenance 维护页、pm2 startup 开机自启等生产级能力。

    简言之:本文的手动配置 = Baremetal 自动化替你执行的那组命令的"展开版"。先在服务器上手动跑通这条链路,再用 Baremetal 封装它,是稳妥的上线路径。

    十、小结

    Serverful 自托管让 Redwood 摆脱 Serverless 平台的约束,回到"自己的一台服务器"上:Nginx 负责静态文件与反向代理,PM2 负责进程守护与发布,yarn rw serve api 负责承载 GraphQL API,DATABASE_URL 连接生产 Postgres。本文从应用侧三处配置(PM2 依赖、pm2.config.js、redwood.toml 的 apiUrl)讲起,覆盖了服务器用户准备、Nginx 站点配置(注意 proxy_pass 尾斜杠)、PM2 生态配置(注意 fork 模式限制)以及"初始化 → 配 .env → 一键发布"的完整部署流程,并深入到 serve 命令源码 与 CLI 参考 解释了底层原理。按此流程,你就能把自己的 Redwood 应用稳定地跑在自有服务器上。

    分享

    • 后端
    • 前端
    • Web框架
    • 开发工具

    【免费下载链接】redwood

    RedwoodGraphQL

    项目地址:
    https://gitcode.com/gh_mirrors/re/redwood

    点击查看 免费下载

    上一篇:
    slam_toolbox与其他SLAM库对比分析:为什么它是生产机器人的首选

    下一篇:
    《ECMAScript 6 入门》精读:let 与 const 命令的块级作用域、暂时性死区与顶层对象脱钩

    创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Redwood 自托管(Serverful)部署实战:使用 PM2 与 Nginx 在 Linux 服务器上运行完整应用
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!