home / skills / digitalocean-labs / do-app-platform-skills / spaces
This skill configures and manages DigitalOcean Spaces for App Platform apps, enabling secure uploads, static assets delivery, and per-app credential handling.
npx playbooks add skill digitalocean-labs/do-app-platform-skills --skill spacesReview the files below or copy the command above to add this skill to your agents.
---
name: spaces
version: 1.0.0
min_doctl_version: "1.82.0"
description: Configure DigitalOcean Spaces (S3-compatible object storage) for App Platform apps. Use when setting up file uploads, static assets, CDN, access logging, or per-app credential management.
related_skills: [designer]
deprecated: false
---
# Spaces Skill
S3-compatible object storage for App Platform applications.
## Tool Separation (Critical)
```
┌─────────────────────────────────────────────────────────────────┐
│ doctl: KEYS ONLY │ aws CLI: EVERYTHING ELSE │
│ • doctl spaces keys create│ • Bucket create/delete │
│ • doctl spaces keys list │ • Object upload/download │
│ • doctl spaces keys delete│ • CORS, logging, lifecycle │
└─────────────────────────────────────────────────────────────────┘
```
> **Why?** doctl's Spaces support is limited to key management. Bucket operations require S3-compatible tools.
---
## Quick Decision
```
┌─────────────────────────────────────────────────────────────────┐
│ What do you need to do with Spaces? │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
Create key Create bucket Upload/download
or rotate set CORS/logging objects
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ doctl │ │ aws CLI │ │ aws CLI │
│ spaces keys │ │ s3api │ │ s3 cp/sync │
└───────────────┘ └───────────────┘ └───────────────┘
```
---
## Prerequisites
```bash
doctl auth init # One-time DO API auth
aws --version # AWS CLI v2
jq --version # JSON processor
```
---
## Quick Start
### 1. Set Environment
```bash
# Choose region matching your App Platform app (see shared/regions.yaml)
export DO_SPACES_REGION="syd1"
export DO_SPACES_ENDPOINT="https://${DO_SPACES_REGION}.digitaloceanspaces.com"
export APP_NAME="myapp"
export BUCKET="${APP_NAME}-uploads"
export DO_SPACES_KEY_NAME="${APP_NAME}-spaces-key"
```
### 2. Create Key (doctl)
```bash
KEY_JSON=$(doctl spaces keys create "${DO_SPACES_KEY_NAME}" --output json)
export AWS_ACCESS_KEY_ID=$(echo "$KEY_JSON" | jq -r '.[0].access_key')
export AWS_SECRET_ACCESS_KEY=$(echo "$KEY_JSON" | jq -r '.[0].secret_key')
# IMPORTANT: Secret shown only once - save it now!
```
### 3. Create Bucket (aws CLI)
```bash
aws --endpoint-url "$DO_SPACES_ENDPOINT" s3api create-bucket --bucket "$BUCKET"
```
### 4. App Spec
```yaml
services:
- name: api
envs:
- key: SPACES_BUCKET
value: myapp-uploads
- key: SPACES_REGION
value: ${SPACES_REGION} # Your bucket's region
- key: SPACES_ENDPOINT
value: ${SPACES_ENDPOINT} # e.g., https://syd1.digitaloceanspaces.com
- key: SPACES_ACCESS_KEY
scope: RUN_TIME
type: SECRET
value: ${SPACES_ACCESS_KEY}
- key: SPACES_SECRET_KEY
scope: RUN_TIME
type: SECRET
value: ${SPACES_SECRET_KEY}
```
> Store `SPACES_ACCESS_KEY` and `SPACES_SECRET_KEY` in GitHub Secrets.
---
## Regions
Spaces uses different slugs than App Platform. See [shared/regions.yaml](../../shared/regions.yaml).
| App Platform | Spaces | Endpoint |
|--------------|--------|----------|
| `nyc` | `nyc3` | `https://nyc3.digitaloceanspaces.com` |
| `sfo` | `sfo3` | `https://sfo3.digitaloceanspaces.com` |
| `ams` | `ams3` | `https://ams3.digitaloceanspaces.com` |
| `lon` | `lon1` | `https://lon1.digitaloceanspaces.com` |
| `fra` | `fra1` | `https://fra1.digitaloceanspaces.com` |
| `tor` | `tor1` | `https://tor1.digitaloceanspaces.com` |
| `sgp` | `sgp1` | `https://sgp1.digitaloceanspaces.com` |
| `blr` | `blr1` | `https://blr1.digitaloceanspaces.com` |
| `syd` | `syd1` | `https://syd1.digitaloceanspaces.com` |
| `atl` | `atl1` | `https://atl1.digitaloceanspaces.com` |
---
## Common Operations
### doctl (Keys Only)
```bash
doctl spaces keys list
doctl spaces keys create "myapp-key" --output json
doctl spaces keys delete <key-id>
```
### aws CLI (Buckets & Objects)
```bash
EP="--endpoint-url https://syd1.digitaloceanspaces.com"
# Buckets
aws $EP s3 ls
aws $EP s3api create-bucket --bucket myapp-uploads
aws $EP s3 rb s3://myapp-uploads
# Objects
aws $EP s3 cp ./file.txt s3://myapp-uploads/path/file.txt
aws $EP s3 cp s3://myapp-uploads/path/file.txt ./file.txt
aws $EP s3 ls s3://myapp-uploads/ --recursive
aws $EP s3 sync ./local-dir/ s3://myapp-uploads/prefix/
```
---
## Scripts (AI-Friendly)
| Script | Purpose |
|--------|---------|
| `scripts/bootstrap_app_spaces.sh` | Full setup: key + buckets + logging |
| `scripts/enable_bucket_logging.sh` | Enable/verify logging (idempotent) |
| `scripts/view_access_logs.sh` | List/download access logs |
| `scripts/rotate_spaces_key.sh` | Rotate credentials safely |
```bash
# Set env vars then run
./scripts/bootstrap_app_spaces.sh
```
---
## Reference Files
| File | Content |
|------|---------|
| [aws-cli-operations.md](reference/aws-cli-operations.md) | Complete aws CLI reference |
| [key-management.md](reference/key-management.md) | Per-app keys, rotation workflow |
| [access-logging.md](reference/access-logging.md) | Bucket logging setup |
| [sdk-configuration.md](reference/sdk-configuration.md) | Node.js, Python, Go SDK setup |
| [troubleshooting.md](reference/troubleshooting.md) | Common errors and fixes |
---
## URL Patterns
| Type | Format |
|------|--------|
| Standard | `https://<bucket>.<region>.digitaloceanspaces.com/<key>` |
| CDN | `https://<bucket>.<region>.cdn.digitaloceanspaces.com/<key>` |
---
## Quick Troubleshooting
| Error | Fix |
|-------|-----|
| BucketAlreadyExists (409) | Use unique prefix: `mycompany-myapp-uploads` |
| Access Denied (403) | Verify keys, check endpoint matches bucket region |
| CORS error | Configure via `aws s3api put-bucket-cors` |
| SignatureDoesNotMatch | Use `https://` prefix, no trailing slash |
See [troubleshooting.md](reference/troubleshooting.md) for details.
---
## Integration
- **→ designer**: Includes Spaces env vars when architecting apps
- **→ deployment**: Credentials stored in GitHub Secrets
- **→ devcontainers**: MinIO provides local Spaces parity
This skill configures DigitalOcean Spaces (S3-compatible object storage) for App Platform applications. It guides you through key creation, bucket management, environment variable configuration, and common workflows like uploads, CDN usage, and access logging. The guidance separates tools: use doctl for key management and the AWS CLI for bucket and object operations. It is focused on per-app credential management and operational best practices.
The skill uses doctl to create and rotate Spaces access keys, then uses the AWS CLI (with a Spaces endpoint) for bucket creation, CORS, logging, lifecycle rules, and object transfers. It provides environment variable shapes and App Platform spec fragments for injecting bucket names, endpoints, and runtime secrets into services. Scripts and CI guidance automate bootstrapping, logging enablement, and safe key rotation.
Why use doctl and AWS CLI together?
doctl supports key management only; S3-compatible bucket and object operations require an S3-aware tool like the AWS CLI configured with the Spaces endpoint.
How do I avoid SignatureDoesNotMatch and Access Denied errors?
Ensure the endpoint matches the bucket region, include the https:// prefix with no trailing slash, and verify keys are correct and scoped to the app.