LHIDC

在香港节点部署Next.js SSR站点:PM2、Nginx反向代理与HTTPS验证流程

面向初学者介绍Next.js SSR站点在Linux香港节点上的生产部署流程,涵盖Node.js与PM2进程守护、Nginx反向代理、HTTPS证书申请续期及上线验证排查。

在香港节点部署Next.js SSR站点:PM2、Nginx反向代理与HTTPS验证流程

先把目标和前置条件对齐

一次常见的部署故障是:Next.js 项目在本地 npm run dev 正常,上传到香港节点后却出现 502、页面刷新报错、HTTPS 证书申请失败,或者重启服务器后站点无法自动恢复。问题通常不在 Next.js 本身,而在生产运行方式、Nginx 反向代理和证书验证链路没有串起来。

本文以一台 Linux 香港节点为例,完成一个 Next.js SSR 站点的生产部署:Node.js 负责运行应用,PM2 负责进程守护和开机自启,Nginx 负责监听 80/443 并反向代理到本机端口,HTTPS 使用 Let’s Encrypt 证书完成验证。示例默认系统为 Ubuntu 22.04/24.04,域名已准备好并可添加 DNS 记录;如果你的系统是 Debian、CentOS 或其他发行版,包管理命令需要对应调整。

开始前请确认:

  • 你拥有一台可公网访问的香港节点,并具备 SSH 登录权限;
  • 域名已解析到该节点公网 IPv4 地址,至少准备 example.com,如需同时访问 www.example.com 也要添加对应解析;
  • 安全组或防火墙已放行 22、80、443 端口;
  • Next.js 项目可以在本地完成 npm run build
  • 项目是 SSR 或混合渲染站点,不是纯静态导出的 next export 部署方式。

下文中的 example.com/var/www/nextapp3000 请替换为你的真实域名、项目路径和应用端口。

最小可用部署:让 Next.js 在服务器上稳定运行

安装 Node.js、Nginx 与 PM2

不要在生产环境使用 next devnext dev 是开发服务器,包含热更新和调试能力,不适合作为线上入口。生产部署应先执行 next build,再使用 next start 或 standalone 方式运行。

在 Ubuntu 22.04/24.04 上,可以安装 Node.js LTS 版本。以下以 Node.js 20 为例;如果你对安装源有审计要求,应先查看 NodeSource 官方文档后再执行安装脚本。

sudo apt update
sudo apt install -y curl ca-certificates gnupg nginx

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

node -v
npm -v

安装 PM2:

sudo npm install -g pm2
pm2 -v

建议不要直接用 root 长期运行应用。可以创建一个普通部署用户,或者使用已有的非 root 用户。下面示例假设使用当前登录用户部署。

创建项目目录:

sudo mkdir -p /var/www/nextapp
sudo chown -R $USER:$USER /var/www/nextapp

将代码上传到 /var/www/nextapp。可以使用 Git 拉取,也可以通过 SFTP、rsync 或 CI/CD 上传。进入项目目录后安装依赖并构建:

cd /var/www/nextapp

npm ci
npm run build

如果构建失败,先不要继续配置 Nginx。Next.js SSR 站点必须先在本机端口跑通,再交给 Nginx 代理,否则后面排查会混在一起。

用 PM2 启动 Next.js 生产进程

在项目根目录创建 ecosystem.config.cjs

module.exports = {
  apps: [
    {
      name: "next-ssr",
      cwd: "/var/www/nextapp",
      script: "node_modules/next/dist/bin/next",
      args: "start -H 127.0.0.1 -p 3000",
      env: {
        NODE_ENV: "production"
      }
    }
  ]
};

这里有两个关键点:

  • -H 127.0.0.1 表示 Next.js 只监听本机地址,不直接暴露到公网;
  • -p 3000 是内部应用端口,后续由 Nginx 将 80/443 请求代理到该端口。

启动应用:

cd /var/www/nextapp
pm2 start ecosystem.config.cjs
pm2 status

查看应用日志:

pm2 logs next-ssr --lines 50

本机验证:

curl -I http://127.0.0.1:3000

如果返回 HTTP/1.1 200 OK307308 或其他符合你应用路由逻辑的状态,说明 Node.js 与 PM2 运行链路基本正常。若这里已经连接失败,优先检查 pm2 logs,不要先改 Nginx。

设置 PM2 开机自启:

pm2 save
pm2 startup systemd -u $USER --hp $HOME

执行后,PM2 会输出一条需要 sudo 执行的命令。复制并执行该命令,再确认服务状态:

systemctl status pm2-$USER

后续发布新版本时,常见流程是:

cd /var/www/nextapp
git pull
npm ci
npm run build
pm2 reload next-ssr --update-env

如果你不是通过 Git 部署,替换为你的代码上传方式即可。上线前建议保留上一版本代码或构建包,避免发布失败时无法回滚。

Nginx反向代理:让域名访问到本机应用端口

