GeekHub

URDF Studio 私有化部署教程

URDF Studio 是一个运行在浏览器中的机器人建模环境:处理机器人拓扑(link/joint)、视觉/碰撞几何体、硬件参数与多文件工作区,并完成多格式导出交付,不需要每次操作都直接手写 XML。

核心能力:

  • 拓扑编辑:通过 link/joint 工具构建与编辑运动学树,3D 画布实时预览;
  • 几何与碰撞:编辑 visual mesh、collision mesh,测量与碰撞优化;
  • 硬件配置:配置电机型号、传动比、阻尼、摩擦与硬件元数据;
  • 多机器人组装:将多个机器人装配到同一工作区,通过 bridge joint 连接;
  • 多格式导入/导出:支持 URDFMJCF(MuJoCo)、USDSDFXacro,以及 CSV/BOM、PDF 报告、ZIP 与 .usp 项目归档;
  • AI 助手(可选):自然语言生成机器人结构、自动化检查与代码审阅,需自备 OpenAI API key。

技术栈为 React 19 + TypeScript + Vite + Three.js,纯前端 SPA,无后端、无数据库、无 GPU 依赖——私有化部署只需要一台能跑 Docker 的机器。项目地址:OpenLegged/URDF-Studio(Apache 2.0)。

本教程讲两件事:怎么把源码构建成镜像跑起来,以及一个容易忽略的 nginx 配置(不配会导致 USD 功能在浏览器里失效)。


一、架构总览

浏览器 ──► Docker 容器 urdf-studio(nginx,宿主机端口 3890,容器内 80)
              │
              ▼
           静态文件 dist/(宿主机本地构建产物)

没有后端。nginx 只做三件事:提供静态文件、SPA 路由回退、设置跨域隔离响应头。所有数据(机器人模型等)都存在浏览器本地,不进服务器。

职责 组件
构建层 源码 → 静态文件 Node 20 + npm run build
服务层 静态文件 + SPA 路由 + 安全头 nginx(Docker 容器)

部署后的访问方式:

  • 部署机本机:http://localhost:3890/
  • 局域网设备:http://<部署机IP>:3890/
  • 如需公网 HTTPS 访问(USD 功能需要,见第三节),可再前置一层反向代理,本文不展开。

二、本地构建

2.1 为什么不在容器里构建

一个自然的想法是写个两阶段 Dockerfile:

FROM node:20-alpine AS build
WORKDIR /app
COPY . .
RUN npm ci && npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html

这条路线不推荐

  1. npm install 要拉几百个包,容器内网络不稳定时构建经常卡死或失败;
  2. 每次改代码都重新拉基础镜像、重新装依赖,迭代慢;
  3. 构建环境的网络问题(代理、镜像源)在容器里更难排查。

实际做法:宿主机上构建,Dockerfile 只负责把 dist 丢进 nginx。构建是一次性动作(代码不变就不用重建),网络问题也隔离在宿主机侧。

2.2 构建步骤

# 1. 拉取源码
git clone https://github.com/OpenLegged/URDF-Studio.git
cd URDF-Studio

# 2. 安装依赖(国内网络建议走 npmmirror)
npm install --registry=https://registry.npmmirror.com

# 3. 构建
npm run build

产物在 dist/ 目录。

Node 版本要求 20+。
如果 npm install 慢或失败,可全局设置镜像源 npm config set registry https://registry.npmmirror.com,或配代理 npm install --proxy http://127.0.0.1:7890(按实际代理端口)。


三、容器化:nginx 镜像

3.1 Dockerfile

# 单阶段 — 只挂载已有 dist
FROM nginx:alpine

COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
COPY nginx.d/ /etc/nginx/conf.d/

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

基础镜像 nginx:alpine 拉不到时,换任意可达镜像源/本地 registry 的等价镜像即可。

