Cloud Storage Configuration Guide
Multi-Cloud Storage Configuration with One-Click Switching
Supported Services · Environment Variables · Usage · API Endpoints
🎯 Overview
This project supports multiple cloud storage providers. Switch between them by simply changing the CDN_MODE environment variable - no code changes required.
☁️ Supported Storage Services
| CDN_MODE | Provider | Use Case | S3 Compatible |
|---|---|---|---|
r2 | Cloudflare R2 | Global users, zero egress fees | ✅ |
s3 | AWS S3 | Global users, native AWS | ✅ |
aliyun | Alibaba Cloud OSS | China users | ❌ |
qiniu | Qiniu Cloud Storage | China users | ❌ |
For global users, Cloudflare R2 is recommended - zero egress fees and global CDN acceleration. For users in China, Alibaba Cloud OSS is recommended.
🔧 Environment Variables
1. Cloudflare R2 (Recommended)
# Storage mode
CDN_MODE=r2
# R2 Configuration
R2_ACCOUNT_ID=your_cloudflare_account_id
R2_ACCESS_KEY_ID=your_r2_access_key_id
R2_SECRET_ACCESS_KEY=your_r2_secret_access_key
R2_BUCKET_NAME=your_bucket_name
R2_PUBLIC_URL=https://your-custom-domain.com
# R2_ENDPOINT=https://xxx.r2.cloudflarestorage.com # Optional, auto-generated by defaultHow to obtain:
- Log in to Cloudflare Dashboard
- Go to R2 → Create bucket
- Go to R2 → Manage R2 API Tokens → Create API Token
- Select permissions: Object Read and Write
- Configure custom domain or use public access domain
2. AWS S3
# Storage mode
CDN_MODE=s3
# S3 Configuration
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your_aws_access_key_id
S3_SECRET_ACCESS_KEY=your_aws_secret_access_key
S3_BUCKET_NAME=your_bucket_name
S3_PUBLIC_URL=https://your-custom-domain.com # Optional, defaults to S3 URL
# S3_ENDPOINT=https://s3.amazonaws.com # Optional, for S3-compatible servicesHow to obtain:
- Log in to AWS Console
- Create an S3 bucket and configure public access
- Create an IAM user and obtain Access Key
- Configure IAM policy to allow S3 operations
3. Alibaba Cloud OSS
# Storage mode
CDN_MODE=aliyun
# Alibaba Cloud OSS Configuration
ALIYUN_OSS_REGION=oss-cn-hangzhou
ALIYUN_OSS_ACCESS_KEY_ID=your_aliyun_access_key_id
ALIYUN_OSS_ACCESS_KEY_SECRET=your_aliyun_access_key_secret
ALIYUN_OSS_BUCKET=your_bucket_name
ALIYUN_OSS_PUBLIC_URL=https://your-custom-domain.com # Optional, defaults to OSS domain
# ALIYUN_OSS_INTERNAL=true # Optional, enable for ECS internal network accessCommon Region Codes:
| Region Code | Location |
|---|---|
oss-cn-hangzhou | East China 1 (Hangzhou) |
oss-cn-shanghai | East China 2 (Shanghai) |
oss-cn-qingdao | North China 1 (Qingdao) |
oss-cn-beijing | North China 2 (Beijing) |
oss-cn-shenzhen | South China 1 (Shenzhen) |
oss-cn-hongkong | Hong Kong |
For more regions, refer to Alibaba Cloud Documentation
How to obtain:
- Log in to Alibaba Cloud Console
- Create a Bucket and configure read/write permissions
- Create AccessKey in RAM Access Control
- Configure custom domain (optional)
4. Qiniu Cloud Storage
# Storage mode
CDN_MODE=qiniu
# Qiniu Configuration
QINIU_ACCESS_KEY=your_qiniu_access_key
QINIU_SECRET_KEY=your_qiniu_secret_key
QINIU_BUCKET=your_bucket_name
QINIU_PUBLIC_URL=https://your-cdn-domain.com
# QINIU_ZONE=z0 # Optional, storage zoneStorage Zone Codes:
| Code | Region |
|---|---|
z0 | East China |
z1 | North China |
z2 | South China |
na0 | North America |
as0 | Southeast Asia |
How to obtain:
- Log in to Qiniu Console
- Go to Object Storage → Create Space
- Get AccessKey/SecretKey in Key Management
- Bind CDN accelerated domain
📖 Usage
Switching Storage Services
Simply modify the CDN_MODE environment variable to switch storage services:
# Switch to Alibaba Cloud OSS
CDN_MODE=aliyun
# Switch to Cloudflare R2
CDN_MODE=r2All upload and delete operations will automatically use the corresponding storage service - no code changes needed.
Using in Code
import {
checkStorageConfig,
uploadToStorage,
deleteFromStorage,
getStorageMode,
} from '@/lib/upload';
// Check configuration
const config = checkStorageConfig();
console.log('Current storage provider:', config.provider);
// Upload file
const result = await uploadToStorage({
body: buffer,
key: 'images/photo.jpg',
contentType: 'image/jpeg',
});
// Delete file
await deleteFromStorage('images/photo.jpg');📡 API Endpoints
Get Storage Configuration Info
GET /api/uploadResponse Example:
{
"configured": true,
"provider": "aliyun",
"types": {
"image": { "maxSize": 5242880, "accept": ["image/jpeg", "image/png", "image/gif", "image/webp"] },
"video": { "maxSize": 104857600, "accept": ["video/mp4", "video/webm"] },
"document": { "maxSize": 10485760, "accept": ["application/pdf"] }
}
}Upload File
POST /api/upload
Content-Type: multipart/form-data
file: (binary)
type: image # Optional: image, video, document
path: uploads/ # Optional: custom path prefixResponse Example:
{
"success": true,
"url": "https://your-domain.com/uploads/abc123.jpg",
"key": "uploads/abc123.jpg"
}📦 Installing Dependencies
Install the corresponding SDK based on the storage service you're using:
# R2/S3 (installed by default)
npm install @aws-sdk/client-s3
# Alibaba Cloud OSS
npm install ali-oss
# Qiniu Cloud
npm install qiniu⚠️ Important Notes
Data Migration: After switching storage services, existing files will NOT be automatically migrated. Manual handling is required.
| Item | Description |
|---|---|
| Data Migration | Existing files won't auto-migrate when switching services |
| URL Changes | File URLs will change after switching; update database references |
| Permission Config | Ensure bucket has correct public read permissions |
| CORS Config | If uploading directly from frontend, configure bucket CORS rules |
CORS Configuration Example
If you need to upload directly from the frontend to the storage service, configure CORS in the bucket:
{
"AllowedOrigins": ["https://your-domain.com"],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3000
}