Store Dreep media in your own Amazon S3 bucket

Create an S3 bucket, attach an IAM policy that allows s3:PutObject, s3:GetObject and s3:DeleteObject on its objects plus s3:ListBucket on the bucket, and generate an access key for that IAM user. In Dreep, open Settings, Storage, pick AWS S3 and enter the bucket name, region and keys. Dreep probes the bucket, then stores originals and variants there.

Where S3 sits in the request path

  1. Your backend

    Calls Dreep with the project API key

  2. Dreep

    Signs S3 requests with your IAM key

  3. Your S3 bucket

    Originals and variants

  4. Dreep CDN URL

    What your users load

S3 is only ever accessed by Dreep with the IAM key you provide. The bucket can keep Block Public Access switched on.

Connect S3 in five steps

You need an active Starter or Pro plan and an empty Dreep project. Do the AWS side first so the keys are ready.

  1. 1

    Create the bucket

    Create a general purpose bucket in the region closest to your users or your compliance boundary. Keep Block Public Access on and the default SSE-S3 encryption; neither gets in Dreep's way.

  2. 2

    Create an IAM user with the policy below

    Create a dedicated IAM user for Dreep, attach the inline policy from the next section with your bucket name, and nothing else. Never use root credentials or a key shared with other systems.

  3. 3

    Create an access key

    Generate an access key for that user (the 'application running outside AWS' use case). Copy the Access Key ID and Secret Access Key.

  4. 4

    Enter the details in Dreep

    In Settings, Storage, choose Connect Your Own Bucket, select AWS S3, and enter the bucket name, the bucket's region (for example eu-west-2) and both keys. There is no endpoint field for S3: Dreep builds https://s3.<region>.amazonaws.com from the region.

  5. 5

    Let Dreep probe and save

    Dreep puts and deletes an object named __dreep_byob_probe_test__ and lists the bucket's top-level prefixes. On success the keys are encrypted with AES-256-GCM and every new upload in the project goes to S3.

The least-privilege IAM policy

These four actions are the full set of S3 calls Dreep makes against a connected bucket. Replace acme-media with your bucket name.

