Overview
DigitalOcean Spaces provides S3-compatible object storage with integrated CDN. This guide will help you set up and configure Spaces for WordPress static assets.
Prerequisites
- DigitalOcean account with Spaces enabled
- Access to DigitalOcean API token
- WordPress sites on DO App Platform
Step 1: Create or Verify Spaces Bucket
Via DigitalOcean Console
- Go to DigitalOcean Spaces
- Check if bucket exists (user mentioned "it's empty")
- Note the bucket name and region
- Enable CDN if not already enabled
Via doctl CLI
# List existing spaces (requires doctl authentication)
doctl spaces list-buckets
# Create a new space if needed
doctl spaces create wordpress-assets --region nyc3
# Enable CDN
doctl spaces cdn enable wordpress-assets
Step 2: Install and Configure s3cmd
s3cmd is a command-line tool for managing S3-compatible storage.
Install s3cmd
# Fedora/RHEL
sudo dnf install s3cmd
# Ubuntu/Debian
sudo apt install s3cmd
# Or via pip
pip install s3cmd
Configure s3cmd for DigitalOcean Spaces
Configuration values:
Access Key: [Your DO Spaces Access Key]
Secret Key: [Your DO Spaces Secret Key]
Default Region: nyc3 (or your region)
S3 Endpoint: nyc3.digitaloceanspaces.com (replace nyc3 with your region)
DNS-style bucket+hostname:port template: %(bucket)s.nyc3.digitaloceanspaces.com
Encryption password: [Leave empty or set password]
Path to GPG program: [Leave empty]
Use HTTPS protocol: Yes
HTTP Proxy server name: [Leave empty]
Test configuration:
Step 3: Create Spaces Access Keys
- Go to API Tokens
- Scroll to Spaces access keys
- Click Generate New Key
- Save the Access Key and Secret Key (shown only once!)
Step 4: Sync WordPress Assets to Spaces
Option A: Manual Sync with s3cmd
# Sync wp-content/uploads from a WordPress site
s3cmd sync /path/to/wordpress/wp-content/uploads/ s3://bucket-name/wp-content/uploads/
# Example for specific site
s3cmd sync ~/wordpress-sites/performwrite/wp-content/uploads/ s3://wordpress-assets/performwrite/uploads/
# Sync with public read permissions
s3cmd sync --acl-public /path/to/wordpress/wp-content/uploads/ s3://wordpress-assets/uploads/
Option B: Automated Sync Script
Create /home/cw/Documents/IBG_HUB/rmm-psa-devops/scripts/sync-wordpress-assets.sh:
#!/bin/bash
BUCKET="wordpress-assets"
REGION="nyc3"
declare -A sites=(
["performwritecom"]="/path/to/performwrite/wp-content/uploads"
["soilife"]="/path/to/soilife/wp-content/uploads"
# Add all 16 sites
)
for site in "${!sites[@]}"; do
echo "Syncing $site to Spaces..."
s3cmd sync --acl-public "${sites[$site]}/" "s3://$BUCKET/$site/uploads/"
done
echo "✅ All assets synced to DigitalOcean Spaces"
Step 5: Configure WordPress to Use CDN
Option 1: Using Environment Variables (Recommended)
Add to wp-config.php:
if (getenv('DO_SPACES_BUCKET')) {
$cdn_endpoint = getenv('DO_SPACES_CDN_ENDPOINT');
define('WP_CONTENT_URL', $cdn_endpoint . '/wp-content');
define('UPLOADS', 'wp-content/uploads');
}
Set in DO App Platform environment variables:
Option 2: Hardcode in wp-config.php
define('WP_CONTENT_URL', 'https://wordpress-assets.nyc3.cdn.digitaloceanspaces.com/performwrite/wp-content');
define('UPLOADS', 'wp-content/uploads');
Option 3: Use WordPress Plugin
WP Offload Media Lite (Supports DigitalOcean Spaces)
- Install plugin: wp plugin install amazon-s3-and-cloudfront --activate
- Go to Settings → Offload Media
- Choose "DigitalOcean Spaces"
- Enter:
- Bucket: wordpress-assets
- Region: nyc3
- Access Key: [Your key]
- Secret Key: [Your secret]
- Enable "Rewrite Media URLs" to use CDN
Step 6: Configure CORS (If Needed)
Create cors.xml:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Apply CORS:
s3cmd setcors cors.xml s3://wordpress-assets
Step 7: Set Cache-Control Headers
# Set cache headers for images (1 year)
s3cmd modify --recursive --add-header="Cache-Control:public, max-age=31536000" s3://wordpress-assets/
# For specific file types
s3cmd modify --recursive --add-header="Cache-Control:public, max-age=31536000" --include='*.jpg' s3://wordpress-assets/
s3cmd modify --recursive --add-header="Cache-Control:public, max-age=31536000" --include='*.png' s3://wordpress-assets/
s3cmd modify --recursive --add-header="Cache-Control:public, max-age=31536000" --include='*.gif' s3://wordpress-assets/
Step 8: Test CDN Delivery
- Upload a test image to WordPress
- Check if it's synced to Spaces
- Verify CDN URL is being used:
curl -I https://wordpress-assets.nyc3.cdn.digitaloceanspaces.com/performwrite/uploads/test-image.jpg
- Confirm cache headers are present
WordPress to Spaces Migration Plan
For Each of 16 Sites:
- Identify uploads directory on current cPanel hosting
- Download/export all wp-content/uploads
- Upload to Spaces using s3cmd sync
- Update wp-config.php to use CDN URLs
- Test image loading
- Set up automatic sync for new uploads
Estimated Data:
Based on database sizes (soilife_wp is 339MB), uploads could be several GB per site.
# Example sync command
for site in performwrite soilife collegeo; do
s3cmd sync --acl-public /backup/wordpress/$site/uploads/ s3://wordpress-assets/$site/uploads/
done
Monitoring & Maintenance
Check Space Usage
# Via s3cmd
s3cmd du -H s3://wordpress-assets
# Via DO Console
# Go to Spaces → Click bucket → See usage stats
Automated Sync (Cron Job)
# Add to crontab
0 2 * * * /home/cw/Documents/IBG_HUB/rmm-psa-devops/scripts/sync-wordpress-assets.sh >> /var/log/spaces-sync.log 2>&1
Pricing Estimate
DigitalOcean Spaces pricing (as of 2026):
- Storage: $5/month for 250GB
- Transfer: $1/GB outbound (first 1TB free with $12/month plan)
For 16 WordPress sites with ~10GB average uploads:
- Total storage: ~160GB
- Cost: $5/month (within free tier)
- Additional storage: $0.02/GB/month
Troubleshooting
Access Denied Errors
- Check Spaces access keys are correct
- Verify bucket permissions (should be public for CDN)
- Confirm CORS is configured if using AJAX
Images Not Loading from CDN
- Check file exists: s3cmd ls s3://bucket-name/path/to/file.jpg
- Verify file is public: s3cmd info s3://bucket-name/path/to/file.jpg
- Check CDN endpoint is correct
- Clear browser cache
Sync Issues
- Ensure s3cmd is configured correctly
- Check network connectivity
- Verify write permissions on local directories
- Use --verbose flag for debugging: s3cmd sync --verbose ...
Security Best Practices
- Rotate access keys regularly
- Use bucket policies to restrict access
- Enable versioning for important assets
- Monitor usage to detect anomalies
- Use signed URLs for private content
Next Steps
- Create or verify DO Spaces bucket
- Install and configure s3cmd
- Export WordPress uploads from cPanel
- Update wp-config.php files with CDN URLs
- Monitor usage and performance
Resources
Last Updated: February 17, 2026