查看: 188|回复: 3

Nuxt4生产部署:PM2集群与Nginx SSR反向代理配置

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
Nuxt 4 使用 Nitro 引擎,生产环境 SSR 不能只上传静态文件,需要 Node 进程与 Nginx 反向代理配合。下面按原文给出的 CentOS/Ubuntu 流程,整理环境要求、PM2 环境变量、构建发布、Nginx 动静分离、自动化脚本以及常见故障排查。原文配置的关键点在于:PM2 负责运行 .output/server/index.mjs,Nginx 负责 /_nuxt/ 静态资源缓存、/api/ 转发和 SSR 回源;在 CentOS 上还要注意 SELinux 对本地端口连接的拦截。

一、环境要求

操作系统可以是 Ubuntu 20.04+、CentOS 7+ 或 Debian 11+;Node.js 要求 >= 20.10.0,因为 Nuxt 4 强依赖高版本 Node;Nginx 要求 >= 1.18;PM2 用于 Node.js 进程管理。硬件建议内存 >= 2GB,磁盘 >= 10GB 可用空间。部署前先确认这些版本,尤其是 Node.js 版本和 Nginx 是否已安装。

二、环境变量与 PM2 配置

Nuxt 4 默认使用 Nitro。部署前要区分 SSR 端调用和浏览器端调用。原文推荐在项目根目录创建或编辑 ecosystem.config.cjs,通过环境变量注入配置。其中 NUXT_PUBLIC_API_BASE 对应代码中的 useRuntimeConfig().public.apiBase,用于 SSR 模式下服务器访问后端接口的基准地址。
  1. module.exports = {
  2. apps: [{
  3. name: 'nuxt-app',
  4. port: 3000,
  5. host: '127.0.0.1',
  6. script: './.output/server/index.mjs',
  7. exec_mode: 'cluster', // 开启集群模式
  8. instances: 'max', // 根据 CPU 核心数启动实例
  9. env: {
  10. NODE_ENV: 'production',
  11. // SSR 模式下服务器访问后端接口的基准地址
  12. NUXT_PUBLIC_API_BASE: 'https://api.yourdomain.com',
  13. }
  14. }]
  15. }
复制代码

这里的 script 指向 Nitro 构建后的服务端入口,exec_mode 使用 cluster,instances 设为 max 可按 CPU 核心数启动实例。

三、构建、上传与启动

先在本地开发机执行构建,确保构建产物是最新的,然后压缩 .output 和 PM2 配置文件,减少传输时间。
  1. # 构建 Nuxt 4 项目
  2. pnpm build
  3. # 压缩打包产物
  4. tar -czf release.tar.gz .output ecosystem.config.cjs
复制代码

将压缩包上传到服务器 /var/www/nuxt-app 目录,可以通过 scp 上传,登录服务器后解压。
  1. # 示例:使用 scp 上传
  2. scp release.tar.gz user@your-server-ip:/var/www/nuxt-app/
  3. # 登录服务器解压
  4. cd /var/www/nuxt-app
  5. tar -xzf release.tar.gz
复制代码

首次部署需要全局安装 PM2 并启动应用,然后设置开机自启并保存进程列表。
  1. # 全局安装 PM2
  2. npm install -g pm2
  3. # 启动应用
  4. pm2 start ecosystem.config.cjs
  5. # 设置开机自启
  6. pm2 startup
  7. pm2 save
复制代码

四、Nginx 核心配置

