Nginx通过try_files优先服务静态资源,未命中时用@ssr内部跳转代理至Node.js SSR服务,并透传Host、X-Forwarded-*等关键头确保上下文一致。

在 Nginx 中用 proxy_pass 实现前后端同构项目的 SSR 代理,核心是让 Nginx 把浏览器请求合理分流:静态资源(如 JS、CSS、图片)直接由 Nginx 返回,而需要服务端渲染的页面(如 /、/user 等路由)转发给 Node.js(或类似)SSR 服务,同时确保 Cookie、Header、路径重写等关键细节正确传递。
区分静态资源与 SSR 路由
SSR 应用通常打包后有 dist/client(前端静态文件)和一个运行中的 Node 服务(如 Express/Nest/Koa 启动在 localhost:3000)。Nginx 需优先匹配静态文件,未命中时再交由 SSR 服务处理。
示例配置:
location / {
# 尝试匹配 dist/client 下的静态文件(index.html 也先查)
root /var/www/my-ssr-app/dist/client;
try_files $uri $uri/ @ssr;
}
<h1>SSR 后端代理</h1><p>location @ssr {
proxy_pass <a href="https://www.php.cn/link/92cdc3666b7883ebeed2973e70725bb1">https://www.php.cn/link/92cdc3666b7883ebeed2973e70725bb1</a>;
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;
}</p>说明:
– try_files $uri $uri/ @ssr 表示先查物理文件,查不到就跳转到 @ssr 内部命名位置;
– root 指向的是静态资源根目录,不是 index.html 路径;
– @ssr 是内部 location,不暴露给客户端,仅用于逻辑跳转。
处理 HTML 页面的 fallback(关键!)
单页应用 + SSR 场景下,用户可能直接访问 /dashboard 这类前端路由。此时 Nginx 找不到对应文件,必须交给 SSR 服务——但 SSR 服务本身也要能正确识别该路径并渲染对应内容。
常见错误:只配了 location /,却没覆盖所有可能的前端路由。稳妥做法是显式拦截所有非静态后缀的请求:
- 把
try_files放在更宽泛的location /中(如上); - 或额外排除静态资源后缀,例如:
location / {
# 排除常见静态资源后缀,其余全部走 SSR
if ($request_uri ~* "\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$") {
expires 1y;
add_header Cache-Control "public, immutable";
break;
}
proxy_pass https://www.php.cn/link/92cdc3666b7883ebeed2973e70725bb1;
# ... 其他 proxy_* 设置同上
}
⚠️ 注意:if 在 location 中慎用,推荐优先采用 try_files + root 方式,更安全高效。
保持 SSR 上下文一致(Cookie、协议、路径)
SSR 渲染常依赖用户登录态(Cookie)、当前域名、是否 HTTPS 等信息。Nginx 必须透传这些上下文:
-
proxy_set_header Host $host:确保 SSR 服务拿到原始 Host(用于生成绝对链接); -
proxy_set_header X-Forwarded-Proto $scheme:让 SSR 知道是 http 还是 https,避免混合内容或跳转异常; -
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for:保留真实客户端 IP; -
proxy_cookie_path / /:若 SSR 服务设置 Cookie 的 path 是/,此项可省略;如有子路径部署(如/app/),需调整; - 如 SSR 服务监听在 Unix socket 或不同端口,改
proxy_pass对应地址即可(如proxy_pass http://unix:/var/run/ssr.sock;)。
可选:支持 history 模式 + 子路径部署
如果项目部署在子路径(如 https://example.com/myapp/),需调整两处:
- Nginx 的
location做前缀匹配:location /myapp/ { ... }; - 静态资源路径加 base:
root /var/www/myapp/dist/client;,且 SSR 服务中router.base = '/myapp/'; - 代理时注意路径截断:用
rewrite ^/myapp/(.*)$ /$1 break;再proxy_pass https://www.php.cn/link/92cdc3666b7883ebeed2973e70725bb1;,避免把/myapp/xxx错误传给后端。
完整子路径示例片段:
location /myapp/ {
alias /var/www/myapp/dist/client/;
try_files $uri $uri/ @ssr_sub;
<pre class='brush:php;toolbar:false;'># 重写路径,去掉 /myapp/ 前缀再转发
location @ssr_sub {
rewrite ^/myapp/(.*)$ /$1 break;
proxy_pass https://www.php.cn/link/92cdc3666b7883ebeed2973e70725bb1;
# ... 其他 proxy_* 头
}}
不复杂但容易忽略的是:静态资源 404 不报错,但 SSR 请求失败会导致白屏;务必检查 Nginx error log 和 SSR 服务日志,确认 proxy_pass 是否真正连通、超时设置是否合理(可加 proxy_connect_timeout 5s; 等)。


















