Next.js 混合部署需 Nginx 路径分流:静态页(如 /、/blog/xxx)由 out/ 目录直接服务,SSR 页(如 /dashboard、/api/xxx)代理至 next start;核心是 try_files $uri $uri/ @ssr 实现自动回退。

Next.js 项目在真实生产中,很少纯粹用 SSR 或纯粹静态导出——更多是混合场景:比如首页、文章页走 SSG 静态导出(快且省资源),而用户中心、搜索页、表单提交页必须用 SSR(需实时数据或服务端逻辑)。Nginx 要同时支持这两种模式,关键不在“能不能”,而在“怎么分发请求”。
先确认哪些路径该走静态,哪些必须走 Node
静态导出部分(如 /、/about、/blog/xxx)必须已通过 next export 或 output: 'export' 构建完成,输出到 out/ 目录;SSR 部分(如 /dashboard、/api/xxx、/search)则由 next start 服务提供,监听 127.0.0.1:3000。
你不能把所有请求都 proxy_pass 给 Node,也不能全扔给静态文件目录——得靠 Nginx 的 location 规则做路径分流:
-
location ^~ /_next/static/→ 直接读out/_next/static/,加长缓存 -
location = /_next/image→ 必须proxy_pass http://127.0.0.1:3000(图片优化端点不支持静态导出) -
location ^~ /api/→ 全部代理到 Node(API 路由不参与静态导出) -
location /→ 先查out/下是否存在对应 HTML 文件,不存在就 fallback 到 SSR 服务
静态 + SSR 混合的 Nginx 配置模板
假设你的静态文件放在 /var/www/myapp/out,Next.js SSR 服务运行在 127.0.0.1:3000:
server {
listen 80;
server_name example.com;
<pre class="brush:php;toolbar:false;"># 静态资源根目录
root /var/www/myapp/out;
index index.html;
# 优先服务 _next/static(JS/CSS/字体等)
location ^~ /_next/static/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# _next/image 必须走 Node,不可静态提供
location = /_next/image {
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;
}
# API 路由全部代理
location ^~ /api/ {
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;
}
# 主路由:先找静态文件,找不到再交给 SSR
location / {
try_files $uri $uri/ @ssr;
}
# SSR 回退入口
location @ssr {
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 90;
}
}
注意:try_files $uri $uri/ @ssr 是混合部署的核心逻辑——它让 Nginx 自动判断一个请求是否能被静态满足;只有真正需要 SSR 渲染的路径(比如带 query 的搜索页、登录态校验页),才会触发 @ssr 块。
构建与部署流程要严格分离
静态导出和 SSR 服务不能共用同一套构建产物。你需要两步构建:
- 执行
npm run build && npm run export(或 Next.js 13+ 的output: 'export'),生成out/目录,用于 Nginx 直接托管 - 单独执行
npm run build(不加 export),保留.next/目录,用于后续next start启动 SSR 服务
两个产物应分别部署:静态文件放 Web 根目录,SSR 服务用 pm2 或 systemd 后台运行,只监听本地端口,不暴露公网。
常见陷阱与绕过方案
混用时最容易出问题的是路径冲突和头信息丢失:
-
404 静态页面却进了 SSR:检查
out/目录下是否有对应 HTML(如out/dashboard/index.html),有就说明你不该让它走 SSR;若本意是动态页,就别放进getStaticPaths或导出逻辑里 -
/_next/image 返回 404 或空白:确认 Nginx 中
location = /_next/image是精确匹配(用=),且没被其他location ^~ /_next/规则提前捕获 -
SSR 页面 Cookie 丢失或协议错误:确保
X-Forwarded-Proto和Host头完整透传,否则getServerSideProps中的req.headers.cookie或重定向会异常 -
API 请求超时:SSR 服务调外部接口时,Nginx 的
proxy_read_timeout应 ≥ 后端最大预期响应时间(建议设为 60–90 秒)











