CentOS 7服务器发布Next.js SSR站点的上线流程
面向前端开发工程师,本文给出在CentOS 7上上线Next.js SSR站点的完整最小闭环:先校验前置条件,再用PM2启动应用并通过Nginx反向代理接入,最后按清单验证服务。文中附带502、404、重启失联等常见问题的排查与回滚思路,可直接用于实际演练。

目标状态
你在前端开发里最常碰到的情况是:本地 npm run build && npm run start 跑得很好,但放到 CentOS 7 后第一次访问就 502,或者页面刷新随机变成空白。先把目标说清楚:在 CentOS 7 服务器上完成 SSR 站点最小闭环上线,核心是三个环节稳定闭合——Next.js 构建产物 -> PM2 持续运行 -> Nginx 反向代理。
这意味着在不更换部署方式、不引入额外编排前提下,能否对外提供页面服务,取决于这三层是否都满足条件。只要你在每层都做了明确校验,后续排障会快很多。
前置条件(先满足再动手)
- 有
CentOS 7登录权限(建议使用 sudo 用户,避免长期 root 运行 Node)。 - 机器可以访问外网仓库(拉取依赖或克隆代码)。
- 项目有生产构建脚本:
build与start存在且可执行。 - 业务允许单实例部署,先以一个
next-ssr实例上线验证闭环。
不先验真条件就上线,后续“看起来配置无误却 502”的概率会很高。
环境基础核对表
| 项目 | 校验命令 | 合格标准 |
|---|---|---|
| 系统版本 | cat /etc/redhat-release |
输出包含 CentOS Linux release 7 |
| Node 管理与版本 | node -v / npm -v |
版本满足项目 package.json 的 engines 要求 |
| 端口占用 | `ss -lntp | grep -E ":80 | :443 |
| 进程管理可用 | pm2 -v |
pm2 可执行 |
| Nginx 基础能力 | nginx -V |
Nginx 已安装且能启动命令 |
| 防火墙/SELinux | firewall-cmd --state、getenforce |
80/443(及内部 3000)放通,httpd_can_network_connect 条件可达 |
环境检查
先把最容易忽略的系统层问题先处理掉,别等到 Nginx 报错才回头找原因。
1) 用户与目录先隔离,避免权限事故
sudo id deploy || sudo useradd -m -s /bin/bash deploy
sudo mkdir -p /var/www/next-ssr /var/log/pm2
sudo chown -R deploy:deploy /var/www/next-ssr /var/log/pm2
2) 安装基础组件(按 CentOS 7 包管理方式)
sudo yum install -y epel-release
sudo yum install -y git curl gcc-c++ make nginx nodejs
node -v
npm -v
pm2 -v 2>/dev/null || sudo npm install -g pm2
nodejs套件来自系统源时版本有差异,若不满足 Next.js 版本要求,优先改用项目兼容的 Node 安装方式或镜像中已验证的 LTS。版本不对是“本地过、服务器不行”的高发根因。
3) 拉取代码并明确构建入口
sudo -iu deploy bash -lc '
set -e
cd /var/www/next-ssr
if [ ! -d ".git" ]; then
git clone <你的仓库地址> .
fi
ls -1 package.json
'
4) 安装依赖并构建生产包
sudo -iu deploy bash -lc '
set -e
cd /var/www/next-ssr
if [ -f package-lock.json ]; then
npm ci
else
npm install
fi
npm run build
'
- 构建成功后先别急着配反向代理,先本地直接打点验证:
cd /var/www/next-ssr && npm run start -- --hostname 127.0.0.1 --port 3000
如果本机 curl http://127.0.0.1:3000 能返回 HTML 起始内容,说明 SSR 运行链路起码没断。
分阶段部署
以下流程按“先应用再代理”顺序执行,能减少 Nginx 误导定位。
阶段一:用 PM2 接管 Next.js
先写一个确定性配置,避免每次手工参数不同导致漂移。
module.exports = {
apps: [
{
name: "next-ssr",
cwd: "/var/www/next-ssr",
script: "npm",
args: "run start",
instances: 1,
exec_mode: "fork",
env: {
NODE_ENV: "production",
PORT: 3000
},
max_memory_restart: "800M",
out_file: "/var/log/pm2/next-ssr-out.log",
error_file: "/var/log/pm2/next-ssr-error.log",
log_date_format: "YYYY-MM-DD HH:mm:ss"
}
]
}
保存为 /var/www/next-ssr/ecosystem.config.js,再启动:
sudo -iu deploy bash -lc '
cd /var/www/next-ssr
pm2 start ecosystem.config.js --env production
pm2 status
'
配置开机自启动:
sudo -iu deploy pm2 startup systemd -u deploy --hp /home/deploy
sudo -iu deploy pm2 save
pm2 startup会输出一条systemctl命令,按提示以 root 执行。先执行再重启验证,避免服务重启后失联。
阶段二:配置 Nginx 反向代理
先备份再替换,防止配置误改不可回退。
sudo cp /etc/nginx/conf.d/next-ssr.conf /etc/nginx/conf.d/next-ssr.conf.bak.$(date +%F_%H%M%S) 2>/dev/null || true
核心反代配置如下:
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;
}
access_log /var/log/nginx/next-ssr-access.log;
error_log /var/log/nginx/next-ssr-error.log;
}
写入并生效:
sudo tee /etc/nginx/conf.d/next-ssr.conf >/dev/null <<'EOF'
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;
}
access_log /var/log/nginx/next-ssr-access.log;
error_log /var/log/nginx/next-ssr-error.log;
}
EOF
sudo nginx -t && sudo systemctl reload nginx
防火墙与 SELinux 放通(按你环境实际执行):
command -v firewall-cmd && sudo firewall-cmd --permanent --add-service=http && sudo firewall-cmd --reload
sudo setsebool -P httpd_can_network_connect 1
阶段三:上线前再确认一次环境状态
sudo systemctl enable --now nginx
sudo systemctl status nginx --no-pager
pm2 startup # 若显示 not enabled,按系统提示补齐
上线检查
不把这步跳过,部署就算完成了,也算是“未上线”。 验证顺序固定:先看应用,再看代理,最后看日志。
关键验证清单
| 检查项 | 命令 | 目标结果 |
|---|---|---|
| PM2 运行 | pm2 status |
next-ssr 为 online |
| Next.js 本机端口 | ss -lntp | grep :3000 |
显示 LISTEN 0.0.0.0:3000 |
| Next.js 直接响应 | curl -I http://127.0.0.1:3000 |
HTTP 200/3xx,且返回头正常 |
| Nginx 转发 | curl -I http://127.0.0.1 |
同上,且响应时间稳定 |
| 系统日志 | journalctl -u nginx -n 100、tail -n 100 /var/log/pm2/next-ssr-error.log |
无启动期持续错误 |
| 外部域名访问(有域名时) | curl -I https://your.domain |
目标路径可达,头里 server 指向预期 |
线上出现间歇性 5xx 时,先看
curl -s http://127.0.0.1:3000是否稳定,再看localhost -> nginx,能快速判断是应用层问题还是代理层问题。这个顺序比“先查日志再猜配置”更省时间。
常见失败
以下故障按排查顺序写,基本都能在最小闭环内闭环定位。
| 现象 | 先查 | 一般修复 |
|---|---|---|
| 浏览器返回 502 | pm2 status、curl 127.0.0.1:3000 |
PM2 未起、端口被占用或脚本参数不一致(start 脚本未用 PORT=3000) |
| 刷新子路由出现 404 | Nginx 是否加了 try_files $uri $uri/ /index.html |
该规则不适用于 SSR 主体路由,删除并只做代理 |
npm run build 通过但 pm2 启动报错 |
PM2 配置里的 script 与实际启动方式 |
对纯 Next.js 项目优先用 npm run start,不要直接执行旧入口 |
| 页面加载卡死或内存飙升后重启 | PM2 日志是否出现 OOM/heap limit | 调低并发压力评估、设置 max_memory_restart、确认是否有内存泄漏 |
EACCES 无权限 |
日志里有路径不可写 | 校正运行用户与工作目录、日志目录归属,避免用 root 启动应用 |
| 客户端 WS 或热更新/订阅失败 | Nginx 是否缺少 Upgrade 头 |
保留 proxy_set_header Upgrade 与 Connection |
回滚
最小闭环上线后出现问题,回滚要快,不能把时间花在“猜”上。
回滚触发条件
- 上线后一小时内出现连续 502/500 且影响关键页面访问;
curl入口检查在应用层和代理层都不能稳定通过;- 回滚窗口内不能等到完整监控报警后才处理。
快速回滚步骤(按序执行)
- 保留一份最近稳定版本(建议事先
git tag或压缩构建目录)。 - 将代码回退到稳定提交并重建:
cd /var/www/next-ssr git fetch --all --prune git checkout <上一次稳定提交> npm ci npm run build - 重启 PM2 进程:
pm2 restart next-ssr --update-env - 若本次仅代理配置引入风险,恢复 Nginx 备份并重载:
sudo cp /etc/nginx/conf.d/next-ssr.conf.bak.<时间戳> /etc/nginx/conf.d/next-ssr.conf sudo nginx -t && sudo systemctl reload nginx - 重复
上线检查表中的 6 项命令,确认恢复后仅返回正常响应。
如果回滚后服务立刻恢复,优先比对这三类变更:ecosystem.config、环境变量、Nginx 反代块。这样你下次再上线时只会动其中一层,验证路径也会更短。