PM2 只负责让 Next.js 进程稳定运行,真正接收公网 HTTP/HTTPS 请求的是 Nginx。Nginx反向代理的作用是:外部用户访问 http://example.comhttps://example.com,Nginx 接收请求后转发到 127.0.0.1:3000,再把 Next.js 返回的页面响应给用户。

创建站点配置:

sudo nano /etc/nginx/sites-available/nextapp

写入以下配置,将域名替换为你的真实域名:

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    access_log /var/log/nginx/nextapp.access.log;
    error_log /var/log/nginx/nextapp.error.log;

    client_max_body_size 20m;

    location /_next/static/ {
        proxy_pass http://127.0.0.1:3000/_next/static/;
        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;

        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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_read_timeout 60s;
        proxy_send_timeout 60s;
        proxy_cache_bypass $http_upgrade;
    }
}

启用站点并检查配置:

sudo ln -s /etc/nginx/sites-available/nextapp /etc/nginx/sites-enabled/nextapp
sudo nginx -t
sudo systemctl reload nginx

如果提示符号链接已存在,不要重复创建,直接检查配置即可。若默认站点占用了相同域名或返回 Nginx 欢迎页,可以查看:

ls -l /etc/nginx/sites-enabled/

确认没有其他配置抢占同一个 server_name。不要随意删除配置文件,建议先备份或只取消不需要站点的软链接。

本机带 Host 头验证 Nginx 转发:

curl -I -H "Host: example.com" http://127.0.0.1

公网验证:

curl -I http://example.com

此时即使还没有 HTTPS,只要 DNS 已生效、80 端口放行、PM2 应用正常,HTTP 访问应该能进入 Next.js 站点。

优化项:减少重启风险和代理误判

明确 SSR 应用与静态站点的差异

Next.js SSR 站点需要 Node.js 进程持续运行,因为请求到达时可能要执行服务端渲染、读取环境变量、访问接口或生成响应。它不同于纯静态 HTML 文件,不能只把 .next 目录丢给 Nginx 当静态目录使用。

判断方式很简单:

  • 使用 getServerSideProps、动态服务端组件、API Routes、Route Handlers,通常需要 Node.js 运行时;
  • 使用 next start 运行,说明需要 Next.js 服务进程;
  • 如果项目配置了 output: "export" 并生成纯静态文件,部署方式会不同,不应套用本文的 SSR 流程。

注意环境变量加载位置

Next.js 生产运行时常用 .env.production 或系统环境变量。修改环境变量后,只 reload Nginx 不会让应用读取新变量,需要重新构建或重启 PM2,具体取决于变量是在构建期还是运行期读取。

常用处理方式:

cd /var/www/nextapp
npm run build
pm2 reload next-ssr --update-env

环境变量文件建议限制权限:

chmod 600 /var/www/nextapp/.env.production

不要把数据库密码、API Token 写入 Nginx 配置,也不要提交到公开代码仓库。

控制应用监听范围

很多 502 或安全扫描告警来自一个细节:Next.js 同时监听了公网地址和 Nginx 代理入口。生产环境中,推荐 Next.js 只监听 127.0.0.1,对外只开放 Nginx 的 80/443。

检查端口监听:

ss -lntp | grep 3000

期望看到类似:

LISTEN 0 511 127.0.0.1:3000 0.0.0.0:*

如果看到 0.0.0.0:3000,说明应用对所有网卡开放。虽然安全组可能未放行 3000,但更稳妥的做法仍是从启动参数上限制为 127.0.0.1

HTTPS证书:申请、重定向与续期验证

HTTPS 证书申请前必须满足两个条件:域名解析到当前香港节点公网 IP,且 80 端口可以从公网访问。Let’s Encrypt 的 HTTP-01 验证会通过 80 端口访问你的域名,如果 DNS 未生效、Nginx 配置错误或安全组拦截,证书申请会失败。

安装 Certbot:

sudo apt install -y certbot python3-certbot-nginx

申请证书并让 Certbot 自动修改 Nginx 配置:

sudo certbot --nginx -d example.com -d www.example.com

执行过程中通常会询问邮箱、服务条款以及是否将 HTTP 重定向到 HTTPS。生产站点一般选择重定向到 HTTPS。完成后,Certbot 会在 Nginx 配置中加入 listen 443 ssl、证书路径和重定向规则。

检查 Nginx 配置并重载:

sudo nginx -t
sudo systemctl reload nginx

验证 HTTPS:

curl -I https://example.com

查看证书信息:

echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -subject -issuer -dates

确认自动续期任务:

systemctl list-timers | grep certbot
sudo certbot renew --dry-run

如果 renew --dry-run 成功,说明证书续期链路基本可用。证书通常不需要手动下载、上传或定期替换;只要续期任务正常,Certbot 会在到期前自动续期。

HTTPS 稳定后,可以考虑增加安全响应头。示例:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