dreep-byob-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DreepObjects",
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::acme-media/*"
    },
    {
      "Sid": "DreepList",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::acme-media"
    }
  ]
}
IAM actionWhy Dreep needs it
s3:PutObjectWriting the probe object, every original and every generated variant.
s3:GetObjectStreaming originals and cached variants. Also authorises HeadObject, used to check whether a variant already exists.
s3:DeleteObjectRemoving the probe object and deleting assets you delete in Dreep.
s3:ListBucketListing prefixes when you test the connection. Without it, S3 answers HeadObject on a missing key with 403 instead of 404, which Dreep treats as a storage failure rather than 'not generated yet'.
  • Using SSE-KMS with a customer managed key? Also allow kms:GenerateDataKey and kms:Decrypt on that key, or writes and reads will be denied.
  • The dashboard has an optional CORS check that calls GetBucketCors. Add s3:GetBucketCORS on the bucket ARN only if you want that check to work; uploads don't need it.

Fields, rules and limits

ItemDetail
Bucket NameExact S3 bucket name, not an ARN or URL.
RegionThe bucket's region code. A wrong region returns 'Bucket region mismatch'.
Access Key ID / SecretFrom the dedicated IAM user. Stored encrypted, bound to the project.
PlanStarter ($2.99/mo) or Pro ($5.99/mo), with an active subscription.
Project stateMust be empty: connect before the first image or file is uploaded.
Changing bucketsNot possible once connected. Use a new project for a new bucket.
CORSNot needed for uploads. Browsers PUT to Dreep's upload URL on cdn.dreep.cloud, and Dreep writes to S3 server-side.

What appears in the bucket

Originals are written under projects/<project-slug>/<folder-path>/originals/<asset-id>/<filename>, and generated variants (resized and converted images, video renditions) under transforms/<content-hash>/<params-hash>.<ext>. Treat both prefixes as Dreep-managed: S3 lifecycle rules that delete or transition objects to Glacier classes under them will break delivery for those assets.

Server-side upload, now backed by S3

A direct upload from your backend, with a transform applied before storage. The stored result lands in your bucket; the URL is still a Dreep CDN URL.

import fs from "node:fs";
import { Dreep } from "dreep";

const dreep = new Dreep({ apiKey: process.env.DREEP_API_KEY });

const asset = await dreep.upload({
  file: fs.createReadStream("invoice-scan.png"),
  folder: "receipts/2026",
  transform: { width: 1600, format: "webp", quality: 82 },
});

asset.url; // Dreep CDN URL, bytes stored in your S3 bucket

Troubleshooting

ErrorUsual cause on AWSFix
BYOB_CONNECTION_FAILEDAccessDenied, InvalidAccessKeyId or SignatureDoesNotMatch on the probe: wrong key, policy not attached, or bucket name typo in the ARN.Check the policy ARNs match the bucket exactly, including the /* on the object statement.
Bucket region mismatchS3 returned a 301 redirect because the bucket lives in another region.Enter the region shown on the bucket's properties page.
BYOB_PLAN_UPGRADE_REQUIREDProject is on Free or the subscription isn't active.Upgrade to Starter or Pro.
BYOB_PROJECT_NOT_EMPTYThe project already has assets.Connect S3 on a new, empty project.
BYOB_ALREADY_CONFIGURED_IMMUTABLEA bucket is already attached to the project.Keep it, or create a new project.
BYOB_STORAGE_UNREACHABLEA later read or write failed: key deactivated, policy edited, bucket policy denying the user, KMS key access removed.Restore the four actions (and KMS access if used) for the IAM user.

Wasabi, DigitalOcean Spaces, MinIO and other S3-compatible storage

The same rules apply to all of them: paid plan, empty project, permanent bucket, and keys with read, write, delete and list on one bucket.

ProviderRegion fieldEndpoint
Wasabie.g. eu-central-1Built for you: s3.<region>.wasabisys.com
DigitalOcean Spacese.g. nyc3, fra1Built for you: <region>.digitaloceanspaces.com
MinIOYour configured regionRequired: your MinIO URL
Generic S3-compatibleAs your provider documentsRequired: the provider's S3 endpoint

Already have files in this bucket? Import them

BYOB and import do different jobs. BYOB makes Dreep write new uploads and variants into your bucket. Import copies objects that already exist in a bucket into a Dreep project, so they become Dreep assets with Dreep URLs.

To import, open Integrations in the Dreep dashboard, connect Amazon S3 with an access key, secret, region and bucket name, browse the objects, choose what to bring over and a destination folder, and start the job. It runs in the background with progress and logs. It is a one-off copy, not an ongoing sync, so read-only credentials are enough.

Who this is for

  • Teams with data residency or retention policies that require media in their own AWS account.
  • Companies that already back up, audit and bill S3 centrally and want media to follow the same controls.
  • Products that want Dreep's transforms, signed URLs and SDKs without building the pipeline on Lambda.

When Dreep is not the right fit

  • Projects that already hold media in Dreep storage: BYOB has to be set before the first upload.
  • Workloads that must stay entirely inside a VPC with no third-party access to the bucket.
  • Keeping an existing S3 library where it is while Dreep serves it: BYOB covers new uploads; existing objects need the separate import, which copies them into a Dreep project.

Frequently asked questions

What is the minimum IAM policy Dreep needs on S3?

s3:PutObject, s3:GetObject and s3:DeleteObject on arn:aws:s3:::your-bucket/*, plus s3:ListBucket on arn:aws:s3:::your-bucket. Those four actions cover every call Dreep makes.

Can I keep S3 Block Public Access enabled?

Yes. Dreep signs every request with your IAM key and serves media through Dreep CDN URLs, so the bucket never needs to be public.

Why does Dreep need s3:ListBucket?

To list prefixes when testing the connection, and because without it S3 returns 403 rather than 404 for a missing object. Dreep checks for existing variants with HeadObject and needs the 404 to tell 'not generated yet' from a permissions failure.

Do I need a CORS configuration on the S3 bucket for browser uploads?

No. Browsers upload to the presigned URL Dreep returns on cdn.dreep.cloud, and Dreep writes to S3 from its own servers, so the browser never makes a cross-origin request to S3.

Can I use an IAM role instead of access keys?

Not today. The connection form takes an Access Key ID and Secret Access Key, so use a dedicated IAM user scoped by the policy on this page and rotate its key on your normal schedule.

What happens to assets if I delete them in Dreep?

Dreep deletes the original object from your bucket. Treat the transforms/ prefix as Dreep-managed cache and don't build processes on its layout.

Related

Put your S3 bucket behind Dreep

Create a Starter or Pro project, attach the four-action IAM policy, and connect the bucket before your first upload.