gl0bal01/devbox
GitHub: gl0bal01/devbox
一个基于Tailscale和Docker的集成工作站,为开发、渗透测试和AI实验提供安全、可复现的环境。
Stars: 0 | Forks: 0
# DevBox v1.0.0
面向 Ubuntu 24.04 + Docker 的 Tailscale 优先开发/渗透测试/人工智能工作站。
**核心亮点**
- **运行时契约** — `scripts/lib/devbox-contract.sh` 是安装布局、服务标识、容器名称、Traefik 主机名、命名卷、备份目标和固定的 Alpine 备份镜像的唯一真实来源。`setup.sh` 安装契约;辅助脚本引用它;Bats 测试固定其形态。
- **仅 Tailscale 的 HTTP 与(可选)HTTPS** — 两种模式均不绑定 `0.0.0.0` 公共端口。HTTPS 使用可选的 Compose 叠加层 + OVH DNS-01 证书。参见 [ARCHITECTURE.md](ARCHITECTURE.md)。
- **每次安装独立的 Ollama 基本身份验证凭证** — 由 `setup.sh` 生成随机 32 字符密码,明文存储在 `~/docker/.secrets/ollama-auth.txt`(权限 0600),可通过 `rotate-ollama-auth.sh` 轮换。Open WebUI 使用内部 Compose DNS 进行通信,无需传递身份验证。
- **每个服务提交镜像摘要锁定文件**。Setup.sh 通过契约生成 Compose 链 (`docker-compose.yml[:docker-compose.https.yml][:docker-compose.lock.yml]`)。CI 通过 `update-images.sh --check` 进行把关。
- **已验证下载** — 每个 `curl|sh` 命令都通过 `fetch_and_verify` 路由执行,其 SHA256 在 `scripts/lib/download-manifest.sh` 中固定。紧急覆盖:`DEVBOX_ALLOW_UNVERIFIED=1`。
- **已签名的每周发布 tarball** — 采用无密钥 cosign + CycloneDX SBOM + SLSA Build L3 来源证明。对分支友好的 CI(条件性 Docker Hub 登录)。Alpine 摘要自动 PR(永不自动合并到 main)。
- **Systemd 集成** — `devbox.service`(oneshot + RemainAfterExit)和每日 `devbox-backup.timer`,均从契约值渲染生成。通过 `make install-systemd` 安装。
- **操作者 Makefile** — `help|doctor|test|lint|compose-check|start|stop|status|backup|security-check|rotate-ollama-auth|install-systemd|uninstall-systemd`。
- **防欺骗碰撞保护** — `setup.sh` 拒绝安装到非 devbox 的 `~/docker/` 目录,除非契约和标记文件都存在(就地升级)。
- **诚实的权限模型** — `dev` 用户属于 `docker` 组(对套接字访问具有等同于 root 的权限)。安全边界 = Tailscale ACL + SSH 密钥认证 + UFW 默认拒绝策略。参见 [docs/security.md](docs/security.md)。
- **35 个契约 bats 测试 + 55 个单元 bats 测试** 通过 `.github/workflows/pr-validate.yml` 守护每个 PR。
## 目录
- [概述](#overview)
- [架构图](#architecture-diagram)
- [要求](#requirements)
- [快速开始](#quick-start)
- [配置](#configuration)
- [安装后](#post-installation)
- [可复现性](#reproducibility)
- [操作者命令](#operator-commands)
- [渗透测试工作流](#penetration-testing-workflow)
- [安全模型](#security-model)
- [故障排除](#troubleshooting)
- [目录结构](#directory-structure)
- [文档索引](#documentation-index)
- [许可证](#license)
## 概述
DevBox 为 Ubuntu 24.04 预配置了一个加固且可复现的环境:Traefik
在 docker-socket-proxy 后方,用于本地 LLM 推理的 Ollama + Open WebUI,以及
用于渗透测试工作的可选 Exegol。每个服务都绑定到 Tailscale IP
— 除了自定义端口的 SSH 外,没有公共监听器。
支持两种访问路径:
- **路径 A — 仅 Tailscale 的 HTTP(默认)。** 端口 80 绑定到 Tailscale
IP。无需域名或证书。通过 WireGuard 的 HTTP 已经加密。
- **路径 B — 仅 Tailscale 的 HTTPS(可选)。** 端口 443 也绑定到
Tailscale IP(没有 `0.0.0.0` 监听器)。通过 OVH DNS-01 获取 Let's Encrypt 通配符证书。需要 `ENABLE_HTTPS=true`、`DEVBOX_DOMAIN` 以及
包含 OVH API 凭证的 `~/.config/devbox/ovh.env`。证书是公开签发的;监听器仅通过 Tailscale 可达。
## 架构图
```
Path A (default) Path B (opt-in)
──────────────── ───────────────
[Your Devices] ──Tailscale──> [Traefik :80] [Your Devices] ──Tailscale──> [Traefik :443]
| |
(Tailscale IP) | (Tailscale IP, TLS) |
v v
+---------------------------[VPS]-------------------------------------------+
| |
| [Tailscale] <──> [Your Devices] (no public binding in either path) |
| | |
| v |
| [Traefik] ──────+──── [Open WebUI] ai.internal / ai.DOMAIN |
| | | |
| | +──── [Ollama API] ollama.internal (basicAuth) |
| | | |
| | +──── [Traefik Dashboard] traefik.internal (basicAuth) |
| | |
| +──> [Docker Socket Proxy] ──> /var/run/docker.sock |
| (internal network, read-only API subset) |
| |
| [Exegol Container] <──> [HTB/THM VPN] (optional, upstream exegol CLI) |
| (noVNC bound via UFW to tailscale0 only) |
| |
+---------------------------------------------------------------------------+
```
关于关键设计决策(信任模型、安装布局、契约、
HTTPS 叠加层、锁定文件工作流、systemd 集成、快照恢复等),
请参见 [ARCHITECTURE.md](ARCHITECTURE.md)。
## 要求
- Ubuntu 24.04 LTS。
- 预安装 Docker + Docker Compose 插件(v2.22+)。
- 最低 4 GB 内存;运行较大模型的 Ollama 推荐 24 GB+。
- 初始安装运行需要 root 访问权限。
- 用于身份验证的 SSH 公钥。
## 快速开始
```
git clone https://github.com/gl0bal01/devbox.git
cd devbox
# 可选:通过 env 覆盖默认值
export DEVBOX_USER=dev
export DEVBOX_SSH_PORT=5522
export SSH_PUBLIC_KEY="$(cat ~/.ssh/id_ed25519.pub)"
# 可选:HTTPS 模式 — 首先创建 OVH 凭证
install -d -m 0700 ~/.config/devbox
cat > ~/.config/devbox/ovh.env <
```
使用 `~/docker/rotate-ollama-auth.sh` 轮换。Open WebUI 不受影响 —
它通过内部 Compose 网络 (`http://ollama:11434`,无需身份验证) 与 Ollama 通信。
### 6. 可选 — 安装 AI 编码工具
```
~/docker/install-ai-dev-stack.sh # interactive menu
~/docker/install-ai-dev-stack.sh --all # install all
~/docker/install-ai-dev-stack.sh --status
~/docker/install-ai-dev-stack.sh --update
```
附带的工具:Claude Code, OpenCode, Goose, LLM, Fabric。
### 7. 可选 — 启用 systemd
```
sudo make install-systemd
# systemctl 启用:devbox.service + devbox-backup.timer(非自动启动)
sudo systemctl start devbox.service
sudo systemctl list-timers devbox-backup.timer
```
`devbox.service` 是 `Type=oneshot RemainAfterExit=yes` — 它在启动时调用
`start-all.sh`,在关闭时调用 `stop-all.sh`。每日备份定时器运行 `backup.sh`,配置了 `Persistent=true RandomizedDelaySec=1800`。
### 8. 验证安全性
```
~/docker/security-check.sh
```
## 可复现性
[docs/updating.md](docs/updating.md) 中记录了三种安装模式:
| 模式 | 方式 | 已签名? | 已冒烟测试? | 推荐用于 |
|---|---|---|---|---|
| `latest` | `git pull origin main` | 否 | 否 | 仅开发/贡献 |
| `weekly-YYYYMMDD` | `gh release download weekly-...` + cosign 验证 | **是** | **是** | **生产环境** |
| `@sha256:` | 通过 SHA256 固定发布 tarball | 是 | 是 | 最高级别谨慎 |
`.github/workflows/weekly-rebuild.yml` 中的每周任务构建一个确定性的
`devbox.tar`,使用无密钥 cosign(GitHub OIDC + Sigstore Rekor)签名,附加
CycloneDX SBOM + SLSA Build L3 来源证明,并通过
`gh release create` 发布。一个独立的 `alpine-digest-check` 任务在 Alpine
摘要漂移时提交 PR — 永不自动合并。
### 验证每周发布
```
gh release download weekly-20260420 \
-p devbox.tar -p devbox.tar.sha256 \
-p devbox.tar.sig -p devbox.tar.pem
sha256sum -c devbox.tar.sha256
cosign verify-blob devbox.tar \
--signature devbox.tar.sig \
--certificate devbox.tar.pem \
--certificate-identity 'https://github.com/gl0bal01/devbox/.github/workflows/weekly-rebuild.yml@refs/heads/main' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'
```
需要同时使用 `--certificate-identity` 和 `--certificate-oidc-issuer` —
省略任一个都会接受任何 GitHub Actions 工作流作为有效签名者。
### 多架构注意事项
提交的 `docker-compose.lock.yml` 文件针对 **x86_64**(CI 运行器架构)。使用 arm64 的操作者必须在本地使用 `./scripts/update-images.sh --apply` 重新生成锁定文件,然后再运行 `start-all.sh`。参见
[docs/updating.md](docs/updating.md)。
### Sigstore 不可用时的回退
如果 Sigstore(Rekor/Fulcio)宕机,CI 将失败关闭,不会裁剪 `weekly-*` 标签。紧急路径:`git checkout main && sudo ./setup.sh`。视为不受信任,并在 Sigstore 恢复后通过重新运行 `weekly-rebuild` 来重新验证。
## 操作者命令
Makefile 是唯一的入口点。
```
make help # one-line summary of every target
make doctor # preflight: docker daemon, tailscale, config.env, contract, marker
make test # lint + compose-check + anchor-check + docs-tree + contract bats
make lint # shellcheck + bash -n + 55 unit bats
make compose-check # validate compose configs (HTTP + HTTPS for every service)
make start # ${HOME}/docker/start-all.sh (refuses without install marker)
make stop # ${HOME}/docker/stop-all.sh
make status # ${HOME}/docker/status.sh
make backup # named-volume tar via alpine@sha256 + acme.json + .env files
make security-check # 10 hardening assertions
make rotate-ollama-auth # regenerate per-install ollama basic-auth credential
make install-systemd # sudo — install + enable devbox.service + devbox-backup.timer
make uninstall-systemd # sudo — stop, disable, remove units
```
依赖安装的目标在 `~/docker/lib/.devbox-marker` 处守卫,缺失时会拒绝并显示诊断消息。`make doctor` 始终运行。
## 渗透测试工作流
```
# 连接至 HTB VPN(基于 PID 文件,无全局 pkill)
htb-vpn ~/htb/lab.ovpn
htb-vpn status
# 启动带桌面的 Exegol(每个容器随机密码)
exegol # Default: exegol-htb on port 45377
exegol osint-box --port 45378 # Multiple containers on different ports
# 为运行中的容器轮换 VNC 密码
~/docker/exegol-reset-vnc.sh exegol-htb
# 访问:http://exegol.internal:45377/vnc.html
# 用户名:root,密码在容器启动时打印一次。
# UFW 仅将端口限制于 tailscale0 接口。
```
完整工作流参见 [docs/exegol.md](docs/exegol.md)。Exegol 使用上游 `exegol` CLI — `services/` 下没有 Compose 堆栈。
## 安全模型
根据 [docs/security.md](docs/security.md) 和 [ARCHITECTURE.md](ARCHITECTURE.md):
Sudoers 白名单(仅限 Docker 边界未处理的命令):
```
dev ALL=(root) NOPASSWD: /usr/sbin/ufw, /usr/bin/tailscale, /usr/sbin/openvpn
dev ALL=(root) NOPASSWD: /bin/systemctl restart docker, /bin/systemctl reload ufw
dev ALL=(root) PASSWD: ALL
```
### 网络暴露
- 仅 SSH(默认端口 5522)暴露给公共互联网。
- Traefik 端口 80 和(可选)443 绑定到 Tailscale IP — 无法从局域网访问。
- 所有 `.internal` URL 都需要 Tailscale。
- Exegol noVNC 端口:容器内部为 `0.0.0.0`,宿主机侧 UFW 规则限定在 `tailscale0`。
### 容器安全
| 措施 | 实现方式 |
|---|---|
| 密钥管理 | `.env` 文件权限 0600,安装时通过白名单 `envsubst` 渲染 |
| Docker 套接字保护 | Traefik 使用 `tecnativa/docker-socket-proxy`(只读 API 子集) |
| 防止权限提升 | 每个容器配置 `security_opt: no-new-privileges:true` |
| 权限丢弃 | `cap_drop: ALL` + 显式 `cap_add` 白名单 |
| 资源限制 | 每个容器的内存、CPU 和 PID 限制 |
| 日志轮转 | `json-file` 驱动,10 MB × 3 个文件(CI 检查漂移) |
| 停止宽限期 | 每个服务调整(Ollama 为 60s 以排空进行中的推理) |
### 身份验证
| 服务 | 方法 |
|---|---|
| SSH | 仅基于密钥(禁用密码,禁用 root) |
| Open WebUI | 应用级(创建管理员后禁用注册) |
| Traefik 仪表板 | 基本身份验证(`dashboard-auth` 中间件) |
| Ollama 外部路由 | 基本身份验证(`ollama-auth` 中间件,每次安装随机凭证) |
### 可选加固模块
`scripts/host/` 下有三个可选的操作者脚本,在基线之上添加按目标的加固。每个脚本**默认为试运行**;需要 `--apply` 才能进行更改。参见 [docs/harden-modules.md](docs/harden-modules.md)。
```
sudo scripts/host/harden-dnat-scope.sh # dry-run
sudo scripts/host/harden-dnat-scope.sh --apply # scope Docker DNAT to Tailscale CGNAT
sudo scripts/host/harden-fail2ban.sh --apply # traefik-auth + recidive jails (publicly bound only)
sudo scripts/host/harden-backup-skeleton.sh \
--tag myapp --path /home/myapp --apply # age-encrypted, systemd-timed backup
```
## 故障排除
```
sudo systemctl status ssh # SSH up?
sudo ss -tlnp | grep ssh # Listening port?
docker ps # Containers up?
docker logs traefik # Traefik logs
tailscale status # Tailscale connected?
~/docker/status.sh # Full status dashboard
~/docker/diagnose.sh # Bundle full diagnostic tarball
```
如果 `setup.sh` 提示 `"Another devbox setup.sh is already running"` 而阻塞:
```
sudo ls -la /var/lock/devbox-setup.lock
sudo rm /var/lock/devbox-setup.lock # only if no real setup is running
```
如果 `setup.sh` 因碰撞错误而拒绝,说明 `~/docker/` 目录树包含非 devbox 文件。要么将它们移开,要么选择一个干净的 `DEVBOX_HOME`。当 `~/docker/lib/devbox-contract.sh` 和 `~/docker/lib/.devbox-marker` 都存在时,就地升级模式会自动触发。
更多场景,请参见 [docs/troubleshooting.md](docs/troubleshooting.md) 和 [docs/ops.md](docs/ops.md)。
## 目录结构
**代码仓库**
```
devbox/
├── setup.sh # Host bootstrap (sources contract, rsyncs, renders, writes marker)
├── ARCHITECTURE.md # Load-bearing design decisions
├── Makefile # Operator entry point
├── README.md
├── CONTRIBUTING.md
├── LICENSE
├── config.env.example # Model for ~/.config/devbox/config.env
├── services/
│ ├── README.md # Compose conventions + rendering table
│ ├── traefik/
│ │ ├── docker-compose.yml
│ │ ├── docker-compose.https.yml
│ │ ├── docker-compose.lock.yml
│ │ ├── traefik.yml
│ │ ├── traefik.https.yml.template
│ │ ├── .env.template
│ │ ├── .env.example
│ │ └── dynamic/
│ │ ├── dashboard-auth.yml.template
│ │ ├── ollama-auth.yml.template
│ │ ├── middlewares-base.yml
│ │ ├── middlewares-https.yml
│ │ ├── middlewares-rate.yml
│ │ └── middlewares-allowlist.yml
│ └── ollama-openwebui/
│ ├── docker-compose.yml
│ ├── docker-compose.https.yml
│ ├── docker-compose.lock.yml
│ ├── .env.template
│ └── .env.example
├── scripts/
│ ├── host/ # Helpers rsynced to ~/docker/ by setup.sh
│ │ ├── start-all.sh
│ │ ├── stop-all.sh
│ │ ├── status.sh
│ │ ├── security-check.sh
│ │ ├── backup.sh # named-volume tar via alpine@sha256
│ │ ├── rotate-ollama-auth.sh # per-install credential rotation
│ │ ├── install-systemd.sh # render + enable systemd units
│ │ ├── diagnose.sh
│ │ ├── install-ai-dev-stack.sh
│ │ ├── htb-vpn.sh
│ │ ├── exegol-start.sh
│ │ ├── exegol-reset-vnc.sh
│ │ ├── harden-dnat-scope.sh # opt-in
│ │ ├── harden-fail2ban.sh # opt-in
│ │ └── harden-backup-skeleton.sh # opt-in
│ ├── install/
│ │ ├── dev-zshrc
│ │ └── mise-profile.sh
│ ├── laptop/ # Run on your laptop
│ │ ├── ollama-setup.sh
│ │ ├── zed-setup.sh
│ │ └── README.md
│ ├── lib/
│ │ ├── devbox-contract.sh # CANONICAL CONTRACT
│ │ ├── fetch-verify.sh
│ │ ├── download-manifest.sh
│ │ └── sources/ # per-upstream version refresh handlers
│ ├── systemd/
│ │ ├── devbox.service.template
│ │ ├── devbox-backup.service.template
│ │ └── devbox-backup.timer.template
│ ├── ci/
│ │ ├── lint.sh # shellcheck + bash -n + 55 unit bats + docs-tree
│ │ ├── check-compose-config.sh
│ │ ├── check-anchor-consistency.sh
│ │ ├── check-docs-tree.sh
│ │ ├── smoke-test.sh
│ │ ├── sbom-targets.sh
│ │ └── release-notes.sh
│ ├── update-images.sh # Two-pass lockfile generator
│ └── update-manifest.sh
├── tests/
│ ├── contract/
│ │ ├── contract.bats # 24 install-contract assertions
│ │ └── systemd.bats # 11 systemd-unit assertions
│ ├── unit/ # 55 bats (anchor, fetch-verify, htb-vpn, parse-image, render-env)
│ └── lib/test-helpers.bash
├── docs/
│ ├── security.md
│ ├── ops.md
│ ├── updating.md
│ ├── harden-modules.md
│ ├── https-setup.md
│ ├── exegol.md
│ ├── ollama-optimization.md
│ ├── remote-ide-setup.md
│ └── troubleshooting.md
└── .github/
└── workflows/
├── pr-validate.yml # lint + compose-check + anchor + docs-tree + contract bats
└── weekly-rebuild.yml # signed tarball + SBOM + SLSA + alpine-digest-check PR
```
**服务器(运行 `setup.sh` 后)**
```
~/
├── .devbox-credentials[.gpg] # Generated credentials (delete after saving)
├── .config/devbox/
│ ├── config.env # ENABLE_HTTPS, DOMAIN, TAILSCALE_IP, DEVBOX_USER, COMPOSE_FILE_
│ └── ovh.env # OVH credentials (HTTPS mode; mode 0600)
├── .local/share/devbox/backups/ # Pre-rsync snapshots + backup.sh archives
├── docker/ # rsynced from services/ + scripts/host/ + scripts/systemd/
│ ├── lib/
│ │ ├── devbox-contract.sh # Installed runtime authority
│ │ └── .devbox-marker # Spoof-resistant install marker
│ ├── .secrets/
│ │ └── ollama-auth.txt # Per-install plaintext credential (0600)
│ ├── traefik/
│ ├── ollama-openwebui/
│ ├── systemd/ # Unit templates for install-systemd.sh
│ ├── start-all.sh, stop-all.sh, status.sh, security-check.sh, backup.sh
│ ├── rotate-ollama-auth.sh, install-systemd.sh
│ ├── exegol-start.sh, exegol-reset-vnc.sh, htb-vpn.sh
│ └── (per-service .env files rendered from .env.template at install time)
├── projects/
└── htb/ # HTB .ovpn files
```
## 文档索引
| 文档 | 主题 |
|---|---|
| [ARCHITECTURE.md](ARCHITECTURE.md) | 关键设计决策(取代旧的 `docs/adr/` 目录) |
| [docs/security.md](docs/security.md) | 信任模型、权限边界、ollama-auth 轮换语义 |
| [docs/ops.md](docs/ops.md) | 备份/恢复、事件响应、快照恢复 |
| [docs/updating.md](docs/updating.md) | 已签名 tarball 安装、摘要刷新、Alpine 自动 PR |
| [docs/harden-modules.md](docs/harden-modules.md) | 可选 `harden-*.sh` 模块(DNAT、fail2ban、age 加密备份) |
| [docs/https-setup.md](docs/https-setup.md) | OVH DNS-01 设置,用于仅 Tailscale 的 HTTPS |
| [docs/exegol.md](docs/exegol.md) | 多容器渗透测试工作流 |
| [docs/ollama-optimization.md](docs/ollama-optimization.md) | 性能调优 |
| [docs/remote-ide-setup.md](docs/remote-ide-setup.md) | 配置本地 IDE 使用远程 Ollama |
| [docs/troubleshooting.md](docs/troubleshooting.md) | 常见问题 |
| [services/README.md](services/README.md) | Compose 布局、渲染表、锚点模式 |
| [scripts/laptop/README.md](scripts/laptop/README.md) | 用于远程 Ollama 的笔记本端设置 |
| [CONTRIBUTING.md](CONTRIBUTING.md) | 如何贡献 |
## 测试环境
| 提供商 | 实例类型 | 状态 |
|---|---|---|
| Hostinger | KVM 8 (32 GB / 8 vCPU) | 已验证 |
| Hetzner | CX31 | 兼容 |
| DigitalOcean | Droplet | 兼容 |
| AWS | EC2 t3.medium+ | 兼容 |
## 许可证
MIT。参见 [LICENSE](LICENSE)。
## 参考资料
- [Tailscale](https://tailscale.com/kb/) · [Traefik](https://doc.traefik.io/traefik/) · [Ollama](https://ollama.ai/) · [Exegol](https://exegol.readthedocs.io/) · [Sigstore / cosign](https://docs.sigstore.dev/) · [SLSA Framework](https://slsa.dev/)
*最后更新:2026-05-16 (v1.0.0 — 运行时契约、仅 Tailscale 的 HTTPS、每次安装独立 ollama-auth、已签名每周 tarball、35 个契约 bats + 55 个单元 bats)*
标签:AI平台, AI开发环境, AI风险缓解, CI/CD安全, Docker Compose编排, Docker容器, Google Gemini, HTTPS证书管理, Llama, Makefile自动化, Ollama模型服务, Open WebUI前端, Systemd服务管理, Tailscale集成, Traefik反向代理, Ubuntu服务器, Web截图, 下载验证, 代码签名, 反向代理配置, 备份恢复, 容器化部署, 容器安全, 容器镜像锁定, 应用安全, 开发工作站, 攻击面发现, 数字取证, 服务网格, 环境隔离, 网络安全, 自动化脚本, 认证管理, 请求拦截, 跌倒检测, 软件物料清单, 隐私保护