Report this

What is the reason for this report?

Presigned URLs vs. Spaces CDN — can I get both private access and edge caching?

Posted on July 6, 2026

Hi all,

I’m building an image gallery app backed by DigitalOcean Spaces (bucket in fra1, CDN enabled). Public images work great through the CDN endpoint, but now I need to serve private images too.

My current approach is generating presigned URLs with the AWS SDK (v3, S3-compatible client) with a 15-minute expiry. That works, but two things bother me:

  1. Presigned URLs only work against the origin endpoint (<bucket>.fra1.digitaloceanspaces.com), not the CDN endpoint (<bucket>.fra1.cdn.digitaloceanspaces.com) — so every request for a private image skips the CDN entirely. Is that expected, or is there a way to have the CDN honor presigned requests?
  2. Since each presigned URL has a unique query string, even if caching did work, wouldn’t every URL be a cache miss anyway?

What are people actually doing for this? Options I’m considering:

  • Keep objects private and just eat the origin latency for authenticated users
  • Proxy images through my backend and cache there (feels like I’m rebuilding a CDN)
  • Make objects public with obfuscated/unguessable keys and rely on the CDN (uneasy about security-by-obscurity)

App is a Node.js backend on a basic Droplet, images are 200 KB–2 MB, maybe 50k requests/day. Any patterns or gotchas would be appreciated. Thanks!



This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

Heya,

this is expected behavior, and your two problems are actually the same problem.

Presigned URLs are SigV4, and the signature covers the Host header. You signed for bucket.fra1.digitaloceanspaces.com, so when the request comes through the CDN hostname the signature doesn’t match. The CDN edge doesn’t validate signatures at all — only origin does. There’s no way around this on Spaces currently, the CDN has basically zero config (no custom cache keys, no edge auth).

And even if it did work, you answered your own question #2 — unique query string per user means every request is a cache miss. Presigned + CDN just don’t compose.

That said, 50k req/day is under 1 req/sec. You’re overthinking the origin latency part. If you go with presigned URLs, one trick makes them way better: don’t sign for “now + 15min”, sign for expiry rounded up to the next 15-minute clock boundary. That way everyone asking for the same image inside a window gets the same URL, and browser caching suddenly works. Set Cache-Control on the objects with a max-age shorter than the window and you’ve recovered most of what the CDN was giving you.

The unguessable-key option isn’t security by obscurity, for what it’s worth. A 128-bit random key in the path is exactly as hard to guess as a presigned URL signature — it’s the same entropy, just without an expiry. Slack served attachments this way for years. The actual tradeoffs are: leaked links work forever (until you delete/move the object), and anyone the user forwards a link to can see the image. Also make double sure listing is off on the bucket or the random keys are pointless. If your “private” just means “strangers shouldn’t stumble into these”, this is the easy answer and you keep the CDN.

If “private” means revocable, per-user access — proxy it. But don’t write the caching in Node, just put nginx in front with proxy_cache pointed at Spaces and auth_request to your app for the permission check. At your volume a basic droplet will be bored.

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Start building today

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.