From 65f132e9c212cb1f10b9500640002d3a923d87f2 Mon Sep 17 00:00:00 2001 From: Jamie Pine Date: Sat, 31 Jan 2026 00:46:50 -0800 Subject: [PATCH] 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) --- .github/workflows/release.yml | 33 ++-- backend/test_r2_upload.sh | 86 +++++++++++ docs/r2-setup.md | 274 ++++++++++++++++++++++++++++++++++ 3 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 backend/test_r2_upload.sh create mode 100644 docs/r2-setup.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 39cefbb2..ac839ebc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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" diff --git a/backend/test_r2_upload.sh b/backend/test_r2_upload.sh new file mode 100644 index 00000000..d166e148 --- /dev/null +++ b/backend/test_r2_upload.sh @@ -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 diff --git a/docs/r2-setup.md b/docs/r2-setup.md new file mode 100644 index 00000000..5d8c0698 --- /dev/null +++ b/docs/r2-setup.md @@ -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: +``` + +### 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: +``` + +### 3. R2_ENDPOINT + +Your Cloudflare R2 endpoint URL + +**Format:** +``` +https://.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://.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)