HSTS 要谨慎启用,尤其是包含子域名的配置。一旦浏览器记住强制 HTTPS,而你的某些子域名没有证书或不支持 HTTPS,访问会直接失败。建议确认所有相关域名都已完成 HTTPS 后再添加。

上线验证:按链路逐层确认

部署完成后,不要只用浏览器打开首页判断成功。Next.js SSR 站点上线至少要验证进程、端口、代理、证书和业务页面五个层面。

验证项 命令或方式 期望结果
PM2 进程 pm2 status next-ssr 状态为 online
应用端口 curl -I http://127.0.0.1:3000 返回符合应用逻辑的 HTTP 状态
Nginx 配置 sudo nginx -t 显示 syntax is ok 和 test is successful
HTTP 访问 curl -I http://example.com 可访问,或 301/308 跳转到 HTTPS
HTTPS 访问 curl -I https://example.com 返回 200、301、308 等有效状态
证书链 openssl s_client 域名、签发者、有效期正常
日志观察 pm2 logs、Nginx access/error log 无持续 502、499、500 错误

Nginx 日志位置可按前面的配置查看:

sudo tail -f /var/log/nginx/nextapp.access.log
sudo tail -f /var/log/nginx/nextapp.error.log

PM2 日志查看:

pm2 logs next-ssr --lines 100

如果页面首页正常,但刷新动态路由出现 404,需要确认请求是否进入 Next.js,而不是被 Nginx 当作静态文件处理。本文的 location / 会统一代理给 Next.js,通常不会出现 SPA 静态站点那种 try_files 路由问题。

常见错误与排查顺序

访问域名返回 502 Bad Gateway

502 表示 Nginx 收到了请求,但无法从上游 Next.js 应用拿到有效响应。按顺序检查:

  1. PM2 进程是否在线:
pm2 status
  1. 本机端口是否可访问:
curl -I http://127.0.0.1:3000
  1. Nginx 代理地址是否和 PM2 启动端口一致:
grep -R "proxy_pass" /etc/nginx/sites-enabled/
  1. 查看应用日志:
pm2 logs next-ssr --lines 100

如果 127.0.0.1:3000 不通,是 Node.js/PM2 问题;如果本机端口通但域名 502,多数是 Nginx 配置或代理地址问题。

证书申请失败

常见原因包括:

  • DNS 还没解析到当前香港节点;
  • 80 端口未放行;
  • Nginx 配置测试失败;
  • 同一个域名被其他 server block 抢占;
  • CDN 或代理层拦截了 Let’s Encrypt 验证请求。

先在服务器外部执行:

curl -I http://example.com

如果 HTTP 都无法访问,先不要重复申请证书。重复失败过多可能触发证书机构的频率限制。

重启服务器后站点不可用

这种情况通常是 PM2 自启没有配置成功,或应用运行在某个临时 shell 会话中。检查:

pm2 status
systemctl status pm2-$USER

如 PM2 列表为空,进入项目目录重新启动并保存:

cd /var/www/nextapp
pm2 start ecosystem.config.cjs
pm2 save

再执行 pm2 startup 并按提示完成 systemd 自启配置。

HTTPS 正常但页面资源加载异常

如果 HTML 能打开,但 JS、CSS 或图片加载失败,重点查看浏览器控制台和 Nginx access log。常见原因有:

  • 应用中写死了旧域名或 HTTP 地址;
  • NEXT_PUBLIC_ 环境变量未重新构建;
  • 反向代理没有正确传递 HostX-Forwarded-Proto
  • 图片域名未在 next.config.jsimages.domainsremotePatterns 中允许。

修改 next.config.js 或构建期环境变量后,需要重新构建:

npm run build
pm2 reload next-ssr --update-env

上线前检查清单

  • 域名 A 记录已指向当前香港节点公网 IP,www 与裸域名按需配置;
  • 安全组或系统防火墙已放行 80、443,只在需要时开放 SSH;
  • Next.js 使用 npm run build 后由 PM2 运行,不使用 next dev
  • 应用监听 127.0.0.1:3000,公网入口交给 Nginx;
  • Nginx反向代理中的 server_nameproxy_pass、日志路径配置正确;
  • sudo nginx -t 通过,reload 后 HTTP 可访问;
  • HTTPS 证书申请成功,certbot renew --dry-run 通过;
  • pm2 savepm2 startup 已完成,服务器重启后应用能自动恢复;
  • .env.production 权限已收紧,敏感信息未写入公开仓库;
  • 使用 curl、浏览器、PM2 日志和 Nginx 日志完成最终验证,再切换正式流量。
上一篇 香港节点适合哪些跨境业务:延迟、路由、回源与合规边界说明 下一篇 旧金山裸金属服务器与旧金山VPS用于美国西部业务,性能边界如何判断

LHIDC 产品中心

继续查看可购买的海外服务器产品

文章用于辅助选型,最终价格、库存与配置请以产品详情页和下单页面展示为准。

查看产品 查看方案