在 CentOS/Ubuntu 上建议创建独立配置文件 /etc/nginx/conf.d/nuxt.conf。原文配置实现了动静分离和 API 转发:/_nuxt/ 下的 JS/CSS 由 Nginx 直接响应并设置长期缓存;/api/ 转发到真实后端,解决浏览器端访问时的跨域问题;主入口先尝试读取 public 下的静态文件,读不到再交给 SSR 渲染出口。
  1. # 定义 Node 应用的上游
  2. upstream nuxt_backend {
  3. server 127.0.0.1:3000;
  4. keepalive 64;
  5. }
  6. server {
  7. listen 80;
  8. server_name yourdomain.com; # 换成实际域名
  9. # 1. 静态资源直接由 Nginx 响应 (提升性能)
  10. # 对应 Nuxt 打包后的 JS/CSS
  11. location /_nuxt/ {
  12. alias /var/www/nuxt-app/.output/public/_nuxt/;
  13. expires 365d;
  14. add_header Cache-Control "public, max-age=31536000, immutable";
  15. access_log off;
  16. }
  17. # 2. 业务 API 转发
  18. # 解决浏览器端访问 /api 时的跨域问题
  19. location /api/ {
  20. proxy_pass http://api.internal-server.com/; # 转发到真实后端
  21. proxy_set_header Host $host;
  22. proxy_set_header X-Real-IP $remote_addr;
  23. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  24. }
  25. # 3. 主程序入口
  26. location / {
  27. # 尝试直接读取 public 下的静态文件 (favicon.ico 等)
  28. root /var/www/nuxt-app/.output/public;
  29. try_files $uri $uri/ @ssr;
  30. }
  31. # 4. SSR 渲染出口
  32. location @ssr {
  33. proxy_pass http://nuxt_backend;
  34. proxy_http_version 1.1;
  35. proxy_set_header Upgrade $http_upgrade;
  36. proxy_set_header Connection 'upgrade';
  37. proxy_set_header Host $host;
  38. proxy_set_header X-Real-IP $remote_addr;
  39. proxy_cache_bypass $http_upgrade;
  40. client_max_body_size 20m;
  41. }
  42. }
复制代码

这段配置里,upstream 使用 keepalive 64 维护到 Node 的连接;/_nuxt/ 使用 alias 指向构建后的静态目录,并用 immutable 和一年过期时间降低重复请求;@ssr 使用 HTTP/1.1 并带上 Upgrade 相关头,同时设置 client_max_body_size 20m,适合有上传或较大请求体的场景。

五、自动化更新脚本

原文在本地根目录准备 deploy.sh,实现构建、打包、上传、解压和重启的一键发布。脚本中的 SERVER_USER、SERVER_IP、DEPLOY_PATH 需要按实际环境修改,pm2 reload nuxt-app 对应 ecosystem 配置里的应用名。
  1. #!/bin/bash
  2. # 配置项
  3. SERVER_USER="root"
  4. SERVER_IP="1.2.3.4"
  5. DEPLOY_PATH="/var/www/nuxt-app"
  6. echo "🚀 开始构建..."
  7. pnpm build
  8. echo "📦 正在打包..."
  9. tar -czf release.tar.gz .output ecosystem.config.cjs
  10. echo "📤 上传服务器..."
  11. scp release.tar.gz $SERVER_USER@$SERVER_IP:$DEPLOY_PATH
  12. echo "🔄 重启服务..."
  13. ssh $SERVER_USER@$SERVER_IP "cd $DEPLOY_PATH && tar -xzf release.tar.gz && pm2 reload nuxt-app"
  14. echo "✨ 部署完成!"
复制代码

六、CentOS 常见故障排查

1. Nginx 502 错误。CentOS 上 SELinux 默认可能禁止 Nginx 连接本地端口,可以先检查 httpd_can_network_connect,再开启权限。
  1. # 检查是否因为权限被拦
  2. sudo getsebool httpd_can_network_connect
  3. # 开启权限
  4. sudo setsebool -P httpd_can_network_connect 1
复制代码

2. 静态资源 403 Forbidden。需要确保 Nginx 用户(通常是 nginx 或 www-data)对项目目录有读取权限。
  1. sudo chmod -R 755 /var/www/nuxt-app
复制代码

3. PM2 日志查看。应用运行不正常时,通过日志定位问题。
  1. pm2 logs nuxt-app --lines 100
复制代码

七、HTTPS 配置与目录结构

使用 Certbot 为 Nginx 配置 HTTPS,原文给出 CentOS 下的安装和签发命令。
  1. sudo dnf install certbot python3-certbot-nginx
  2. sudo certbot --nginx -d yourdomain.com
复制代码

部署后的目录结构可参考如下:.output 下包含 server 和 public,server 是 Nitro Server 逻辑,public 是浏览器访问的静态文件;ecosystem.config.cjs 是 PM2 配置;release.tar.gz 是传输包或备份包。
  1. /var/www/nuxt-app/
  2. ├── .output/ # 构建产物 (SSR 入口 & 静态资源)
  3. │ ├── server/ # Nitro Server 逻辑
  4. │ └── public/ # 浏览器访问的静态文件
  5. ├── ecosystem.config.cjs # PM2 配置文件
  6. └── release.tar.gz # 备份/传输包
复制代码

