Guide
How an SFTP proxy works: object storage as an SFTP backend
A technical look at how an SFTP gateway translates SFTP operations into object-storage API calls, how virtual directories map to key prefixes, and where the filesystem abstraction leaks.
An SFTP proxy presents a familiar filesystem-style interface to clients, then quietly translates each operation into calls against an object store that has no real folders, no in-place writes, and no atomic rename. Understanding that translation explains both what works seamlessly and where the abstraction has to leak.
The two halves
On the client side, the proxy is a normal SSH/SFTP server: it authenticates the user, then
serves SFTP operations (OPEN, READ, WRITE, READDIR, RENAME, REMOVE, and so on).
On the backend side, it holds credentials for an object store (a scoped IAM role for S3, or a scoped access key for Azure, GCS, and S3-compatible stores) and turns each SFTP operation into the equivalent storage API call.
Mapping the filesystem onto a flat keyspace
Object storage is a flat keyspace: every object has a string key like
clients/acme/2026/report.csv. There are no directories, only keys that happen to contain
slashes. The proxy presents virtual directories by treating the part of the key before a
slash as a folder:
READDIR /clients/acmebecomes aListObjectscall with prefixclients/acme/and a delimiter of/, and the results are presented as files and sub-folders.OPEN+WRITEofreport.csvstreams the incoming bytes into aPutObject(often a multipart upload for large files) at the matching key.OPEN+READstreams aGetObjectback to the client.REMOVEis aDeleteObject.
A user’s path jail is just a prefix the proxy enforces: it refuses operations outside the user’s prefix, so the credential can only ever touch its own slice of the bucket.
Where the abstraction leaks (and why)
Some filesystem operations have no clean object-storage equivalent, and a good proxy handles them honestly rather than faking them:
- In-place edit / append: objects are written whole, not edited. The proxy returns a clean “operation unsupported” rather than silently corrupting data.
- Rename: there’s no atomic rename in object storage, so a rename is a server-side copy then delete. It works for the common upload-to-temp-then-rename pattern, but it isn’t atomic, and renaming a huge object takes as long as copying it.
- Timestamps and permissions: object storage has no POSIX mode bits or mtime metadata, so
chmodand timestamp-preserving flags report success but don’t do anything. - Listing very large directories: a naive live
ListObjectson a prefix with millions of keys can be slow or time out, which is why some gateways offer an optional synced index to keep listings fast.
The full, honest list for Firepipe specifically is on the SFTP compatibility & known limitations page.
Why the proxy holds the credentials, not the client
The client only ever sees SFTP and its own path jail. It never gets the storage credentials; the proxy holds those and uses least-privilege access scoped to one bucket or prefix. That’s what lets you hand a partner an SFTP login without ever exposing your cloud keys, and revoke that login instantly without touching the storage itself.
In short
An SFTP proxy is a faithful translator: filesystem operations in, object-storage calls out, virtual directories from key prefixes, and a path jail enforced on every call. It feels like a filesystem until you hit the handful of things a flat object store genuinely can’t do, where a good one fails loudly. See it on your own bucket at SFTP to S3.
Try it on your own bucket
Connect a bucket you already own, Amazon S3, Azure Blob, Google Cloud Storage, or an S3-compatible store, and hand out a clean SFTP endpoint in minutes. Your files stay in your cloud.
Start free