Integrate Cloudflare R2 for CUDA binary hosting

- Update CI workflow to upload CUDA binary to R2 instead of GitHub
- Use custom domain: downloads.voicebox.sh
- Update release notes with R2 download link
- Add R2 setup documentation with GitHub secrets instructions
- Add local test script for R2 uploads
- Fixes GitHub 2GB release asset limit issue

Required GitHub secrets:
- R2_ACCESS_KEY_ID
- R2_SECRET_ACCESS_KEY
- R2_ENDPOINT

Cost: ~$0.04/month (free bandwidth with R2)
This commit is contained in:
Jamie Pine
2026-01-31 00:46:50 -08:00
parent c211e52382
commit 65f132e9c2
3 changed files with 384 additions and 9 deletions
+24 -9
View File
@@ -177,9 +177,9 @@ jobs:
### NVIDIA GPU Acceleration (Windows)
Windows users with NVIDIA GPUs can enable CUDA for 4-5x faster inference:
1. Install the app normally (CPU version)
2. The app will detect your GPU and offer to download CUDA support
3. Or manually download `voicebox-server-cuda-*.exe` (~3GB) from the assets below
1. Install the app normally (CPU version included in installer)
2. The app will detect your GPU and offer to download CUDA support automatically
3. Or manually download: [voicebox-server-cuda-x86_64-pc-windows-msvc.exe](https://downloads.voicebox.sh/cuda/__VERSION__/voicebox-server-cuda-x86_64-pc-windows-msvc.exe) (~2.4GB)
The app includes automatic updates - future updates will be installed automatically.
releaseDraft: true
@@ -187,11 +187,26 @@ jobs:
args: ${{ matrix.args }}
includeUpdaterJson: true
- name: Upload CUDA server binary (Windows only)
- name: Upload CUDA server to Cloudflare R2 (Windows only)
if: matrix.platform == 'windows-latest'
uses: softprops/action-gh-release@v1
with:
files: backend/cuda-release/voicebox-server-cuda-*.exe
draft: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }}
run: |
# Install AWS CLI if not available
pip install awscli
# Get version from tag
VERSION=${GITHUB_REF#refs/tags/}
# Get platform tuple
PLATFORM=$(rustc --print host-tuple)
# Upload to R2
aws s3 cp backend/cuda-release/voicebox-server-cuda-${PLATFORM}.exe \
s3://voicebox-releases/cuda/${VERSION}/voicebox-server-cuda-${PLATFORM}.exe \
--endpoint-url $R2_ENDPOINT \
--acl public-read
echo "CUDA binary uploaded to: https://downloads.voicebox.sh/cuda/${VERSION}/voicebox-server-cuda-${PLATFORM}.exe"
+86
View File
@@ -0,0 +1,86 @@
#!/bin/bash
# Test R2 upload locally before running in CI
set -e
echo "============================================================"
echo "Cloudflare R2 Upload Test"
echo "============================================================"
# Check for required environment variables
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ] || [ -z "$R2_ENDPOINT" ]; then
echo "ERROR: Missing required environment variables"
echo ""
echo "Please set:"
echo " export AWS_ACCESS_KEY_ID='your-r2-access-key-id'"
echo " export AWS_SECRET_ACCESS_KEY='your-r2-secret-access-key'"
echo " export R2_ENDPOINT='https://your-account-id.r2.cloudflarestorage.com'"
echo ""
exit 1
fi
# Check for AWS CLI
if ! command -v aws &> /dev/null; then
echo "Installing AWS CLI..."
pip install awscli
fi
# Find CUDA binary
CUDA_BINARY=$(ls dist/voicebox-server-cuda*.exe 2>/dev/null | head -1)
if [ -z "$CUDA_BINARY" ]; then
echo "ERROR: CUDA binary not found in dist/"
echo "Run: bash build_cuda.bat"
exit 1
fi
echo ""
echo "Found CUDA binary: $CUDA_BINARY"
echo "Size: $(du -h "$CUDA_BINARY" | cut -f1)"
echo ""
# Test version
VERSION="v0.1.12-test"
PLATFORM="x86_64-pc-windows-msvc"
FILENAME="voicebox-server-cuda-${PLATFORM}.exe"
echo "Test upload configuration:"
echo " Version: $VERSION"
echo " Platform: $PLATFORM"
echo " Endpoint: $R2_ENDPOINT"
echo " Bucket: voicebox-releases"
echo " Path: cuda/$VERSION/$FILENAME"
echo ""
read -p "Proceed with upload? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 1
fi
echo ""
echo "Uploading to R2..."
aws s3 cp "$CUDA_BINARY" \
"s3://voicebox-releases/cuda/${VERSION}/${FILENAME}" \
--endpoint-url "$R2_ENDPOINT" \
--acl public-read
if [ $? -eq 0 ]; then
echo ""
echo "============================================================"
echo "Upload successful!"
echo "============================================================"
echo ""
echo "Download URL:"
echo "https://downloads.voicebox.sh/cuda/${VERSION}/${FILENAME}"
echo ""
echo "Test with:"
echo "curl -I https://downloads.voicebox.sh/cuda/${VERSION}/${FILENAME}"
echo ""
else
echo ""
echo "Upload failed!"
exit 1
fi
+274
View File
@@ -0,0 +1,274 @@
# Cloudflare R2 Setup Guide
## Overview
The CUDA binary (2.4GB) is hosted on Cloudflare R2 at `downloads.voicebox.sh` instead of GitHub Releases (which has a 2GB limit).
## R2 Bucket Configuration
**Completed:**
- Bucket created: `voicebox-releases`
- Custom domain configured: `downloads.voicebox.sh`
## GitHub Secrets Required
Add these secrets to your GitHub repository:
### 1. R2_ACCESS_KEY_ID
Your Cloudflare R2 API Access Key ID
**How to get it:**
1. Go to Cloudflare Dashboard → R2
2. Click "Manage R2 API Tokens"
3. Create API Token with "Object Read & Write" permissions
4. Copy the "Access Key ID"
**Add to GitHub:**
```
Repository Settings → Secrets and variables → Actions → New repository secret
Name: R2_ACCESS_KEY_ID
Value: <your-access-key-id>
```
### 2. R2_SECRET_ACCESS_KEY
Your Cloudflare R2 Secret Access Key
**How to get it:**
- Same process as above
- Copy the "Secret Access Key" (shown only once!)
- Store it securely
**Add to GitHub:**
```
Name: R2_SECRET_ACCESS_KEY
Value: <your-secret-access-key>
```
### 3. R2_ENDPOINT
Your Cloudflare R2 endpoint URL
**Format:**
```
https://<account-id>.r2.cloudflarestorage.com
```
**How to find your account ID:**
- Cloudflare Dashboard → R2
- Look at the URL or bucket settings
- Should be a string of letters/numbers
**Add to GitHub:**
```
Name: R2_ENDPOINT
Value: https://<your-account-id>.r2.cloudflarestorage.com
```
## Bucket Structure
After CI uploads, the bucket will have this structure:
```
voicebox-releases/
└── cuda/
├── v0.1.12/
│ └── voicebox-server-cuda-x86_64-pc-windows-msvc.exe
├── v0.1.13/
│ └── voicebox-server-cuda-x86_64-pc-windows-msvc.exe
└── v0.2.0/
└── voicebox-server-cuda-x86_64-pc-windows-msvc.exe
```
## Public Access
Files are uploaded with `--acl public-read`, making them accessible at:
```
https://downloads.voicebox.sh/cuda/v{VERSION}/voicebox-server-cuda-x86_64-pc-windows-msvc.exe
```
**Example:**
```
https://downloads.voicebox.sh/cuda/v0.1.12/voicebox-server-cuda-x86_64-pc-windows-msvc.exe
```
## Testing the Setup
### Local Test Upload
Before running the CI, test uploading locally:
```bash
# Set environment variables
export AWS_ACCESS_KEY_ID="your-r2-access-key-id"
export AWS_SECRET_ACCESS_KEY="your-r2-secret-access-key"
export R2_ENDPOINT="https://your-account-id.r2.cloudflarestorage.com"
# Install AWS CLI
pip install awscli
# Test upload (use a small test file first)
echo "test" > test.txt
aws s3 cp test.txt \
s3://voicebox-releases/test/test.txt \
--endpoint-url $R2_ENDPOINT \
--acl public-read
# Verify it's accessible
curl https://downloads.voicebox.sh/test/test.txt
# If successful, try the actual CUDA binary
aws s3 cp backend/dist/voicebox-server-cuda.exe \
s3://voicebox-releases/cuda/v0.1.12-test/voicebox-server-cuda-x86_64-pc-windows-msvc.exe \
--endpoint-url $R2_ENDPOINT \
--acl public-read
```
### Verify Upload
Check if the file is accessible:
```bash
curl -I https://downloads.voicebox.sh/cuda/v0.1.12-test/voicebox-server-cuda-x86_64-pc-windows-msvc.exe
```
Should return:
```
HTTP/2 200
content-length: 2545086396
content-type: application/x-msdownload
...
```
## CI Workflow
The workflow now:
1. **Builds CPU binary** → Includes in installer
2. **Builds CUDA binary** → Uploads to R2
3. **Release notes** → Include R2 download link
### CI Steps (Windows)
```yaml
- name: Build CUDA Python server (Windows only)
# Builds the CUDA binary
- name: Upload CUDA server to Cloudflare R2 (Windows only)
env:
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }}
run: |
aws s3 cp backend/cuda-release/voicebox-server-cuda-*.exe \
s3://voicebox-releases/cuda/${VERSION}/... \
--endpoint-url $R2_ENDPOINT \
--acl public-read
```
## Cost Tracking
Monitor your R2 usage:
**Cloudflare Dashboard → R2 → voicebox-releases → Metrics**
Expected costs (per month):
- Storage: 2.4GB × $0.015/GB = **$0.036**
- Egress: **$0.00** (free!)
- Class A ops: ~100 × $4.50/million = **$0.00**
**Total: ~$0.04/month** (essentially free!)
## Troubleshooting
### Upload fails: "Access Denied"
**Solution:** Check API token permissions
- Must have "Object Read & Write" on the bucket
- Regenerate token if needed
### File not accessible at downloads.voicebox.sh
**Solution:** Check custom domain configuration
- R2 Dashboard → Bucket → Settings → Custom Domains
- Ensure `downloads.voicebox.sh` is properly configured
- DNS may take time to propagate
### "endpoint-url" not recognized
**Solution:** Make sure AWS CLI is updated
```bash
pip install --upgrade awscli
```
### File uploaded but wrong permissions
**Solution:** Re-upload with `--acl public-read`
```bash
aws s3 cp ... --acl public-read
```
Or set bucket default permissions in R2 Dashboard.
## Security Notes
### API Token Permissions
**Recommended:**
- Object Read & Write only
- No admin permissions needed
- Scoped to `voicebox-releases` bucket only
**Avoid:**
- Account-wide permissions
- Account admin access
- Worker edit permissions
### Secret Rotation
Rotate API tokens every 6-12 months:
1. Create new API token
2. Update GitHub secrets
3. Verify CI still works
4. Delete old token
## Maintenance
### Cleaning Old Versions
Optional: Delete old CUDA binaries to save storage costs
```bash
# List all versions
aws s3 ls s3://voicebox-releases/cuda/ \
--endpoint-url $R2_ENDPOINT
# Delete old version
aws s3 rm s3://voicebox-releases/cuda/v0.1.0/ \
--recursive \
--endpoint-url $R2_ENDPOINT
```
### Monitoring
Set up Cloudflare notifications:
- Storage approaching limits
- Unusual traffic patterns
- High operation counts
## Next Steps
1. ✅ Bucket configured
2. ⏳ Add GitHub secrets (R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_ENDPOINT)
3. ⏳ Test local upload
4. ⏳ Push branch and create test release
5. ⏳ Verify CUDA binary accessible from downloads.voicebox.sh
6. ⏳ Implement frontend download manager
---
**Status**: Ready for testing
**Cost**: ~$0.04/month
**Bandwidth**: Free (unlimited)