speak-mintlify uploads generated audio files to S3-compatible storage for efficient delivery. This guide covers setup for AWS S3, Cloudflare R2, and self-hosted MinIO.
Storage Providers Overview
AWS S3
Cloudflare R2
MinIO
AWS S3 Setup
Create an S3 bucket
- Log in to AWS Console
- Click Create bucket
- Choose a unique bucket name (e.g.,
my-docs-audio) - Select a region close to your users (e.g.,
us-east-1) - Uncheck “Block all public access” (we need public read access)
- Click Create bucket
Configure bucket policy
- Go to your bucket → Permissions → Bucket Policy
- Add this policy (replace
YOUR_BUCKET_NAME):
Create IAM user
- Go to IAM Console → Users
- Click Add users
- User name:
speak-mintlify-uploader - Select Access key - Programmatic access
- Click Next: Permissions
Attach permissions
Configure environment variables
.env file:Optional: CloudFront CDN
For better performance, serve audio through CloudFront:Create CloudFront distribution
- Go to CloudFront Console
- Click Create distribution
- Origin domain: Select your S3 bucket
- Origin access: Legacy access identities → Create new OAI
- Viewer protocol policy: Redirect HTTP to HTTPS
- Click Create distribution
Update bucket policy
Update S3_PUBLIC_URL
Cloudflare R2 Setup
Cloudflare R2 offers zero egress fees and is more cost-effective for high-traffic sites.Create R2 bucket
- Log in to Cloudflare Dashboard
- Go to R2 from the sidebar
- Click Create bucket
- Enter bucket name (e.g.,
docs-audio) - Choose a location hint (optional)
- Click Create bucket
Enable public access
- Go to your bucket → Settings
- Scroll to Public access
- Click Allow Access and confirm
- Copy the Public bucket URL (e.g.,
https://pub-abc123.r2.dev)
Create API token
- Go to R2 → Manage R2 API Tokens
- Click Create API token
- Token name:
speak-mintlify - Permissions: Object Read & Write
- (Optional) Apply to specific buckets only
- Click Create API token
- Save the Access Key ID and Secret Access Key
Configure environment variables
.env file:<account_id> with your Cloudflare account ID (found in R2 settings).Custom Domain for R2
Use your own domain for cleaner URLs:Add custom domain
- Go to your R2 bucket → Settings → Custom Domains
- Click Connect domain
- Enter your domain (e.g.,
audio.docs.com) - Follow DNS setup instructions
Update S3_PUBLIC_URL
MinIO Setup (Self-Hosted)
MinIO is perfect for self-hosted or on-premise deployments.Install MinIO
- Docker
- Binary
- Kubernetes
Create bucket
- Access MinIO Console at
http://localhost:9001 - Login with root credentials
- Go to Buckets → Create Bucket
- Bucket name:
docs-audio - Click Create Bucket
Set bucket to public
- Go to your bucket → Anonymous → Add Access Rule
- Prefix:
*(all objects) - Access: readonly
- Click Add
Create access key
- Go to Access Keys → Create access key
- Copy the Access Key and Secret Key
- Click Create
Configure environment variables
Testing Your Setup
Verify your storage configuration works:- Files upload successfully
- Public URLs are accessible
- Audio plays in your browser
- Cleanup correctly identifies orphaned files
Environment Variables Reference
- AWS S3:
https://bucket.s3.region.amazonaws.com - CloudFront:
https://d123.cloudfront.net - R2:
https://pub-abc.r2.dev - MinIO:
https://minio.example.com/bucket
auto for R2)- R2:
https://abc123.r2.cloudflarestorage.com - MinIO:
https://minio.example.com - Not needed for AWS S3
Troubleshooting
Upload fails with 403 Forbidden
Upload fails with 403 Forbidden
- Check IAM user has
s3:PutObjectpermission - Verify bucket name in IAM policy matches actual bucket
- Ensure access keys are correct
- Verify API token has “Object Read & Write” permissions
- Check token is applied to correct bucket
- Ensure endpoint URL includes account ID
- Check access key has write permissions
- Verify bucket policy allows uploads
- Check MinIO server is running
Public URLs return 403 or 404
Public URLs return 403 or 404
- AWS S3: Verify bucket policy allows public read
- R2: Ensure “Allow Access” is enabled
- MinIO: Check anonymous access rules
- Remove trailing slashes from
S3_PUBLIC_URL - Verify bucket name is correct
- Test URL directly in browser
CORS errors in browser
CORS errors in browser
Connection timeout to S3_ENDPOINT
Connection timeout to S3_ENDPOINT
- Verify endpoint URL is correct (including protocol)
- Check firewall/security groups allow connections
- For MinIO, ensure server is accessible from CI/CD
- Test with
curloraws s3 ls
Files uploaded but not accessible
Files uploaded but not accessible
- Check
S3_PUBLIC_URLmatches actual public URL - Verify content-type is set correctly (
audio/mpeg) - Check bucket/object ACLs (legacy AWS S3)
- Test URL in incognito/private browser
Best Practices
Use separate buckets
Enable versioning
Set lifecycle policies
Monitor costs
Use CDN
Secure credentials
Cost Optimization
- AWS S3
- Cloudflare R2
- MinIO
- Storage: ~$0.023/GB/month (Standard)
- Bandwidth: $0.09/GB egress (first 10TB/month)
- Requests: Minimal cost for PUT/GET
- Use S3 Intelligent-Tiering for infrequently accessed files
- Enable CloudFront to reduce egress costs
- Set lifecycle rules to delete old versions
