contriboss/vein
GitHub: contriboss/vein
Vein 是一个高性能的多生态包代理与缓存服务器,通过统一端点为 RubyGems、crates.io 和 npm 提供本地缓存和供应链保护能力。
Stars: 23 | Forks: 2
# Vein 💎
一个快速、智能的多生态包代理/缓存工具,支持 RubyGems、crates.io 和 npm。
**统一端点:** Bundler、ore-light、Cargo 和 npm 都可以指向同一个 Vein 基础 URL。同一台服务器通过路径/请求头检测来处理 RubyGems、crates.io sparse index 及 crate 下载,以及 npm metadata 和 tarballs。目前支持对 RubyGems 的上游进行配置;crates.io 和 npm 使用固定的上游。
## 什么是 Vein?
Vein 是一个针对多个包生态系统的**智能缓存代理**,它可以:
- 通过可配置的上游代理 RubyGems
- 带缓存地镜像 crates.io sparse index 和 crate 下载
- 带缓存地代理 npm registry 的元数据和 tarballs
- 在重复请求时从本地存储提供缓存的制品
- 可以在没有 RubyGems 上游的情况下运行;crates.io 和 npm 仍然使用其内置的上游
- 基于 Rama(模块化服务框架)构建
- 极简配置 - 在常见设置下开箱即用
## 为什么选择 Vein?
- **极速**:基于 Rama 的高性能代理
- **智能缓存**:只需缓存一次制品,之后直接从本地提供
- **供应链保护**:隔离系统(目前支持 RubyGems;正逐步扩展至其他生态系统)
- **极简配置**:crates.io 和 npm 开箱即用;当需要 Vein 获取新 gems 时,只需添加 RubyGems 上游
- **简单部署**:单一二进制文件,没有复杂的依赖
- **多 registry 端点**:RubyGems + crates.io + npm 共享一个基础 URL
- **Ore 集成**:与 ore-light 的回退机制无缝协作
## 快速开始
```
# 使用 Docker 运行
docker run -p 8346:8346 -v vein-data:/data ghcr.io/contriboss/vein:latest
# 或者使用 docker-compose
curl -O https://raw.githubusercontent.com/contriboss/vein/master/docker-compose.yml
docker-compose up -d
# 或者从源码构建
cargo build --release
./target/release/vein serve
```
## 工作原理
```
Client Request → Vein → Local Cache?
├─ Hit → Serve from filesystem
└─ Miss → Fetch from upstream (RubyGems / crates.io / npm)
├─ Cache locally
└─ Serve to client
```
**永久缓存:** 制品文件(gems、crates、npm tarballs)在首次获取时即被缓存,此后均从本地提供。Index/元数据端点通过 TTL + 重新验证进行缓存。
**简洁架构:** 使用 SQLite(默认)或 PostgreSQL 存储元数据 + 使用文件系统存储缓存制品(默认存储根目录:`./cache`)。
## 功能
- [x] 基于 Rama 的 HTTP 代理
- [x] SQLite/PostgreSQL 清单(持久化元数据)
- [x] 文件系统存储(默认 `./cache/`,带有按生态系统划分的子文件夹)
- [x] 智能缓存解析器
- [x] 流式缓存(在提供服务的同时进行缓存)
- [x] SHA256 验证
- [x] 极简配置
- [x] Docker 镜像
- [x] 包名/版本/平台解析
- [x] 带有指标的请求日志记录
- [x] 损坏时的缓存重新验证
- [x] 带有可配置上游的 RubyGems 代理
- [x] crates.io sparse index + crate 下载缓存
- [x] npm registry 元数据 + tarball 缓存
- [x] 用于目录、隔离和 SBOM 检查的管理控制面板
- [x] CycloneDX SBOM 提取,带有管理预览和下载 API(目前支持 RubyGems;正逐步扩展)
- [x] 隔离系统(防范供应链攻击,目前支持 RubyGems;正逐步扩展)
### 用法
```
# (可选)编写配置文件 – 默认值与此代码片段类似
cat <<'TOML' > vein.toml
[server]
host = "0.0.0.0"
port = 8346
[storage]
path = "./cache"
[database]
path = "./vein.db"
# 可选:为未缓存的 gems 启用 RubyGems 获取
# [upstream]
# url = "https://rubygems.org"
TOML
# 启动 proxy(RubyGems、crates.io 和 npm 在一个 endpoint 上)
cargo run -- serve --config vein.toml
# 检查 cache 统计信息
cargo run -- stats --config vein.toml
```
### CycloneDX SBOM 访问
**范围:** 目前为缓存的 RubyGems 生成 SBOM。路线图是将 SBOM 生成扩展到 Vein 支持的其他生态系统,包括 crates.io 和 npm。
- **管理控制面板:** 启动 `make admin`,然后浏览至 `http://127.0.0.1:9400/catalog/?version=` 以预览生成的 SBOM,并直接从 UI 下载 JSON。
- **代理端点:** 任何客户端都可以通过在运行中的 Vein 代理上调用 `GET /.well-known/vein/sbom?name=&version=[&platform=]` 来获取 SBOM,而无需管理 UI。响应是一个 CycloneDX 1.5 文档,带有 `Content-Type: application/json` 和便于下载的文件名。对于默认的 `ruby` 构建版本,请省略 `platform` 查询;对于原生变体(例如 `arm64-darwin`),请提供此参数。
- SBOM 在 gem 首次缓存时自动生成,并在重新获取该 gem 时刷新。
### 隔离(供应链保护)
**范围:** 目前隔离功能应用于 RubyGems 元数据/索引响应。路线图是将相同的保护应用到 Vein 支持的其他生态系统,包括 crates.io 和 npm。
Vein 可以延迟新 gem 版本在 Bundler 索引中的出现时间,从而为社区争取时间,在恶意包到达您的 CI/CD 之前将其拦截。
**工作原理:**
- 新的 gem 版本会被隔离一段可配置的时间(默认:3 天)
- `bundle update` 和 `bundle outdated` 将无法看到被隔离的版本
- 直接安装(`gem install foo -v 1.2.3`)仍然有效(显式选择)
- 隔离期满后,版本会自动提升
**真实场景(rest-client 1.6.13,2019 年 8 月):**
- 发布了恶意版本,约 12 小时后被撤销
- 在此期间运行 `bundle update` 的任何 CI/CD 都会受到破坏
- 使用 Vein 的 3 天隔离:零暴露风险
**在配置中启用:**
```
[delay_policy]
enabled = true
default_delay_days = 3
skip_weekends = true # Don't release on Sat/Sun
business_hours_only = true # Only release during business hours
release_hour_utc = 10 # Release at 10:00 UTC
# 针对每个 gem 的 overrides(支持 glob patterns)
[[delay_policy.gems]]
name = "rails*"
pattern = true
delay_days = 7 # Extra scrutiny for Rails ecosystem
[[delay_policy.gems]]
name = "internal-*"
pattern = true
delay_days = 0 # Trust internal gems
# Pin 特定版本以供即时使用
[[delay_policy.pinned]]
name = "rails"
version = "8.0.1"
reason = "Security patch - verified safe"
```
**CLI 命令:**
```
# 显示 quarantine 状态
vein quarantine status
# 列出 quarantine 中的版本
vein quarantine list
# 手动 promote 过期版本
vein quarantine promote
# Approve 一个版本以供立即发布
vein quarantine approve rails 8.0.1 --reason "Security patch"
# Block 恶意版本
vein quarantine block badgem 1.0.0 --reason "Malware detected"
```
**管理界面:** 在管理服务器上浏览至 `/quarantine` 以查看统计信息并批准/阻止相应版本。
### 配置
最小配置(crates.io 和 npm 使用默认值即可工作;需要时配置 RubyGems 上游):
```
# vein.toml
[server]
port = 8346 # default
[storage]
path = "./cache" # default
# 可选:为未缓存的 gems 启用 RubyGems 获取
# [upstream]
# url = "https://rubygems.org"
```
完整配置选项:
```
[server]
host = "0.0.0.0"
port = 8346
workers = 4 # Rama worker threads
[upstream]
url = "https://rubygems.org" # Optional RubyGems upstream
fallback_urls = []
[storage]
path = "./cache"
[database]
path = "vein.db" # SQLite inventory
[logging]
level = "info" # debug, info, warn, error
json = false
[delay_policy]
enabled = false # Enable quarantine system
default_delay_days = 3 # Default quarantine period
skip_weekends = true # Don't release on weekends
business_hours_only = true # Only release during business hours
release_hour_utc = 9 # Hour to release (0-23)
```
### 存储架构
Vein 采用 **数据库 + 文件系统** 架构以实现最佳性能:
#### SQLite (`vein.db`) 或 PostgreSQL - 持久化元数据存储
**用途**:所有缓存包的权威数据源
**存储内容**:
- 完整的包元数据(名称、版本、平台)
- 文件系统路径
- SHA256 校验和
- 文件大小
- 最后访问时间戳
**使用时机**:
- 在缓存未命中时,验证是否需要获取包
- 在缓存写入时,存储元数据
## 开发
```
# Build(SQLite backend,默认)
cargo build --release
# 使用 PostgreSQL backend 进行 Build
cargo build --release --no-default-features --features postgres,tls
# 运行(带 logging)
RUST_LOG=debug cargo run -- serve
# 测试
cargo test
```
**注意:** SQLite 和 PostgreSQL 在编译时是互斥的。请选择其中之一。
## Docker 部署
### 基本用法
```
# 拉取 image
docker pull ghcr.io/contriboss/vein:latest
# 使用 persistent volumes 运行
docker run -d \
--name vein \
-p 8346:8346 \
-v vein-data:/data \
-e RUST_LOG=info \
ghcr.io/contriboss/vein:latest
# 查看日志
docker logs -f vein
```
### 使用 Docker Compose(推荐)
包含的 `docker-compose.yml` 会启动一个**完全配置好的、可用于生产环境的** Vein 代理,并带有 PostgreSQL 后端:
```
# 克隆并启动
git clone https://github.com/contriboss/vein.git
cd vein
docker compose up -d
# 验证健康状态
docker compose ps # Both services should show "healthy"
# 查看日志
docker compose logs -f vein
# 停止服务
docker compose down
```
**包含内容:**
- PostgreSQL 18 及持久化存储
- 带有自动迁移的 Vein 代理(无需手动设置)
- 两个服务的健康检查
- 预先配置好的网络
将 Bundler、Cargo 或 npm 指向 `http://localhost:8346` 即可大功告成。
### 自定义配置
```
# 创建配置文件
cp vein.example.toml vein.toml
# 根据需要编辑...
# 使用自定义 config 运行
docker run -d \
--name vein \
-p 8346:8346 \
-v $(pwd)/vein.toml:/data/vein.toml:ro \
-v vein-data:/data \
vein:latest serve --config /data/vein.toml
```
## 部署
### Systemd 服务
```
[Unit]
Description=Vein Package Proxy
After=network.target
[Service]
Type=simple
User=vein
ExecStart=/usr/local/bin/vein serve --config /etc/vein/vein.toml
Restart=always
[Install]
WantedBy=multi-user.target
```
### 在 Nginx 之后
```
upstream vein {
server localhost:8346;
}
server {
listen 443 ssl http2;
server_name packages.company.com;
location / {
proxy_pass http://vein;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
## 与 ore-light 的关系
- **ore-light**:基于 Go 的 Bundler 替代方案(客户端 gem 管理)
- **Vein**:多生态包代理/缓存(服务端包分发)
ore-light 是一个可以使用 Vein RubyGems 端的客户端。
Vein 本身的范围更广:它还能从相同的基础 URL 为 crates.io 和 npm 流量提供服务。
## 为什么选择 Rama(而不是 Pingora)
Vein 最初基于 Cloudflare 的 Pingora 框架构建。然而,Pingora **完全缺乏对 FreeBSD 的支持**,并且修复此问题的贡献被忽略了。一个旨在添加 FreeBSD 支持的 PR 没有得到任何回应。
因此我迁移到了 [Rama](https://github.com/plabayo/rama),它:
- 在 FreeBSD 15.0-STABLE(以及 Linux、macOS、Windows、iOS、Android)上完美编译
- 具有真正的模块化架构(而不是仅仅挂个“模块化”的名头)
- 欢迎个人的贡献,而不仅仅是大公司的贡献
- 不会将您锁定在固执己见的模式中,当您超出边界时被迫去 fork 代码
对于需要灵活性和多平台支持的项目来说,Rama 是一个更健康的选择。
谢谢,Cloudflare。
## 商业用途与扩展
Vein 基于 [Rama](https://github.com/plabayo/rama) 构建,这是一个由 [Plabayo](https://plabayo.tech) 开发的模块化服务框架。
**项目状态**:Vein 是一个**副业项目**,并将保持免费和开源。它不会商业化。
**HTTP 功能**:刻意保持基础。Vein 只做它需要做的事:代理、缓存、提供包。没有计划添加复杂的 HTTP 功能或企业级功能。
**需要更多功能?** 需要额外功能(高级路由、身份验证、监控、协议扩展)的公司应**直接聘请 Plabayo** 来扩展 Vein:
- 扩展可以是公开的(贡献给上游)或私有的(内部 fork)
- 这使 Vein 保持专注,并将工作交给了构建基础 的团队
- 避免让作者变成全职的代理顾问
**支持合同**:Plabayo 为基于 Rama 的项目提供商业服务合同。请通过 https://plabayo.tech 联系他们
## 许可证
Vein 采用双重许可:
- **个人/个人使用**:MIT 许可证(见 [LICENSE-MIT](./LICENSE-MIT))
- **商业/公司使用**:AGPL-3.0(见 [LICENSE-AGPL](./LICENSE-AGPL))
您可以选择最适合您用例的许可证。如果在商业组织内使用,则适用 AGPL-3.0 条款。
标签:Cargo, npm, RubyGems, 包代理, 可视化界面, 测试用例, 缓存服务器, 请求拦截, 通知系统, 镜像服务