Deploy AWS S3 Public Proxy
Deploy and Host AWS S3 Public Proxy with Railway
AWS S3 Public Proxy
Just deployed
Deploy and Host AWS S3 Public Proxy on Railway
AWS S3 Public Proxy is a tiny Go HTTP server that publicly serves read-only objects from a private S3-compatible bucket. It accepts GET / from anonymous callers and streams the object bytes back with a 200 response — no presigned URLs, no redirects, and no way to list, upload, or delete.
About Hosting AWS S3 Public Proxy
Railway Buckets (and most S3-compatible providers) are private by default — clients can't fetch objects without valid SigV4-signed credentials, which you never want to ship to a browser or a mobile app. This template runs a minimal Go proxy that holds the credentials server-side, accepts only GET/HEAD requests, and streams the bytes through. Stable URLs (https:///path/to/file.pdf) map 1:1 to S3 keys and are safe to share, bookmark, or put behind a CDN.
Common Use Cases
- Serving public assets (images, PDFs, downloads) from a private Railway Bucket to a frontend
- Exposing a subset of bucket content to non-browser clients (mobile apps, curl, server-side fetchers) where 302 redirects are awkward
- Putting a CDN (Cloudflare, Bunny, CloudFront) in front of a private bucket without exposing credentials
- Giving teammates a stable, shareable URL to a file without generating a presigned link
Dependencies for AWS S3 Public Proxy Hosting
The template ships the Go proxy and its Dockerfile. You bring the storage: attach a Railway Bucket after deploy, or point the proxy at any external S3-compatible provider.
Deployment Dependencies
- Credentials for the target S3-compatible storage (access key, secret, endpoint, region, bucket name).
Implementation Details
Architecture Components
This template deploys a single service:
- Proxy: a ~10 MB Go binary running on a distroless, non-root container. Accepts only
GETandHEAD; returns405for every other method. AGET /healthendpoint is exposed unauthenticated for Railway healthchecks.
Request Flow
anonymous client ──GET /path/to/file──► proxy (public) ──SigV4──► S3 bucket (private)
│
▼
200 + file bytes
The proxy signs each upstream request with the server-side credentials, then streams the response body straight through. Content-Type, Content-Length, ETag, and Last-Modified are forwarded, and If-None-Match / If-Match headers are passed upstream so CDNs and clients can cache efficiently.
Security Model
- Read-only by design.
PUT,POST,DELETE, and any other non-GET/HEAD verbs return405. - No listing. There is no endpoint that enumerates keys — callers must already know the object path.
- Credentials stay server-side. Clients never see S3 credentials, signed URLs, or the upstream endpoint.
- Public by design. Anyone who knows a key can fetch the file. Do not point this at a bucket that holds sensitive objects.
Service Configuration
- Endpoint:
https:///. - Storage: set
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_S3_BUCKET_NAME,AWS_ENDPOINT_URL, andAWS_DEFAULT_REGIONon the service. For a Railway Bucket, use reference variables against the bucket's credentials. - Caching: tune
CACHE_CONTROL(defaultpublic, max-age=300) to match the lifetime of your objects.
License Information
MIT.
Why Deploy AWS S3 Public Proxy on Railway?
The read-only enforcement, SigV4 signing, conditional-request forwarding, and distroless packaging are all pre-configured — giving a frontend or public client safe read access to a private bucket is a one-click deploy instead of a bespoke Go service or nginx + signing-module project.
Notes
- Source repo: https://github.com/FournyP/aws-s3-public-proxy-railway-template
- Designed to pair with a Railway Bucket, but works with any S3-compatible provider (AWS S3, MinIO, Cloudflare R2, Backblaze B2, Tigris).
Template Content
AWS S3 Public Proxy
FournyP/aws-s3-public-proxy-railway-templateAWS_ENDPOINT_URL
S3-compatible API endpoint. For Railway Buckets, reference AWS_ENDPOINT_URL (e.g. https://t3.storageapi.dev). For real AWS, use https://s3..amazonaws.com.
AWS_ACCESS_KEY_ID
S3 access key ID. Reference your bucket's AWS_ACCESS_KEY_ID so credentials stay in sync.
AWS_S3_BUCKET_NAME
Name of the bucket whose objects will be publicly served. Reference your bucket's AWS_S3_BUCKET_NAME.
AWS_SECRET_ACCESS_KEY
S3 secret access key. Reference your bucket's AWS_SECRET_ACCESS_KEY. Treat as sensitive.
