How to share files from S3 without making them public
One of the most common mistakes people make with Amazon S3 is making a bucket public just to share a few files. It seems like the quickest solution: flip a setting, grab the object URL, send it off. But public buckets have been the root cause of some of the most high-profile data breaches in recent years. Sensitive documents, customer records, and private media have all been exposed because someone enabled public access and either forgot to turn it off or did not realize the scope of what they had opened.
The good news is that there are several ways to share files from S3 (and other S3-compatible providers like Cloudflare R2, DigitalOcean Spaces, and Wasabi) without ever making your bucket public. This guide walks through four approaches, starting with the most technical and ending with the simplest.
Why public buckets are dangerous
When you enable public access on an S3 bucket, every object in that bucket becomes accessible to anyone with the URL. There is no authentication, no logging of who accessed what, and no way to revoke access to a specific file without changing the entire bucket’s permissions.
Automated scanners continuously crawl the internet looking for open S3 buckets. Once your bucket is indexed, any data inside it is effectively available to the world. AWS has added guardrails like the S3 Block Public Access settings and console warnings, but the core risk remains: if the bucket is public, the data is exposed.
The solution is to keep your bucket private and use one of the methods below to grant temporary, scoped access to specific files.
Method 1: Presigned URLs via the AWS CLI or SDK
Presigned URLs are the native S3 mechanism for sharing private objects. You generate a URL that includes a cryptographic signature and an expiration time. Anyone with the URL can download the file until the URL expires, but the bucket itself stays private.
How it works. You use the AWS CLI or an SDK (Python, JavaScript, Go, etc.) to create a presigned URL for a specific object. The URL contains your credentials in hashed form, the object key, and the expiration timestamp. S3 validates the signature when the URL is accessed and serves the file if the signature is valid and the URL has not expired.
Example using the AWS CLI:
aws s3 presign s3://my-bucket/reports/quarterly-2026.pdf --expires-in 3600This generates a URL that is valid for one hour (3,600 seconds). The maximum expiration is seven days when using IAM user credentials, or shorter when using temporary security tokens.
Example using the AWS SDK for Python (boto3):
import boto3
s3 = boto3.client('s3')
url = s3.generate_presigned_url(
'get_object',
Params={'Bucket': 'my-bucket', 'Key': 'reports/quarterly-2026.pdf'},
ExpiresIn=3600
)
print(url)Pros. No changes to bucket policy or public access settings. Granular control over which objects are shared and for how long. Works with any S3-compatible provider.
Cons. Requires command-line or programming knowledge. No password protection. No download limits. Anyone who obtains the URL can use it until it expires. There is no audit trail beyond S3 access logs. For every file you want to share, you need to run a command or write code.
Method 2: Bucket policies with conditions
S3 bucket policies are JSON documents that define access rules for an entire bucket or specific prefixes. You can use conditions to restrict access by IP address, referrer, VPC endpoint, or other criteria.
How it works. You write a policy that grants s3:GetObject permission on specific objects, but only when certain conditions are met. For example, you can restrict access to a specific IP range:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSpecificIP",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/shared/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}
]
}Pros. Useful when you need to grant access to a known network or set of users. Policies are centrally managed and auditable.
Cons. Complex to write and maintain. A misconfigured policy can accidentally expose more data than intended. Condition-based access does not work well for sharing with external parties whose IP addresses you do not control. Bucket policies are AWS-specific; the syntax differs or is not supported at all on R2, Spaces, and Wasabi.
Method 3: CloudFront signed URLs and signed cookies
If you are already using Amazon CloudFront as a CDN in front of your S3 bucket, you can use CloudFront signed URLs or signed cookies to control access. This approach adds a distribution layer between the user and S3.
How it works. You configure CloudFront to require signed URLs or cookies, then use a CloudFront key pair to generate signatures that grant time-limited access. Signed cookies are useful when you want to grant access to multiple files without signing each URL individually.
Pros. Better performance through edge caching. Signed cookies are convenient for multi-file access. You can restrict by date, IP, and path.
Cons. Requires setting up and maintaining a CloudFront distribution, which adds complexity and cost. This approach is overkill for most file-sharing scenarios and is entirely AWS-specific.
Method 4: Use Nubbo for visual, no-code sharing
The methods above all work, but they share a common limitation: they require technical knowledge and, in most cases, coding or command-line work. If you are a photographer sharing proofs with a client, a project manager sending deliverables to a stakeholder, or a small team that needs a simple way to share files from cloud storage, those approaches are more complicated than they need to be.
Nubbo is a web-based tool that connects to your S3 bucket (or Cloudflare R2, DigitalOcean Spaces, or Wasabi) and provides file sharing through a visual interface. Here is how it works:
Connect your bucket. Enter your provider credentials in Nubbo. Your bucket stays private; Nubbo uses your credentials to generate presigned URLs on the fly.
Select a file and share it. Browse your files using Nubbo’s file browser, select the file you want to share, and click “Share.” A link is generated instantly.
Add protection. Set a password, an expiration date, a download limit, or any combination of the three. The recipient will need to enter the password before they can download the file.
Send the link. Copy the link and send it however you prefer: email, Slack, text message. The recipient does not need a Nubbo account or AWS credentials.
What makes this different from a presigned URL? Under the hood, Nubbo uses presigned URLs, which means your files are transferred directly between the recipient’s browser and your storage provider. Nothing passes through Nubbo’s servers. But on top of that, Nubbo adds the layers that raw presigned URLs lack: password protection, download tracking, expiration controls, and a clean download page instead of a raw URL that exposes your bucket name and object key.
Beyond single-file sharing
Nubbo also handles use cases that presigned URLs cannot:
Photo and video galleries. Share photos or videos as a gallery with watermarks, custom branding and a like system. Useful for photographers and designers who want client feedback in a polished interface rather than a ZIP file.
File requests. Need someone to upload files to your bucket? File requests generate an upload link that anyone can use, without giving them access to your bucket. Uploaded files go directly to your storage provider.
Media playback. Audio and video files can be streamed directly in the browser through Nubbo’s built-in media player.
Security considerations
Sharing files from private buckets means you need to trust the tools involved. Nubbo’s architecture is designed around a zero-knowledge model: your storage credentials are encrypted with AES-256-GCM, and file transfers happen directly between the client and the storage provider. Two-factor authentication is available for your Nubbo account. You can read more about the security model on the security page.
Choosing the right approach
Here is a quick summary to help you decide:
| Method | Technical skill needed | Password protection | Download limits | Multi-provider | Setup time |
|---|---|---|---|---|---|
| Presigned URLs (CLI/SDK) | High | No | No | Yes (with config) | Minutes per file |
| Bucket policies | High | No | No | AWS only | Hours |
| CloudFront signed URLs | High | No | No | AWS only | Hours |
| Nubbo | Low | Yes | Yes | Yes (native) | Minutes (one-time) |
If you are a developer who already has the AWS CLI configured and you need to share a single file once, a presigned URL is the fastest path. If you are setting up a system for recurring, policy-based access within your AWS infrastructure, bucket policies are worth the investment.
But if you regularly share files with people outside your team, need password protection or download limits, or want to avoid running commands every time someone needs a file, a visual tool will save you significant time.
Getting started
Keeping your S3 buckets private is not optional. It is a baseline security practice. The question is how you grant access to the files that need to be shared. Whether you use presigned URLs, bucket policies, or a tool like Nubbo depends on your technical comfort level and how often you share files.
If you want to try the visual approach, create your free account, connect your bucket, and share your first file in under two minutes. Your bucket stays private, your files stay under your control, and the people you share with get a clean, secure download experience.