Files
IOT_SIM/deploy/README.md
T
xuyueandClaude Opus 5.5 697f31e9ce 部署:bubblewrap 沙箱、编译检查、访问口令、Docker Compose
- 学生程序每次运行放进 bubblewrap:断网,只读挂载系统文件、运行时和自己的工程目录,
  看不到其他进程和服务器环境变量;限制堆内存 128 MB、CPU 时间 120 秒、运行 60 分钟,
  nice 10,全站同时运行上限 150;启动时自检沙箱,不可用时拒绝运行
- 编译检查(SIM001):网络、反射、启动进程、调用本机代码、加载程序集、dynamic 给出中文报错
- 访问口令:cookie 保存口令哈希,按真实 IP 限制输错次数;前端口令页
- 服务端配置集中到 config.ts,可用环境变量覆盖;Bun 直接提供打包好的网页
- Dockerfile(多阶段,服务端打包成单文件)、compose.yaml(Caddy 只收 HTTP,接入 NPM 的
  npm_proxy 网络)、deploy/deploy.sh(本机构建后经 ssh 传到服务器)和部署说明
- 测试:沙箱隔离、内存上限、CPU 时间上限、编译检查

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 15:40:09 +08:00

78 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 部署
服务器上的结构:
```
学生浏览器 ──HTTPS──▶ Nginx Proxy Manager(443) ──npm_proxy 网络──▶ caddy(iot-sim:80) ──▶ app(Bun + .NET + bubblewrap)
```
- **app**:Bun 服务端、打包好的网页、C# 编译服务。学生程序每次运行都放进 bubblewrap 沙箱:断网,看不到服务器文件和其他进程,工程目录只读,限制内存(128 MB)、CPU 时间(120 秒)和运行时长(60 分钟)。
- **caddy**:只收 HTTP,转发给 app,压缩网页;从 NPM 转发来的 `X-Forwarded-For` 里取学生的真实 IP。
- 不映射宿主机端口,NPM 通过外部网络 `npm_proxy` 访问 `iot-sim:80`。
## 服务器要求
- Linux,Docker 和 Docker Compose v2,已有外部网络 `npm_proxy`(NPM 所在的网络)。
- 2 核 8G 足够两个班同时使用(实测 100 个程序同时运行约 1.1 GB)。
- 沙箱需要宿主机允许非特权用户命名空间。**Debian 12(本平台的服务器)默认允许**,不用设置,可用 `sysctl kernel.unprivileged_userns_clone` 确认输出为 1。
- **Ubuntu 23.10 及以上**默认禁止,沙箱会起不来,需要放开:
```bash
echo 'kernel.apparmor_restrict_unprivileged_userns=0' | sudo tee /etc/sysctl.d/60-userns.conf
sudo sysctl --system
```
其他发行版一般不需要。服务器启动时会自检沙箱,不通过会在日志里打印原因,并拒绝运行学生代码(不会在无隔离的情况下运行)。
## 第一次部署
1. 在服务器上准备目录和口令:
```bash
mkdir -p ~/iot-sim && cd ~/iot-sim
# 部署脚本会上传 .env.example;也可以直接新建 .env:
echo 'ACCESS_PASSWORD=换成你的口令' > .env
chmod 600 .env
```
2. 在本机(开发机)执行:
```bash
deploy/deploy.sh 用户@服务器
```
脚本在本机构建镜像,通过 ssh 传到服务器并启动。日志最后应看到"C# 编译服务已就绪",且没有"沙箱无法启动"。
3. 在 Nginx Proxy Manager 里添加 Proxy Host:
- Domain Names:已备案的域名
- Scheme:`http`,Forward Hostname / IP:`iot-sim`,Forward Port:`80`
- **打开 Websockets Support**(运行程序靠 WebSocket,不打开会一直连不上)
- SSL:申请证书,打开 Force SSL
4. 浏览器打开域名,输入口令进入。
## 日常操作
在服务器的 `~/iot-sim` 目录下:
| 做什么 | 命令 |
|---|---|
| 更新到新版本 | 在本机再执行一次 `deploy/deploy.sh 用户@服务器` |
| 换口令 | 修改 `.env` 后 `docker compose up -d`(所有人要重新输入口令) |
| 看日志 | `docker compose logs -f app` |
| 看资源占用 | `docker stats` |
| 重启 / 停止 | `docker compose restart` / `docker compose down` |
## 可调参数
写在 `.env` 里,改完 `docker compose up -d` 生效。
| 变量 | 默认 | 说明 |
|---|---|---|
| `ACCESS_PASSWORD` | (必填) | 访问口令 |
| `APP_MEM_LIMIT` | `4g` | 整个平台的内存上限 |
| `SIM_MAX_RUNS` | `150` | 全站同时运行的学生程序上限,超过时提示"服务器繁忙" |
| `SIM_HEAP_LIMIT_MB` | `128` | 每个学生程序的内存上限 |
| `SIM_CPU_LIMIT_SECONDS` | `120` | 每次运行累计 CPU 时间上限(防死循环) |
| `SIM_MAX_RUN_MINUTES` | `60` | 每次运行最长时间 |