Moving User Uploads to DigitalOcean Spaces with S3‑Compatible Tooling
Learn how to move user uploads off Droplet disks to DigitalOcean Spaces using its S3‑compatible API and optional CDN, with a step‑by‑step example and verification checklist.
07 Oct 2026, 05:39 UTC

Problem: Local Disk Coupling Creates Risk
When user‑generated files are written directly to a Droplet’s local filesystem, the data lives on a single virtual machine. Destroying, rebuilding, or vertically resizing that Droplet can lead to irreversible loss unless you first copy the files elsewhere. This tight coupling also makes scaling storage independently of compute difficult.
Thesis: Use DigitalOcean Spaces as an S3‑compatible object store, optionally fronted by its built‑in CDN, to decouple uploads from Droplets while keeping existing S3 tooling.
Why Spaces Fits the Workflow
- Spaces exposes an S3‑compatible API, so tools like
aws cli,boto3, ors3cmdwork after you change only the endpoint URL and access keys. - Buckets are regional resources; you pick the datacenter closest to your users for lower latency.
- Access keys are scoped per Space, limiting the blast radius compared with a cloud‑wide credential.
- The optional CDN adds an edge‑cached hostname and lets you attach a custom subdomain with a managed TLS certificate.
Worked Example: Create a Space, Test S3 Compatibility, Enable CDN
Prerequisites: a DigitalOcean Personal Access Token with read/write scope, doctl installed, and the AWS CLI configured for a custom endpoint.
- Create a Space in the desired region (e.g.,
nyc3).# Replace $TOKEN with your personal access token doctl spaces create my-user-uploads --region nyc3 - Generate access keys** for that Space (shown in the control panel or via
doctl spaces key-list). Save theAccess KeyandSecret Key. - Configure AWS CLI** to point at the Space endpoint.
aws configure set spaces.endpoint_url https://nyc3.digitaloceanspaces.com aws configure set aws_access_key_id YOUR_ACCESS_KEY aws configure set aws_secret_access_key YOUR_SECRET_KEY # Optional: set a default region (not used by Spaces but required by the CLI) aws configure set region us-east-1- Upload a test file** and verify you can download it.
aws s3 cp ./test-image.jpg s3://my-user-uploads/test-image.jpg # Expected: upload progress and "upload: ./test-image.jpg to s3://my-user-uploads/test-image.jpg" # Download to a temporary location mkdir -p /tmp/dl && aws s3 cp s3://my-user-uploads/test-image.jpg /tmp/dl/ # Check file integrity (e.g., compare checksums)- Enable the CDN** on the Space via the control panel or
doctl.doctl spaces cdn enable my-user-uploads # The command returns an edge hostname like my-user-uploads.nyc3.cdn.digitaloceanspaces.com- Add a custom subdomain** (e.g.,
assets.example.com) and request a TLS certificate through the control panel. After the certificate is issued, CNAME your subdomain to the edge hostname.- Verify edge caching** by making two requests and inspecting the
Ageheader.curl -I https://assets.example.com/test-image.jpg # First request: Age: 0 (or missing) # Second request (within TTL): Age: non‑zero, indicating a cached response - Upload a test file** and verify you can download it.
Trade‑offs and Limitations
- No automatic cross‑region replication. If you need disaster recovery across regions, you must copy objects yourself (e.g., via a cron job using
aws s3 syncto a second Space). - CDN stale‑content risk. Replacing an object with the same key serves the old version until the TTL expires or you purge the cache. You can purge via the control panel or
doctl spaces cdn purge --key test-image.jpg. - Egress metered separately** from Droplet bandwidth. High‑traffic sites should estimate CDN data transfer costs using DigitalOcean’s pricing page before committing.
- Feature parity** – Spaces implements a subset of the S3 API. Advanced features like S3 Object Lock, Intelligent‑Tiering, or certain CLI flags may be missing or behave differently. Consult the latest Spaces documentation for the exact supported actions.
Practical Verification Checklist
- Confirm the Space exists in the chosen region (
doctl spaces list). - Upload and download a test object with the AWS CLI; check that the ETag matches the local file’s MD5 (where applicable).
- After enabling CDN, request the object via the custom domain and verify the
Ageheader increases on subsequent requests. - Test a cache purge: update the object, purge the key, then confirm the new version is served (Age resets to near zero).
- Review your project’s egress usage in the DigitalOcean billing dashboard after a week of traffic to ensure cost expectations align.
Actionable Closing
Start by creating a low‑cost test Space in your preferred region, run the upload/download verification, and enable the CDN only after you’ve confirmed the workflow works with your existing S3‑compatible code. Use the verification checklist above to guard against stale caches and unexpected egress charges. Once validated, migrate your user‑upload path to point at the Space endpoint, rotate the old local‑disk cleanup scripts, and enjoy decoupled storage that scales independently of your Droplets.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.