---
description: 前端静态站部署到 OpenResty（releases + current 软链原子切换；建站 + HTTPS 由部署引擎复用「网站」系统统一接管，不手写 conf）
applicable: [static, frontend]
buildSource: artifact
variables:
  - key: deployRoot
    label: 部署根目录
    default: "/opt/reeve/www/sites/{{project}}"
    required: true
  - key: sslEmail
    label: SSL 邮箱
    required: false
  - key: apiProxyPort
    label: API 反代端口（同域名后端口，如后端在 127.0.0.1:5500 就填 5500；留空=纯静态站不反代）
    required: false
  - key: apiProxyPrefix
    label: API 反代前缀（如 ryplus_uni → /ryplus_uni/ 转发到后端；默认 api）
    default: api
    required: false
---

# 前端静态站 · OpenResty

把本地构建好的静态产物（dist）打包上传，按 `releases/ + current` 软链原子切换发布。

> **建站与 SSL 由部署引擎接管**：网站根 `sites/<域名>/index`（软链→current）、独立 `log/`、nginx 站点 conf
> 和 HTTPS 自动签发，全部复用「网站」标签同一套 `render_static`/`inject_*`/certbot 实现（域名锚点 conf、
> 与手动建站完全一致、parse 不漂移）。本配方只负责产物发布。域名必填（向导强制）；勾 HTTPS + 填邮箱即自动签证书。
> 容器化 OpenResty（应用商店装的 reeve-openresty）与宿主 openresty 双模式自适应。
>
> 🔴 **同域名「前端 SPA + 后端 API」一站搞定**：填 `apiProxyPort`（后端口，如 5500）+ `apiProxyPrefix`
> （如 `ryplus_uni`），引擎自动在本站 conf 注入 `location /<prefix>/ → 127.0.0.1:<port>`（含 WebSocket 头），
> 80/443 两块都注入。于是 `/` 给前端、`/<prefix>/` 给后端，**同域名免跨域、无需手写 vhost**。后端容器只需
> 监听 `127.0.0.1:<port>`、**不要**给后端部署目标设 domain（否则会被整域反代覆盖）。

```bash stage:release on:target
# 软链 current 已由引擎切到新 release；此处仅自检产物就绪（建站由引擎接管）
test -d "{{currentLink}}" || { echo "current 未就绪"; exit 1; }
test -f "{{currentLink}}/index.html" || echo "提示：current 下未见 index.html（SPA 入口），请确认构建产物正确"
```

```bash stage:health on:target
# current 下有 index.html，且 OpenResty 在运行（容器 running / 宿主进程存活）
test -f "{{currentLink}}/index.html" || { echo "current 下缺 index.html"; exit 1; }
if docker inspect -f '{{.State.Status}}' reeve-openresty >/dev/null 2>&1; then
  docker inspect -f '{{.State.Status}}' reeve-openresty | grep -q running
else
  pgrep -x nginx >/dev/null 2>&1 || pgrep -x openresty >/dev/null 2>&1
fi
```
