12 KiB
DigitalOcean Spaces Setup (S3-Compatible Object Storage)
Audience: Junior DevOps Engineers, Infrastructure Team Time to Complete: 15-20 minutes Prerequisites: DigitalOcean account with billing enabled
Overview
This guide sets up DigitalOcean Spaces - an S3-compatible object storage service for storing files, uploads, and media for your MaplePress backend.
What You'll Build:
- DigitalOcean Space (bucket) for file storage
- API keys (access key + secret key) for programmatic access
- Docker Swarm secrets for secure credential storage
- Configuration ready for backend integration
Why DigitalOcean Spaces?
- S3-compatible API (works with AWS SDK)
- Simple pricing: $5/mo for 250GB + 1TB transfer
- CDN included (speeds up file delivery globally)
- No egress fees within same region
- Integrated with your existing DigitalOcean infrastructure
Table of Contents
- Create DigitalOcean Space
- Generate API Keys
- Create Docker Secrets
- Verify Configuration
- Test Access
- Troubleshooting
Step 1: Create DigitalOcean Space
1.1 Create Space via Dashboard
- Log into DigitalOcean dashboard: https://cloud.digitalocean.com
- Click Manage → Spaces Object Storage in left sidebar
- Click Create a Space
- Configure:
- Choose a datacenter region: Select same region as your droplets (e.g.,
NYC3orToronto) - Enable CDN: ✅ Yes (recommended - improves performance globally)
- Choose a unique name:
maplepress(must be globally unique) - Select a project: Your project (e.g., "MaplePress Production")
- Choose a datacenter region: Select same region as your droplets (e.g.,
- Click Create a Space
Expected output:
- Space created successfully
- You'll see the space URL:
https://maplepress.tor1.digitaloceanspaces.com
1.2 Record Space Information
Save these values (you'll need them later):
# Space Name
SPACE_NAME=maplepress
# Endpoint (without https://)
SPACE_ENDPOINT=tor1.digitaloceanspaces.com
# Region code
SPACE_REGION=tor1
# Full URL (for reference)
SPACE_URL=https://maplepress.tor1.digitaloceanspaces.com
Region codes for reference:
- Toronto:
tor1.digitaloceanspaces.com - San Francisco 3:
sfo3.digitaloceanspaces.com - Singapore:
sgp1.digitaloceanspaces.com - Amsterdam:
ams3.digitaloceanspaces.com - Frankfurt:
fra1.digitaloceanspaces.com
✅ Checkpoint: Space created and URL recorded
Step 2: Generate API Keys
2.1 Create Spaces Access Keys
- In DigitalOcean dashboard, go to API in left sidebar
- Scroll down to Spaces access keys section
- Click Generate New Key
- Configure:
- Name:
maplepress-backend-prod - Description: "Backend service access to Spaces" (optional)
- Name:
- Click Generate Key
⚠️ CRITICAL: The secret key is only shown once! Copy it immediately.
2.2 Save Credentials Securely
You'll see:
- Access Key:
DO00ABC123XYZ...(20 characters) - Secret Key:
abc123def456...(40 characters)
SAVE BOTH IN YOUR PASSWORD MANAGER NOW!
Example:
DigitalOcean Spaces - MaplePress Production
Access Key: DO00ABC123XYZ456
Secret Key: abc123def456ghi789jkl012mno345pqr678stu901
Endpoint: nyc3.digitaloceanspaces.com
Bucket: maplepress
2.3 Update Local .env File
On your local machine:
# Navigate to production infrastructure
cd ~/monorepo/cloud/infrastructure/production
# Edit .env file
vi .env
# Add these lines:
SPACES_ACCESS_KEY=DO00ABC123XYZ456
SPACES_SECRET_KEY=abc123def456ghi789jkl012mno345pqr678stu901
SPACES_ENDPOINT=tor1.digitaloceanspaces.com
SPACES_REGION=tor1
SPACES_BUCKET=maplepress
Save: Esc, :wq, Enter
✅ Checkpoint: API keys saved securely in password manager and .env file
Step 3: Create Docker Secrets
On manager node:
# SSH to manager
ssh dockeradmin@<manager-public-ip>
3.1 Create Spaces Access Key Secret
# Create secret for access key
echo -n "DO00ABC123XYZ456" | docker secret create spaces_access_key -
# Verify
docker secret ls | grep spaces_access_key
# Should show: spaces_access_key About a minute ago
Important: Replace DO00ABC123XYZ456 with your actual access key!
3.2 Create Spaces Secret Key Secret
# Create secret for secret key
echo -n "abc123def456ghi789jkl012mno345pqr678stu901" | docker secret create spaces_secret_key -
# Verify
docker secret ls | grep spaces_secret_key
# Should show: spaces_secret_key About a minute ago
Important: Replace with your actual secret key!
3.3 Verify All Secrets
# List all secrets
docker secret ls
You should see:
ID NAME CREATED
abc123... maplepress_jwt_secret from 05_backend.md
abc124... maplepress_ip_encryption_key from 05_backend.md
def456... redis_password from 03_redis.md
ghi789... meilisearch_master_key from 04_meilisearch.md
jkl012... spaces_access_key NEW!
mno345... spaces_secret_key NEW!
✅ Checkpoint: All secrets created successfully
Step 4: Verify Configuration
4.1 Test Space Access from Local Machine
Install AWS CLI (if not already installed):
# On your local machine (Mac)
brew install awscli
# Or on Linux:
sudo apt install awscli
Configure AWS CLI for DigitalOcean Spaces:
# Create AWS credentials file
mkdir -p ~/.aws
vi ~/.aws/credentials
# Add this profile:
[digitalocean]
aws_access_key_id = DO00ABC123XYZ456
aws_secret_access_key = abc123def456ghi789jkl012mno345pqr678stu901
Save: Esc, :wq, Enter
4.2 Test Listing Space Contents
# List contents of your space
aws s3 ls s3://maplepress \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean
# Should show empty (new space) or list existing files
4.3 Test File Upload
# Create test file
echo "Hello from MaplePress!" > test-file.txt
# Upload to space
aws s3 cp test-file.txt s3://maplepress/test-file.txt \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean \
--acl public-read
# Should show: upload: ./test-file.txt to s3://maplepress/test-file.txt
4.4 Test File Download
# Download from space
aws s3 cp s3://maplepress/test-file.txt downloaded-test.txt \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean
# Verify content
cat downloaded-test.txt
# Should show: Hello from MaplePress!
# Clean up
rm test-file.txt downloaded-test.txt
4.5 Test Public URL Access
# Try accessing via browser or curl
curl https://maplepress.tor1.digitaloceanspaces.com/test-file.txt
# Should show: Hello from MaplePress!
✅ Checkpoint: Successfully uploaded, listed, downloaded, and accessed file
Step 5: Test Access
5.1 Verify Endpoint Resolution
# Test DNS resolution
dig tor1.digitaloceanspaces.com +short
# Should return IP addresses (e.g., 192.81.xxx.xxx)
5.2 Test HTTPS Connection
# Test SSL/TLS connection
curl -I https://tor1.digitaloceanspaces.com
# Should return:
# HTTP/2 403 (Forbidden is OK - means endpoint is reachable)
5.3 Check Space Permissions
- Go to DigitalOcean dashboard → Spaces
- Click on your space (
maplepress) - Click Settings tab
- Check File Listing: Should be ❌ Restricted (recommended for security)
- Individual files can be made public via ACL when uploading
✅ Checkpoint: Spaces endpoint is accessible and working
Troubleshooting
Problem: "Space name already exists"
Symptom: Can't create space with chosen name
Cause: Space names are globally unique across all DigitalOcean customers
Solution:
Try these naming patterns:
maplepress-<your-company>maplepress-<random-string>mp-prod-<date>(e.g.,mp-prod-2025)
Check availability by trying different names in the creation form.
Problem: "Access Denied" When Testing
Symptom: AWS CLI returns AccessDenied error
Causes and Solutions:
-
Wrong credentials:
# Verify credentials in ~/.aws/credentials match DigitalOcean dashboard cat ~/.aws/credentials -
Wrong endpoint:
# Make sure endpoint matches your space region # NYC3: nyc3.digitaloceanspaces.com # SFO3: sfo3.digitaloceanspaces.com -
Wrong bucket name:
# Verify bucket name matches space name exactly aws s3 ls --endpoint-url https://tor1.digitaloceanspaces.com --profile digitalocean # Should list your space
Problem: "NoSuchBucket" Error
Symptom: AWS CLI says bucket doesn't exist
Check:
# List all spaces in your account
aws s3 ls --endpoint-url https://tor1.digitaloceanspaces.com --profile digitalocean
# Make sure your space appears in the list
If space is missing:
- Check you're in the correct DigitalOcean account
- Check space wasn't accidentally deleted
- Check endpoint URL matches space region
Problem: Files Not Publicly Accessible
Symptom: Get 403 Forbidden when accessing file URL
Cause: File ACL is private (default)
Solution:
# Upload with public-read ACL
aws s3 cp file.txt s3://maplepress/file.txt \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean \
--acl public-read
# Or make existing file public
aws s3api put-object-acl \
--bucket maplepress \
--key file.txt \
--acl public-read \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean
Note: Your backend will control ACLs programmatically. Public access should only be granted to files that need to be publicly accessible (e.g., user-uploaded images for display).
Problem: CDN Not Working
Symptom: Files load slowly or CDN URL doesn't work
Check:
-
Verify CDN is enabled:
- DigitalOcean dashboard → Spaces → Your space → Settings
- CDN should show: ✅ Enabled
-
Use CDN URL instead of direct URL:
# Direct URL (slower): https://maplepress.tor1.digitaloceanspaces.com/file.txt # CDN URL (faster): https://maplepress.tor1.cdn.digitaloceanspaces.com/file.txt -
Clear CDN cache if needed:
- Spaces → Your space → Settings → CDN
- Click Purge Cache
Problem: High Storage Costs
Symptom: Unexpected charges for Spaces
Check:
# Calculate total space usage
aws s3 ls s3://maplepress --recursive --human-readable --summarize \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean
# Shows: Total Size: X.XX GB
Pricing reference:
- $5/mo includes 250GB storage + 1TB outbound transfer
- Additional storage: $0.02/GB per month
- Additional transfer: $0.01/GB
Optimization tips:
- Delete old/unused files regularly
- Use CDN to reduce direct space access
- Compress images before uploading
- Set up lifecycle policies to auto-delete old files
Next Steps
✅ You now have:
- DigitalOcean Space created and configured
- API keys generated and secured
- Docker Swarm secrets created
- Verified access from local machine
Next guide:
- 05_backend.md - Deploy MaplePress backend
- Backend will use these Spaces credentials automatically
- Files uploaded via backend API will be stored in your Space
Space Configuration for Backend:
The backend will use these environment variables (configured in 05_backend.md):
environment:
- AWS_ACCESS_KEY_FILE=/run/secrets/spaces_access_key
- AWS_SECRET_KEY_FILE=/run/secrets/spaces_secret_key
- AWS_ENDPOINT=https://tor1.digitaloceanspaces.com
- AWS_REGION=tor1
- AWS_BUCKET_NAME=maplepress
Useful Commands:
# List all files in space
aws s3 ls s3://maplepress --recursive \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean
# Get space size
aws s3 ls s3://maplepress --recursive --summarize \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean
# Delete test file
aws s3 rm s3://maplepress/test-file.txt \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean
# Sync local directory to space
aws s3 sync ./local-folder s3://maplepress/uploads/ \
--endpoint-url https://tor1.digitaloceanspaces.com \
--profile digitalocean
Last Updated: January 2025 Maintained By: Infrastructure Team
Changelog:
- January 2025: Initial DigitalOcean Spaces setup guide for MaplePress production deployment