Overview
Digital Ocean Spaces is an S3-compatible object storage service perfect for serving installers, providing:
- CDN integration for fast global downloads
- 250GB storage + 1TB transfer for $5/month
- Additional transfer at $0.01/GB
- Signed URLs for secure, time-limited access
Setup Steps
1. Create a Space
- Go to Digital Ocean Console
- Click "Create Space"
- Configure:
- Choose datacenter: Select region close to your users (e.g., NYC3)
- Enable CDN: Yes (recommended)
- Space name: rmm-installers (or your preferred name)
- File listing: Disabled (keep private)
- CDN custom subdomain: Optional (e.g., cdn.yourdomain.com)
2. Generate API Keys
- Go to API → Spaces access keys
- Click "Generate New Key"
- Name: "RMM Backend API"
- Save the keys securely:
- Access Key ID: DO_SPACES_KEY
- Secret Access Key: DO_SPACES_SECRET
3. Configure Environment Variables
Add to your backend .env or DO App Platform environment:
USE_DO_SPACES=true
DO_SPACES_KEY=your_access_key_here
DO_SPACES_SECRET=your_secret_key_here
DO_SPACES_BUCKET=rmm-installers
DO_SPACES_REGION=nyc3
DO_SPACES_ENDPOINT=nyc3.digitaloceanspaces.com
DO_SPACES_CDN_ENDPOINT=cdn.yourdomain.com # Optional
CLEANUP_AFTER_UPLOAD=true # Delete local files after upload
4. Set Up Folder Structure
Recommended structure in your Space:
rmm-installers/
├── installers/
│ ├── public/
│ │ ├── agent/
│ │ │ └── dev-agent.exe
│ │ └── bootstrapper/
│ │ └── bootstrapper.exe
│ ├── tenant-123/
│ │ ├── bootstrapper/
│ │ │ └── bootstrapper_tenant-123.exe
│ │ ├── agent/
│ │ │ └── agent_tenant-123_v1.0.0.exe
│ │ └── tray/
│ │ └── tray_tenant-123.exe
│ └── tenant-456/
│ └── ...
└── plugins/
└── ...
5. Configure CDN (Optional but Recommended)
If you enabled CDN:
- Custom Domain (optional):
- Add CNAME record: cdn.yourdomain.com → rmm-installers.nyc3.cdn.digitaloceanspaces.com
- Update DO_SPACES_CDN_ENDPOINT to your custom domain
- Cache Settings:
- Default TTL: 3600s (1 hour)
- Installers rarely change, so longer TTL is fine
6. Test the Setup
Upload a test file:
# Using spacesService
const spacesService = require('./services/spacesService');
await spacesService.uploadFile('./test.txt', 'test/test.txt');
Generate a signed URL:
const url = spacesService.getSignedUrl('test/test.txt', 3600);
console.log('Signed URL:', url);
7. Migration Strategy
Option A: Gradual Migration
- Keep existing API serving functional
- Enable USE_DO_SPACES=true
- New builds upload to Spaces and redirect
- Old builds still serve from local storage
- Gradually cleanup local files
Option B: Full Migration
- Upload all existing installers to Spaces:
# Script to bulk upload
cd backend/downloads
for file in *.exe; do
node -e "
const spaces = require('../services/spacesService');
spaces.uploadFile('./$file', 'installers/public/legacy/$file');
"
done
- Enable USE_DO_SPACES=true
- Set CLEANUP_AFTER_UPLOAD=true
- Remove local downloads directory from git
8. Security Best Practices
- Private ACL: All objects default to private
- Signed URLs: Generate time-limited URLs (default 1 hour)
- Key Rotation: Rotate API keys periodically
- Firewall: Restrict API key usage to your backend IP if possible
- Monitoring: Enable Space metrics in DO console
9. Cost Estimation
Base Cost: $5/month includes:
- 250 GB storage
- 1 TB outbound transfer
Additional Costs:
- Storage: $0.02/GB/month above 250GB
- Transfer: $0.01/GB above 1TB
Example Scenarios:
- 100 installers × 50MB each = 5GB storage: $5/month
- 1000 downloads/month × 50MB = 50GB transfer: $5/month
- 10,000 downloads/month × 50MB = 500GB transfer: $5/month (within 1TB limit)
10. Monitoring & Maintenance
Check Space Usage:
const objects = await spacesService.listObjects('installers/');
console.log(`Total objects: ${objects.length}`);
Cleanup Old Installers:
// Keep last 5 versions per tenant
await spacesService.cleanupOldInstallers('tenant-123', 5);
Admin Endpoints:
- List installers: GET /api/download/admin/list-installers/:tenantId
- Cleanup: POST /api/download/admin/cleanup-installers/:tenantId
11. Troubleshooting
Issue: Uploads fail with "Access Denied"
- Solution: Verify API keys are correct and have Spaces permissions
Issue: Signed URLs don't work
- Solution: Check Space is not set to public file listing
Issue: Slow downloads
- Solution: Ensure CDN is enabled and using correct endpoint
Issue: High bandwidth costs
- Solution: Increase signed URL cache time, enable browser caching
12. Rollback Plan
If issues occur:
- Set USE_DO_SPACES=false in environment
- Restart backend
- System reverts to serving from local storage
- No data loss (local files still exist if CLEANUP_AFTER_UPLOAD=false)
Integration Complete!
Your installer serving is now: ✅ Scalable to millions of downloads ✅ CDN-accelerated globally ✅ Secure with time-limited access ✅ Cost-effective at $5/month base ✅ Easy to maintain and monitor