域名与反向代理
使用域名(特别是 HTTPS)而非 IP 地址来服务工作室时的配置。 本章必须按顺序全部完成才能生效。 即使漏掉一项,也会出现看似不同的症状,如“预览空白”、“构建聊天连接错误”、“部署应用数据返回 401”等。
域名只有一个
预览和部署应用都在与工作室相同域名的 /container/ 下提供服务。
https://studio.company.com/ → 스튜디오 UI + API
https://studio.company.com/container/… → 프리뷰 · 배포앱
所需的是 1 条 DNS 记录、1 张证书、1 个 vhost。
我们不将应用分离到独立主机。由于预览和部署地址都是相对路径,在仅开放 80/443 的反向代理配置中可以直接工作。
预览和部署应用是由聊天生成的代码,即不可信内容。它们在与工作室相同的源站上运行——这意味着放弃了通过分离源站获得的隔离。这是为了将域名缩减为一个而接受的权衡。
因此,请不要将应用创建权限授予不可信用户。 此配置的前提是仅将构建者角色授予内部运维人员。
准备事项清单
- DNS A 记录 1 条
- 该主机名的 TLS 证书
- 反向代理能访问工作室盒子的 :80
- 在工作室盒子防火墙上允许 代理 → :80
应用监听器 (:5171) 由工作室盒子内的 web nginx 将 /container/ · /apps/ · /preview/ 转发过去,因此无需对外暴露。 只有在不使用反向代理而直接通过端口访问的安装中,才需要开放防火墙。
1. 向代理添加 vhost
外部代理只需将所有请求转发到工作室盒子的 :80 即可。/container/
/apps/ · /preview/ 分支已由盒子内的 web nginx 处理。
必须包含的 4 项
漏掉时出现的症状各不相同,难以查找原因,因此建议直接复制以下示例使用。
| 设置 | 漏掉时出现的症状 |
|---|---|
proxy_set_header Host $http_host | 路由和链接生成会错乱 |
Upgrade / Connection 请求头 | 预览实时更新 (HMR) 的 WebSocket 断开,代码修改无法反映到画面 |
proxy_read_timeout 3600s | 构建聊天显示“连接错误: network error” —— 当代理因执行工具而沉默数十秒时,默认的 60 秒超时会断开流 |
proxy_buffering off | 流式响应积压在缓冲区,回答会延迟成块出现 |
构建聊天和问答通过 SSE 实时传输。由于服务器每 25 秒发送一次心跳,代理超时只需比这更长即可,但 3600s 是经实际运营验证的值。
nginx 配置示例
server {
listen 80;
server_name studio.company.com;
location / {
proxy_pass http://<studio-host>:80;
proxy_http_version 1.1;
proxy_set_header Host $http_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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s; # 에이전트 SSE(빌드 채팅) — 필수
proxy_buffering off; # 스트리밍 즉시 전달 — 필수
client_max_body_size 64M; # 사진·도면 첨부
}
}
HTTPS 可通过 certbot 等签发 —— 只需让 listen 443 ssl 块继承上述配置即可。
如果将 vhost 文件直接挂载到打包的 web nginx 容器的 conf.d,请确保文件名以 zz- 开头。因为 nginx 将按字母顺序将第一个 server 块作为默认服务器,如果名称排在前,所有不匹配的请求都会流向错误的地方,导致整个工作室崩溃(实际发生过的事故)。
2. 重新登录(必需)
完成域名配置后,所有用户必须注销一次后重新登录。
登录 Cookie 是签发时主机的专属。通过 IP 访问并登录的会话在切换到域名后不会传递,数据请求会以 401 失败。
3. 验证
| 验证项 | 方法 |
|---|---|
| 工作室能打开 | 访问 https://studio.company.com → 登录 |
| 预览能显示 | 打开项目 → 预览画面显示,控制台无 Mixed Content |
| 应用路径已打通 | 访问 https://studio.company.com/container/ → 显示 404/应用列表即正常(已连接) |
| 实时更新 | 在聊天中修改一句话 → 预览自动更新 |
| 长时间构建 | 构建聊天运行 1 分钟以上 → 无“连接错误”完成 |
| 部署应用数据 | 打开已部署的应用 → 显示真实数据(无 401) |
注意事项
配置域名后,请仅通过域名访问。 使用 IP 访问的用户 Cookie 不同,部署应用数据会返回 401。
- WebSocket 默认支持,无需额外配置。
- 免费通用证书仅覆盖一级子域名(
studio.company.com✅,apps.studio.company.com❌)。
由于会在聊天中附加现场照片和图纸,请设置 client_max_body_size 64M。
如果遗漏,大图片上传会因 413 失败。
不通过反向代理,仅附加 HTTPS
如果没有单独的代理服务器,而要在工作室盒子上直接终止 TLS,请使用运维包中的 TLS 覆盖层。
cd /opt/kopens/plantpulse-studio-docker
cp tls/nginx-tls.conf.example tls/nginx-tls.conf # server_name 등 수정
# tls/cert.pem, tls/key.pem 배치(사내 CA 또는 공인 인증서)
docker compose -f docker-compose.yml -f docker-compose.tls.yml up -d
tls/nginx-tls.conf.example 中没有 /container/ 块,且注释尚未移除的
APPS_ORIGIN 和单独的端口 (5443) 仍被指引。如果直接使用,预览和部署应用地址
(/container/…)会返回 404。
目前,请在副本(tls/nginx-tls.conf)中直接添加 /container/ 块——使用上方
nginx 配置示例中的 4 种请求头,并移除前缀后转发给应用监听器即可。请勿添加 APPS_ORIGIN 行(不会被读取)。
症状 → 原因快速对照
这些是域名部署中常见的实际情况。更广泛的内容参见 故障排除。
| 症状 | 原因 | 措施 |
|---|---|---|
预览和部署应用空白,控制台显示 Mixed Content | 工作室使用 HTTPS,但应用资源以 HTTP 请求 | 在代理中添加 X-Forwarded-Proto $scheme 后全部改为 HTTPS |
| 部署应用真实数据返回 401 | 配置域名前已登录的会话 | 注销后重新登录一次 |
| 构建聊天耗时较长时显示“连接错误: network error” | 代理无数据传输超时(默认 60 秒) | proxy_read_timeout 3600s |
| 代码修改不反映到预览 | HMR WebSocket 未升级 | 添加 Upgrade / Connection 请求头 |
| 回答延迟成块出现 | proxy_buffering 已开启(默认值) | proxy_buffering off |
| 任何域名都流向错误的地方 | web nginx conf.d 加载顺序(首个 server 为默认服务器) | 将 vhost 文件名以 zz- 开头 |
/container/… 返回 404 | TLS 覆盖层副本中缺少 /container/ 块 | 参阅上方警告 |
| 直接通过端口使用的安装中应用无法显示 | 防火墙阻止了 5171 | 开放防火墙后通过 curl -I http://<host>:5171/ 验证 |