整体来看,Nuxt 4 生产部署要核对 Node.js 版本、.output 路径、PM2 应用名、Nginx upstream 端口 3000,以及 CentOS 下的 SELinux 和目录权限。静态资源交给 Nginx 缓存、API 单独转发、SSR 回源到本地 Node 进程,这种分工能降低 Node 压力,也便于后续排错和自动发布。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Nuxt4生产部署:PM2集群与Nginx SSR反向代理配置

整体思路很完整,动静分离和 @ssr 回源的结构基本可以直接照搬。补充几个实际部署时容易踩的点,供参考: 一是 ecosystem.config.cjs 里的 port 和 host 这两个字段 PM2 本身并不识别,它们只是被原样塞进配置文件,不会自动变成应用的环境变量。Nitro 读的是 PORT/HOST 或 NITRO_PORT/NITRO_HOST,所以最好在 env 里显式写上 NITRO_PORT 和 NITRO_HOST,不然可能出现应用监听在别的地址、Nginx upstream 连不上的情况,排查起来很绕。 二是 upstream 那里虽然写了 keepalive 64,但 @ssr 里又设置了 Connection 'upgrade',这会让到后端的连接变成非 keepalive,长连接优化的效果基本抵消。如果确实需要 WebSocket 升级,建议把 upgrade 相关头单独拆一个 location,普通 SSR 请求用 proxy_http_version 1.1 加 proxy_set_header Connection "";不需要 WS 的话直接把 Upgrade 那段去掉更干净。 三是 NUXT_PUBLIC_API_BASE 属于 public 运行时配置,会被打进客户端产物里,浏览器端也能看到。它的语义更偏向"浏览器访问后端的地址"。如果 S
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Nuxt4生产部署:PM2集群与Nginx SSR反向代理配置

感谢分享,这套流程整理得挺清楚的,尤其是动静分离和 SELinux 那段,很多人第一次在 CentOS 上部署都会卡在本地端口连接被拦。看完有几个小地方想补充和确认一下,供参考。 首先是 PM2 配置里 port 和 host 写在 apps 顶层,这两个不是 PM2 的标准字段,PM2 不会把它们传给应用。Nitro 的 node-server 入口读取的是 PORT、NITRO_PORT 和 HOST、NITRO_HOST,建议直接写进 env,比如 PORT 设为 3000、HOST 设为 127.0.0.1,否则可能出现 Nginx 以为在 3000、Node 却监听别的端口的情况。cluster 模式下 instances 用 max 在 2GB 内存的机器上要小心,Nuxt SSR 每个实例都有一定内存占用,核多内存少时容易 OOM,建议按内存留余量,配个 max_memory_restart 更稳。 其次是 Nginx 里 upstream 开了 keepalive 64,但 @ssr 里又把 Connection 固定成 upgrade,这两者是冲突的,keepalive 基本不会生效。比较稳妥的做法是用 map 根据 $http_upgrade 动态设置 Connection,普通请求置空、WebSocket 才 upgrade,同时 /api/ 那段也补上 pr
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Nuxt4生产部署:PM2集群与Nginx SSR反向代理配置

感谢整理,这套配置把 Nuxt 4(Nitro)生产部署的主干基本都串起来了,动静分离和 try_files 回源那一段写得比较清楚,尤其把 /_nuxt/ 用 alias 指到 .output/public/_nuxt/ 并加上 immutable 长缓存,这部分对首屏加载帮助很明显。 分享几个实际部署时容易踩的点,供参考: 一是 CentOS 的 SELinux,如果开着 enforcing,Nginx 反向代理到 127.0.0.1:3000 会直接 502,除了看 error.log 里的 permission denied,还需要执行 setsebool -P httpd_can_network_connect 1 放行,或者用 semanage 把端口标注好,这个坑排查起来挺花时间。 二是 PM2 的 instances: 'max',在 2G 内存的机器上如果 CPU 核数多,实际会起不少 Node 进程,SSR 内存占用不算低,建议先按核数上限压一压,比如 instances 设 2,观察 pm2 monit 再决定。 三是 Nginx 里 alias 指向目录时结尾斜杠要和 location 的 /_nuxt/ 对齐,否则会出现拼接路径错误导致静态资源 404,这点改配置时特别容易漏。 四是 upstream 里用了 keepalive 64,但要真正复用连接,@
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-11-6 06:34 , Processed in 0.021288 second(s), 28 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部