Access a private S3 bucket
This example demonstrates how to access a private S3 bucket that is not exposed to the public internet. In this guide, we will configure a Workers VPC Service for an internal S3-compatible storage service, create a Worker that makes requests to that bucket, and deploy the Worker to validate our changes.
- A private S3-compatible storage service running in your VPC/virtual network (such as AWS S3 VPC endpoint, MinIO, or similar)
- A virtual machine/EC2 instance running in the same VPC as your S3 VPC endpoint
- Workers account with Workers VPC access
A Cloudflare Tunnel creates a secure connection from your private network to Cloudflare. This tunnel will allow Workers to securely access your private resources.
-
Navigate to the Workers VPC dashboard ↗ and select the Tunnels tab.
-
Select Create to create a new tunnel.
-
Enter a name for your tunnel (for example,
s3-tunnel) and select Save tunnel. -
Choose your operating system and architecture. The dashboard will provide specific installation instructions for your environment.
-
Follow the provided commands to download and install
cloudflaredon your VM, and execute the service installation command with your unique token.
The dashboard will confirm when your tunnel is successfully connected. Note the tunnel ID for the next step.
First, create a Workers VPC Service for your internal S3 storage:
npx wrangler vpc service create s3-storage \ --type http \ --tunnel-id <YOUR_TUNNEL_ID> \ --hostname s3.us-west-2.amazonaws.comYou can also create a Workers VPC Service using an IP address (for example, if using MinIO):
npx wrangler vpc service create s3-storage \ --type http \ --tunnel-id <YOUR_TUNNEL_ID> \ --ipv4 10.0.1.60 \ --http-port 9000Note the service ID returned for the next step.
Configure your S3 bucket to allow anonymous access from your VPC endpoint. This works for unencrypted S3 objects:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowAnonymousAccessFromVPCE", "Effect": "Allow", "Principal": "*", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": [ "arn:aws:s3:::your-bucket-name", "arn:aws:s3:::your-bucket-name/*" ], "Condition": { "StringEquals": { "aws:sourceVpce": "vpce-your-endpoint-id" } } } ]}You can test S3 access directly from the VM where your Cloudflare Tunnel is running to verify the bucket policy is working correctly. These commands should work without any AWS credentials:
# Test listing bucket contentscurl -i https://s3.us-west-2.amazonaws.com/your-bucket-name/
# Test downloading a specific filecurl -i https://your-bucket-name.s3.us-west-2.amazonaws.com/test-file.txtUpdate your wrangler.toml:
{ "$schema": "./node_modules/wrangler/config-schema.json", "name": "private-s3-gateway", "main": "src/index.js", "compatibility_date": "2024-01-01", "vpc_services": [ { "binding": "S3_STORAGE", "service_id": "<YOUR_SERVICE_ID>" } ]}name = "private-s3-gateway"main = "src/index.js"compatibility_date = "2024-01-01"
[[vpc_services]]binding = "S3_STORAGE"service_id = "<YOUR_SERVICE_ID>"In your Workers code, use the Workers VPC Service binding in order to send requests to the service:
export default { async fetch(request, env, ctx) { try { // Fetch a file from the private S3 bucket via VPC endpoint const response = await env.S3_STORAGE.fetch("https://s3.us-west-2.amazonaws.com/my-bucket/data.json");
// Use the response from S3 to perform more logic in Workers, before returning the final response return response; } catch (error) { return new Response("Storage unavailable", { status: 503 }); } },};This guide demonstrates how you could access private object storage from your Workers. You could use Workers VPC Services to fetch files directly and manipulate the responses to enable you to build more full-stack and backend functionality on Workers.
Now, you can deploy and test your Worker that you have created:
npx wrangler deploy# Test GET requestcurl https://private-s3-gateway.workers.dev- Add authentication and authorization
- Implement rate limiting
- Set up monitoring and alerting
- Explore other examples
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark
-