build(deploy): production images, compose stacks and 1panel guide
P5-prep Task 1(docs/plans/2026-09-21-P5-准备件.md): - docker/server.Dockerfile:单镜像 photo-live-server 多角色(api-cn/api-ov/ worker/sync/migrate-deploy/seed-admin,entrypoint.sh 分发;migrate-deploy 支持 cn|ov|all 区域参数)。三阶段:全量 install(锁文件冻结)→ prisma generate 双库 + 逐包构建;--prod 依赖层;runtime=node:20-alpine+openssl/curl + 全局 prisma@5.22.0(对齐锁文件)+ 双库 client 镜像内重建(db-cn 落 pnpm store .prisma、db-ov 落包内 generated/)。sharp 走 musl 预编译验证通过。 - docker/web.Dockerfile + infra/deploy/nginx.conf.template:photo-live-web (nginx:alpine + envsubst 模板)。viewer(/,history 回退) + admin(/admin/, hash 路由) + /v1 反代 API_UPSTREAM(含 /v1/realtime WS 升级)+ /assets/、/admin/assets/、/embed/v1/ immutable 长缓存(admin assets 的 alias 前缀剥除坑已实测修复)。VITE_* 为构建期参数(VIEWER_BASE/ EMBED_ORIGIN 随域名构建传入)。 - infra/deploy/docker-compose.cn.yml / -ov.yml:cn=api-cn+worker+sync+web, ov=api-ov+web-ov(核实架构:sync 仅 cn 侧,inbox/emergency 内嵌 api-ov, 无 ov 侧 sync 进程);健康检查 /v1/health、unless-stopped、json-file 10m×3、外部 1panel-network 复用 1Panel MySQL/Redis、SERVER_IMAGE/ WEB_IMAGE 环境变量化镜像 tag(回滚杠杆)。 - .env.production.example-cn/-ov:生产变量全量清单(cn 25 键/ov 24 键, DB/Redis/OSS/SYNC/AUTH/限速/域名分组注释,源自 services+packages process.env 全量审计);.gitignore 放行 example,真实 .env.production-* 永不入库。 - infra/deploy/README-1Panel.md:镜像导入双路径(save tar 导入 / 仓库 pull)、 MySQL 建库授权 SQL(utf8mb4_0900_bin,<8.0.30 回退 utf8mb4_bin——D12)、 Redis 连接、1Panel 编排、OpenResty 反代+证书、migrate-deploy 一次性容器、 首次部署顺序(DB→迁移→ov 栈→cn 栈→seed→冒烟)。 - 根 package.json pnpm.onlyBuiltDependencies 增补 sharp/prisma/@prisma/ engines/@prisma/client(镜像构建所需 install 脚本白名单)。 本地验证:两镜像构建成功(server 988MB / web 97.7MB);compose config 校验 通过;server 镜像内逐服务 require(sharp/argon2/双 Prisma client/bullmq/ ioredis)与双引擎 so.node、migrate-deploy 角色、无 .env 泄漏均实测;web 镜像 容器实测路由(viewer 回退/admin 子路径/assets 与 embed immutable/WS 代理路径 502 语义)全通过。未起真实栈(无真实 DB,符合准备件边界)。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
# README-1Panel —— photo-live 生产部署指南(1Panel 单机双地域)
|
||||
|
||||
> P5-prep 产物(无凭证前置批):本指南只描述操作步骤与占位值,不含任何真实密钥。
|
||||
> 目标形态:**cn 服务器**(1Panel:MySQL/Redis/OpenResty + photo-live-cn 编排)
|
||||
> 与 **ov 服务器**(1Panel:MySQL/Redis/OpenResty + photo-live-ov 编排)。
|
||||
> 同步架构(已从代码核实):sync 独立进程**只跑 cn 侧**,双库直连 + 双 API 调用;
|
||||
> ov 侧 inbox(内容接收)与 emergency(紧急停用)内嵌在 api-ov 进程内。
|
||||
|
||||
| 产物 | 说明 |
|
||||
| --- | --- |
|
||||
| `docker/server.Dockerfile` | 单镜像 `photo-live-server` 多角色:api-cn / api-ov / worker / sync / migrate-deploy / seed-admin |
|
||||
| `docker/web.Dockerfile` | `photo-live-web`:nginx 承载 viewer(/)+admin(/admin/)+/v1 反代+静态长缓存 |
|
||||
| `docker-compose.cn.yml` / `docker-compose-ov.yml` | 两地域编排(本目录) |
|
||||
| `.env.production.example-cn` / `-ov` | 变量全量清单(仓库根,复制后填值) |
|
||||
| `RUNBOOK.md` | 发布/迁移/回滚/紧急停用运行手册 |
|
||||
|
||||
---
|
||||
|
||||
## 1. 镜像导入(两条路径任选)
|
||||
|
||||
**版本约定**:tag = `git短sha-日期`(如 `12059d9-20260921`),同一 tag 双镜像配套,
|
||||
回滚即换 tag(见 RUNBOOK.md)。
|
||||
|
||||
### 路径 A:本地构建 → tar 上传 → 1Panel 导入(无镜像仓库时)
|
||||
|
||||
```bash
|
||||
# 本地(仓库根)构建;tag 按上方约定替换
|
||||
docker build -f docker/server.Dockerfile -t photo-live-server:12059d9-20260921 .
|
||||
docker build -f docker/web.Dockerfile \
|
||||
--build-arg VITE_VIEWER_BASE=https://你的viewer域名 \
|
||||
--build-arg VITE_EMBED_ORIGIN=https://你的viewer域名 \
|
||||
-t photo-live-web:12059d9-20260921 .
|
||||
|
||||
docker save photo-live-server:12059d9-20260921 | gzip > photo-live-server.tar.gz
|
||||
docker save photo-live-web:12059d9-20260921 | gzip > photo-live-web.tar.gz
|
||||
# 上传两台服务器后,1Panel → 容器 → 镜像 → 导入(选择 tar.gz)
|
||||
```
|
||||
|
||||
> web 镜像的 `VITE_VIEWER_BASE`/`VITE_EMBED_ORIGIN` 是**构建期**变量(admin 分享卡
|
||||
> 与嵌入代码拼 URL 用);cn/ov 两地域各用各自域名构建一次。漏传只影响分享卡外链,
|
||||
> 不影响 API 路由(API 基址=同源 /v1,由运行时 `API_UPSTREAM` 决定)。
|
||||
|
||||
### 路径 B:推镜像仓库 → 服务器 pull(有仓库时)
|
||||
|
||||
1Panel → 容器 → 仓库 → 创建(阿里云 ACR 个人版即可)→ 之后编排文件里 image 直接写
|
||||
`registry.cn-hangzhou.aliyuncs.com/你的命名空间/photo-live-server:tag`,或在服务器
|
||||
`docker pull` 后 `docker tag` 成编排里用的名字。
|
||||
|
||||
## 2. MySQL 建库 / 授权(两台各执行对应段)
|
||||
|
||||
1Panel → 数据库 → MySQL(8.0+)→ 创建数据库。**库名/字符集**:
|
||||
|
||||
```sql
|
||||
-- cn 服务器(库名 photo_cn)
|
||||
CREATE DATABASE photo_cn CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin;
|
||||
CREATE USER 'photo'@'%' IDENTIFIED BY '强密码';
|
||||
GRANT ALL PRIVILEGES ON photo_cn.* TO 'photo'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- ov 服务器(库名 photo_ov)
|
||||
CREATE DATABASE photo_ov CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin;
|
||||
CREATE USER 'photo_ov'@'%' IDENTIFIED BY '强密码';
|
||||
GRANT ALL PRIVILEGES ON photo_ov.* TO 'photo_ov'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
- `utf8mb4_0900_bin`(大小写敏感)是账号/token/publicToken 语义的前提,需
|
||||
**MySQL ≥ 8.0.30**(决策 D12:先在两台 ECS 上 `SELECT VERSION();` 登记精确版本;
|
||||
若低于 8.0.30,改用 `utf8mb4_bin`(同样大小写敏感),并重跑语义相关验收)。
|
||||
- 授权 host:`'%'` 便于容器网段接入;生产更稳妥做法是限定网段
|
||||
(`'172.%'` 容器网 + cn 服务器出口 IP)。**ov 库必须额外放行 cn 服务器出口 IP
|
||||
的 3306**(sync 进程直连 ov 库),建议叠加 SSL 或隧道(P5 实测定案)。
|
||||
|
||||
## 3. Redis 连接
|
||||
|
||||
1Panel → 数据库 → Redis → 创建(默认库即可)。连接串二选一:
|
||||
|
||||
- **容器网络互连(推荐)**:photo-live 编排与 1Panel 的 Redis 同在
|
||||
`1panel-network`,host 直接写 Redis **容器名**(`docker ps` 查名,如
|
||||
`1Panel-redis-xxxx`),端口写容器内端口 6379。
|
||||
- **宿主机 IP 直连**:host 写宿主机内网 IP;1Panel 应用端口默认只绑 127.0.0.1,
|
||||
需在 1Panel 端口设置放开监听地址或改绑 0.0.0.0(注意防火墙)。
|
||||
|
||||
填入 env:cn `REDIS_URL_CN`;ov `REDIS_URL_OV`。
|
||||
|
||||
## 4. Compose 编排(1Panel → 容器 → 编排 → 创建编排)
|
||||
|
||||
1. 文件管理器在 1Panel 数据目录旁新建目录(示例 `/opt/photo-live/`),上传:
|
||||
- `docker-compose.cn.yml`(cn)/ `docker-compose-ov.yml`(ov)
|
||||
- 由仓库根 `.env.production.example-cn`/`-ov` 复制改名的
|
||||
`.env.production-cn`/`.env.production-ov`(**与 compose 同目录**,已填值)
|
||||
2. 1Panel → 容器 → 编排 → 创建编排 → 路径选择该目录(或直接粘贴 compose 内容,
|
||||
再把 env 文件放到 1Panel 显示的编排目录内)。
|
||||
3. 默认编排挂**外部网络 `1panel-network`**(1Panel 应用网络,容器名互通 MySQL/
|
||||
Redis)。若你的 1Panel 网络名不同(`docker network ls` 核对),改 compose 末段
|
||||
`name:`;若用宿主机 IP 连接,把 networks 整段换成 `photo-net: {}` 并在 env 里
|
||||
用 IP 形态的连接串。
|
||||
4. 启动前确认镜像 tag:默认 `photo-live-server:latest`/`photo-live-web:latest`;
|
||||
建议在 1Panel 编排的环境变量里固定 `SERVER_IMAGE`/`WEB_IMAGE` 为具体版本 tag。
|
||||
|
||||
## 5. OpenResty 网站 + 证书反代到 web 容器
|
||||
|
||||
1Panel → 网站 → 创建网站 → 反向代理:
|
||||
|
||||
- cn:主域名 `photo.example.cn`(viewer)→ 代理 `http://127.0.0.1:8088`;
|
||||
管理端 `admin.photo.example.cn` → 同一后端 `http://127.0.0.1:8088`(admin 走
|
||||
hash 路由 `/admin/` 路径,也可与 viewer 同域直接用 `photo.example.cn/admin/`)。
|
||||
- ov:`photo.example.com` → `http://127.0.0.1:8089`。
|
||||
- 证书:网站设置 → HTTPS → 申请/绑定证书,开启「强制 HTTPS」。
|
||||
- OpenResty 侧注意:
|
||||
- **不要重复缓存** `/v1/`(API 动态;图片 URL 本身是带签名的 OSS 直链,不经过
|
||||
这层);静态资源缓存已在 photo-live-web 容器内配置好。
|
||||
- WebSocket(`/v1/realtime`)透传:1Panel 反代默认透传 Upgrade 头;若自建
|
||||
OpenResty 配置,需保留 `proxy_set_header Upgrade/Connection`(参考
|
||||
`nginx.conf.template` 的 /v1/ 段)。
|
||||
- 若 web 端口改绑了非回环地址,注意防火墙只放行 OpenResty 出口。
|
||||
|
||||
## 6. 迁移执行(migrate-deploy 角色,一次性容器)
|
||||
|
||||
```bash
|
||||
# cn 服务器:迁移 cn 库(env 文件与 compose 同目录;--rm 用完即删)
|
||||
docker run --rm --env-file /opt/photo-live/.env.production-cn \
|
||||
--network 1panel-network \
|
||||
photo-live-server:12059d9-20260921 migrate-deploy cn
|
||||
|
||||
# ov 服务器:迁移 ov 库
|
||||
docker run --rm --env-file /opt/photo-live/.env.production-ov \
|
||||
--network 1panel-network \
|
||||
photo-live-server:12059d9-20260921 migrate-deploy ov
|
||||
|
||||
# 首次引导 admin 账号(cn;幂等,已存在则跳过)
|
||||
docker run --rm --env-file /opt/photo-live/.env.production-cn \
|
||||
--network 1panel-network \
|
||||
photo-live-server:12059d9-20260921 seed-admin
|
||||
```
|
||||
|
||||
`migrate-deploy` 支持区域参数 `cn | ov | all`(缺省 all——单机双库演练用;生产两台
|
||||
各跑各的)。Prisma migrate deploy 只向前应用未执行过的迁移,已在
|
||||
RUNBOOK.md 固化为发布步骤与回滚原则。
|
||||
|
||||
## 7. 首次部署顺序(cn 与 ov 并行各自的 1-2,汇合于 3-6)
|
||||
|
||||
1. **DB 就绪**:两台各建库/授权(§2)+ Redis(§3)。
|
||||
2. **镜像导入**:两台各自导入 server+web 镜像(§1)。
|
||||
3. **迁移**:cn `migrate-deploy cn` → ov `migrate-deploy ov`(§6)。
|
||||
4. **起栈**:ov 先 `docker-compose-ov.yml` up(api-ov + web-ov)→ cn
|
||||
`docker-compose.cn.yml` up(api-cn + worker + sync + web)。sync 依赖 ov API
|
||||
与 ov 库可达,故 cn 栈最后起。
|
||||
5. **域名/证书**:OpenResty 反代 + HTTPS(§5),DNS 解析两地域各自接入。
|
||||
6. **引导与演练**:cn `seed-admin`(§6)→ 管理端登录 → 建测试相册 →
|
||||
`scripts/prod-smoke.sh <cnBase> <ovBase> <账号> <密码>` 四点冒烟
|
||||
(健康/登录/上传/公开读,ov 未部署时 `--ov` 跳过 ov 段)→ 观察同步水位
|
||||
(sync 日志 `outbox batch pushed`)→ 清理测试数据(软删照片即可)。
|
||||
|
||||
日常发布/回滚见 `RUNBOOK.md`。
|
||||
@@ -0,0 +1,58 @@
|
||||
# infra/deploy/docker-compose-ov.yml —— 海外(ov)生产编排(P5-prep Task 1)。
|
||||
# 只跑两个容器:api-ov(ov 公开读/互动/WS + sync-inbox + emergency 通道,全部
|
||||
# 内嵌——核实自 services/api/src/app-ov.module.ts)与 web-ov(nginx 网关)。
|
||||
# 【无 sync 进程】:cn→ov 内容同步的发送器/对账/统计回传全在 cn 侧
|
||||
# (docker-compose.cn.yml 的 sync 服务),跨地域经公网连 ov 的 API + MySQL。
|
||||
#
|
||||
# 使用:同目录放 .env.production-ov(模板见仓库根 .env.production.example-ov);
|
||||
# 网络与 1Panel 复用说明同 docker-compose.cn.yml 头注。
|
||||
|
||||
name: photo-live-ov
|
||||
|
||||
x-logging: &default-logging
|
||||
driver: json-file
|
||||
options: { max-size: "10m", max-file: "3" }
|
||||
|
||||
services:
|
||||
api-ov:
|
||||
image: ${SERVER_IMAGE:-photo-live-server:latest}
|
||||
command: ["api-ov"]
|
||||
init: true
|
||||
env_file: .env.production-ov
|
||||
environment:
|
||||
PORT_OV: "8081" # main-ov.ts 读 PORT_OV;容器内固定
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fs", "http://127.0.0.1:8081/v1/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 20s
|
||||
logging: *default-logging
|
||||
networks: [photo-net]
|
||||
|
||||
web-ov:
|
||||
image: ${WEB_IMAGE:-photo-live-web:latest}
|
||||
init: true
|
||||
environment:
|
||||
API_UPSTREAM: http://api-ov:8081
|
||||
ports:
|
||||
# 同 cn:默认只绑回环供同机 OpenResty 反代(ov 侧主机端口用 8089 区分)。
|
||||
- "127.0.0.1:8089:80"
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
api-ov: { condition: service_healthy }
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fs", "http://127.0.0.1/"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
logging: *default-logging
|
||||
networks: [photo-net]
|
||||
|
||||
networks:
|
||||
photo-net:
|
||||
# 说明同 docker-compose.cn.yml(1Panel 网络名按实际调整;或改宿主机 IP 连接)。
|
||||
name: 1panel-network
|
||||
external: true
|
||||
@@ -0,0 +1,88 @@
|
||||
# infra/deploy/docker-compose.cn.yml —— 国内(cn)生产编排(P5-prep Task 1)。
|
||||
# 角色:api-cn(写路径 API)/ worker(sharp 变体流水线 + 发布事务 outbox)/
|
||||
# sync(outbox→ov 推送 + 对账 + 统计回传,双库直连)/ web(nginx 网关)。
|
||||
# 架构核实:sync 是独立进程跑在 cn 侧(services/sync/src/main.ts 双库连接);
|
||||
# ov 侧无任何 sync 进程(inbox 内嵌 api-ov,见 docker-compose-ov.yml)。
|
||||
#
|
||||
# 使用(1Panel 容器→编排→新建编排,或 docker compose -f 本文件 up -d):
|
||||
# 1. 同目录放 .env.production-cn(模板见仓库根 .env.production.example-cn)。
|
||||
# 2. 镜像已导入(README-1Panel.md §1);SERVER_IMAGE/WEB_IMAGE 可用环境变量
|
||||
# 覆盖 tag(回滚 = 指回旧 tag 后 up -d,见 RUNBOOK.md)。
|
||||
# 3. 网络默认挂外部 1panel-network 以便用容器名直连 1Panel 的 MySQL/Redis;
|
||||
# 若你的 1Panel 网络名不同,或打算用宿主机 IP + 端口连接,把下方 networks
|
||||
# 整段换成普通桥接网络(photo-net: {})并同步改 .env 里的连接串 host。
|
||||
#
|
||||
# 首次部署顺序(迁移先于 API):README-1Panel.md §7。
|
||||
|
||||
name: photo-live-cn
|
||||
|
||||
x-server-image: &server-image ${SERVER_IMAGE:-photo-live-server:latest}
|
||||
x-logging: &default-logging
|
||||
driver: json-file
|
||||
options: { max-size: "10m", max-file: "3" }
|
||||
|
||||
services:
|
||||
api-cn:
|
||||
image: *server-image
|
||||
command: ["api-cn"]
|
||||
init: true
|
||||
env_file: .env.production-cn
|
||||
environment:
|
||||
PORT: "8080" # 容器内固定;对外经 web 反代或 OpenResty
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fs", "http://127.0.0.1:8080/v1/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 20s
|
||||
logging: *default-logging
|
||||
networks: [photo-net]
|
||||
|
||||
worker:
|
||||
image: *server-image
|
||||
command: ["worker"]
|
||||
init: true
|
||||
env_file: .env.production-cn
|
||||
# 无 HTTP 端口:健康面由 restart 策略 + 日志监控承担(RUNBOOK.md 故障速查)。
|
||||
restart: unless-stopped
|
||||
logging: *default-logging
|
||||
networks: [photo-net]
|
||||
|
||||
sync:
|
||||
image: *server-image
|
||||
command: ["sync"]
|
||||
init: true
|
||||
env_file: .env.production-cn
|
||||
# 需要额外可达:OV_API_URL(公网域名)与 DATABASE_URL_OV(ov MySQL,跨地域)。
|
||||
restart: unless-stopped
|
||||
logging: *default-logging
|
||||
networks: [photo-net]
|
||||
|
||||
web:
|
||||
image: ${WEB_IMAGE:-photo-live-web:latest}
|
||||
init: true
|
||||
environment:
|
||||
API_UPSTREAM: http://api-cn:8080 # /v1 反代目标(含 WS /v1/realtime)
|
||||
ports:
|
||||
# 只绑本机回环:1Panel OpenResty(同宿主机)反代到 127.0.0.1:8088;
|
||||
# OpenResty 在其它机器时改为 "8088:80" 并配防火墙白名单。
|
||||
- "127.0.0.1:8088:80"
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
api-cn: { condition: service_healthy }
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fs", "http://127.0.0.1/"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
logging: *default-logging
|
||||
networks: [photo-net]
|
||||
|
||||
networks:
|
||||
photo-net:
|
||||
# 复用 1Panel 应用网络(其名通常为 1panel-network):容器名互通 MySQL/Redis。
|
||||
# 若网络名不同:name 改实际名。若走宿主机 IP 连接:整段替换为 `photo-net: {}`。
|
||||
name: 1panel-network
|
||||
external: true
|
||||
@@ -0,0 +1,78 @@
|
||||
# infra/deploy/nginx.conf.template —— photo-live-web nginx 配置模板。
|
||||
# 官方 nginx 镜像启动脚本对 /etc/nginx/templates/*.template 执行 envsubst 并
|
||||
# 输出到 /etc/nginx/conf.d/。模板变量仅 ${API_UPSTREAM}(compose environment
|
||||
# 注入);envsubst 只替换已定义的环境变量,$uri/$host 等 nginx 变量不受影响。
|
||||
#
|
||||
# 路由布局(viewer history 路由 / admin hash 路由,路由模式核实自
|
||||
# apps/viewer/src/router/index.ts createWebHistory 与 apps/admin/src/router/
|
||||
# index.ts createWebHashHistory):
|
||||
# / viewer SPA(try_files 回退 index.html)
|
||||
# /admin/ admin 静态(hash 路由无需 history 回退;try_files 仅兜底)
|
||||
# /assets/ viewer vite 内容寻址产物 → immutable 一年
|
||||
# /admin/assets/ admin vite 内容寻址产物 → immutable 一年
|
||||
# /embed/v1/ 嵌入 loader.js(版本目录即内容版本)→ immutable 一年;
|
||||
# /embed/:slotToken 是 viewer SPA 路由,走 / 的回退,不被本条误捕
|
||||
# /v1/ 反代 API_UPSTREAM(HTTP + WS /v1/realtime 升级透传)
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html/viewer;
|
||||
index index.html;
|
||||
|
||||
gzip on;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/css application/javascript application/json image/svg+xml;
|
||||
|
||||
# /v1 → API 容器(viewer/admin 前端均为同源相对路径请求)。
|
||||
location /v1/ {
|
||||
proxy_pass ${API_UPSTREAM};
|
||||
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;
|
||||
# WS(/v1/realtime)升级;普通 HTTP 请求不受影响。
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_read_timeout 75s;
|
||||
proxy_send_timeout 75s;
|
||||
}
|
||||
|
||||
# admin(hash 路由:静态直达即工作;try_files 兜底异常直链)。
|
||||
location ^~ /admin/ {
|
||||
alias /usr/share/nginx/html/admin/;
|
||||
try_files $uri $uri/ /admin/index.html;
|
||||
}
|
||||
# admin 内容寻址资源:immutable(注意 alias 指到 assets/ 本身:location 前缀
|
||||
# /admin/assets/ 被剥去后拼到 alias 末尾,多剥一段就 404——实测坑位)。
|
||||
location ^~ /admin/assets/ {
|
||||
alias /usr/share/nginx/html/admin/assets/;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# 嵌入 loader(版本化路径 /embed/v1/loader.js,apps/viewer/public 静态携带)。
|
||||
location ^~ /embed/v1/ {
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# viewer 内容寻址资源:immutable。
|
||||
location ^~ /assets/ {
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# viewer SPA history 路由回退。
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user