3.2 nginx.conf(主配置)——关键部分

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # ⚠️ 关键:COOP/COEP 跨域隔离头
    add_header Cross-Origin-Opener-Policy same-origin;
    add_header Cross-Origin-Embedder-Policy require-corp;
    add_header Cross-Origin-Resource-Policy same-site;

    include /etc/nginx/conf.d/*.conf;
}

为什么必须有这三行:

URDF Studio 的 USD 场景功能依赖 Web 的 SharedArrayBuffer(多线程 3D 渲染)。浏览器规范规定 SharedArrayBuffer 只在跨域隔离(cross-origin isolated)的页面上可用,必须同时满足:

  • 页面通过 HTTPS(或 localhost)访问;
  • 响应头包含 Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp

缺任何一条,USD 相关功能在浏览器直接失效,页面通常会报 “SharedArrayBuffer is only available for cross-origin isolated contexts”。这三行不是可选优化,是功能前提。

Cross-Origin-Resource-Policy: same-site 是配套资源头,防止子资源被跨站嵌入。

3.3 nginx.d/default.conf(站点配置)

server {
    listen 80;
    server_name _;

    root /usr/share/nginx/html;
    index index.html;

    location / {
        # SPA 路由回退:未命中的路径都返回 index.html
        try_files $uri $uri/ /index.html;
    }
}

try_files ... /index.html 是 SPA 部署的标准写法,保证刷新 /settings 等深层路由不会 404。

3.4 构建并运行

docker build -t urdf-studio:latest .
docker run -d 
    --name urdf-studio 
    --restart unless-stopped 
    -p 3890:80 
    urdf-studio:latest

3.5 验证

# 状态码
curl -s -o /dev/null -w "%{http_code}n" http://localhost:3890/
# 期望 200

# COOP/COEP 头是否下发
curl -sI http://localhost:3890/ | grep -i "cross-origin"
# 期望看到三行 Cross-Origin-* 头

浏览器打开 http://localhost:3890/,DevTools → Application 里看 crossOriginIsolated

  • localhost 访问:应为 true,SharedArrayBuffer 可用,USD 功能完整(浏览器豁免 localhost);
  • 局域网 http://<IP>:3890 访问:应为 false(HTTP + 非 localhost),USD 功能不可用——这是浏览器规范限制,不是部署错误。需要完整 USD 功能就走 HTTPS 入口(前置反向代理 + 证书)。

四、踩坑记录

# 现象 原因 处理
1 两阶段 Dockerfile 构建卡死/失败 容器内 npm install 网络不稳定 宿主机本地构建 + 单阶段镜像挂载 dist
2 USD 功能报 SharedArrayBuffer 错误 缺 COOP/COEP 响应头,或页面非 HTTPS/localhost nginx 加三行跨域隔离头;公网访问必须 HTTPS
3 局域网 HTTP 访问 USD 不可用 浏览器只豁免 HTTPS 和 localhost 预期行为;要完整功能用 HTTPS 入口
4 深层路由(如 /settings)刷新 404 nginx 缺 SPA 回退 try_files $uri $uri/ /index.html;
5 国内机器 npm install 极慢 默认 registry 是 npmjs.org --registry=https://registry.npmmirror.com 或配代理
6 拉不到 nginx:alpine 基础镜像 网络问题 换镜像源或本地 registry 等价镜像

五、运维要点

  • 镜像更新:代码改动 → 本地 npm run builddocker builddocker rm urdf-studio 后重新 docker run。镜像是纯静态、无状态、无数据卷,重建零成本。
  • 进程守护--restart unless-stopped,宕机自动拉起。
  • 数据安全:用户数据存浏览器本地(localStorage / IndexedDB),服务器不接触任何用户数据。如需公网访问,建议用 Nginx/Caddy 等反向代理前置 + Let’s Encrypt 签发 TLS 证书。
  • 资源占用:nginx 容器内存占用 ~10MB 量级。部署机唯一硬性要求是 Docker + 构建时的 Node 20 环境(构建完 Node 可以卸掉)。

附:文件清单

URDF-Studio/
├── Dockerfile          # 单阶段:nginx:alpine + dist + 配置
├── nginx.conf          # 主配置:COOP/COEP 跨域隔离头
├── nginx.d/
│   └── default.conf    # 站点配置:SPA 回退
└── dist/               # npm run build 产物(不入库)

附:在线示例与使用方法

作者部署的在线示例:https://urdf.gooney.fun/(按本教程部署,HTTPS 入口,USD 功能完整可用)。

使用方式(浏览器端操作,不涉及服务器):

  1. 导入:打开首页后通过 File 菜单/拖拽导入 URDF、MJCF、USD、Xacro、SDF 文件,也支持整个文件夹、ZIP 包或 .usp 项目归档(包含 mesh 等多文件的完整工程)。
  2. 编辑:左侧文件树/结构树选择 link 或 joint,在 3D 画布中直接变换(transform controls 拖拽),右侧属性面板修改几何尺寸、质量、惯性、电机与硬件参数;顶部标签页在拓扑编辑、几何/碰撞/测量、硬件配置之间切换。
  3. 碰撞:在碰撞编辑模式下调整 collision mesh,检查 link 间的干涉,应用碰撞优化策略。
  4. 组装:导入多个机器人后通过 bridge joint 把它们装配进同一工作区,做组件级管理。
  5. 导出:选择目标格式(URDF / MJCF / USD / SDF / Xacro / CSV·BOM / PDF / ZIP / .usp 归档)导出;多文件工程用 ZIP 或 .usp 归档,保证 mesh 等资源不丢。
  6. AI 助手(可选):在设置里填入 OpenAI API key 后,可用自然语言生成机器人结构、跑自动化检查并导出 PDF/CSV 报告。
  7. 数据保存:所有数据存在浏览器本地(localStorage/IndexedDB),刷新页面不丢,但换浏览器或清浏览器数据会丢失未导出的工程——重要成果请及时导出归档。

USD 功能(.usd 预览/导出)仅在 HTTPS 或 localhost 入口可用(SharedArrayBuffer 限制);用 HTTP 直连 IP 访问时该部分不可用,属预期行为。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注