Back to Articles

transfer.sh: Building a Command-Line File Sharing Service with Pluggable Storage

[ View on GitHub ]

transfer.sh: Building a Command-Line File Sharing Service with Pluggable Storage

Hook

With 15,810 GitHub stars, transfer.sh proves that developers still prefer typing curl --upload-file over clicking through web UIs—and its pluggable architecture shows why building for the command line first doesn’t mean sacrificing flexibility.

Context

File sharing tools have always faced a fundamental tension: ease of use versus control. Commercial services like Dropbox and WeTransfer offer polished interfaces but lock you into their infrastructure, pricing, and privacy policies. Meanwhile, setting up your own file sharing usually meant wrestling with complex software stacks or building something from scratch.

transfer.sh emerged as a third path: a purpose-built HTTP server designed for command-line workflows that you can deploy yourself in minutes. Written in Go by dutchcoders, it treats file sharing through a command-line interface while giving you complete control over where files live—local disk, Amazon S3, Google Drive, or Storj. Upload with curl, download with wget, script it in your CI/CD pipeline, or wrap it in your own tooling. It’s the Unix philosophy applied to file sharing: do one thing well and compose with everything else.

Technical Insight

HTTP Upload with Headers

HTTP Download

Validate & Encrypt

Store File

Local

S3

Cloud

Distributed

Return URL + X-Url-Delete

Check Limits

Enforce

Client/cURL

HTTP Server

TLS + Auth + IP Filter

File Processing

AES256 Encryption

VirusTotal Scan

Storage Provider

Abstraction Layer

Filesystem Storage

Amazon S3

Google Drive

Storj Network

Metadata Store

Max-Downloads

Max-Days

Retention Policy

System architecture — auto-generated

The design of transfer.sh centers on its storage abstraction layer. The server supports multiple storage backends through a pluggable provider system that allows the same HTTP interface to work with local filesystem, Amazon S3, Google Drive, or Storj storage without changing client commands.

The command-line interaction model is deliberately minimal. Uploading a file requires nothing more than curl’s --upload-file flag:

curl --upload-file ./document.pdf https://transfer.sh/document.pdf

The server responds with a URL. No API keys, no authentication dance, no JSON parsing required. But this simplicity doesn’t mean lack of control—it means control through HTTP headers rather than configuration files. Want to limit a file to specific downloads? Add a header:

curl --upload-file ./secret.txt https://transfer.sh/secret.txt -H "Max-Downloads: 3"

Need the file to expire in 24 hours? Another header:

curl --upload-file ./temporary.log https://transfer.sh/temporary.log -H "Max-Days: 1"

The server returns an X-Url-Delete response header containing a unique deletion URL, giving you programmatic cleanup without maintaining state on the client side. You can pipe this into your scripts, store it in a database, or ignore it entirely.

For encryption, transfer.sh takes a dual approach. The README demonstrates client-side encryption using GPG—the recommended method:

gpg --armor --symmetric --output - /tmp/sensitive.txt | curl --upload-file - https://transfer.sh/encrypted.txt

This pipes GPG’s output directly to curl, encrypting before the file ever touches the server. But transfer.sh also supports server-side AES256 encryption via the X-Encrypt-Password header. The maintainers are refreshingly direct about this: “Beware, use this feature only on your self-hosted server: trusting a third-party service for server side encryption is at your own risk.” This honesty about threat models is rare in open-source documentation.

The system extends to optional VirusTotal integration. Upload a file and immediately submit it for scanning:

curl -X PUT --upload-file suspicious.exe https://transfer.sh/suspicious.exe/virustotal

This approach to malware scanning shows how transfer.sh composes with external services—it’s not trying to be a complete solution, just a well-designed component in a larger toolchain. The server configuration supports basic HTTP authentication (via user/pass or htpasswd file), IP whitelisting/blacklisting, and TLS termination, giving you the security controls you’d expect in a production service without forcing opinions about how you should use them.

Gotcha

transfer.sh’s biggest limitation is also its design philosophy: it deliberately avoids user management. There’s no concept of accounts, permissions, or access control beyond basic HTTP authentication and IP filtering. You can password-protect uploads, but every user with the password has identical capabilities. If you need per-user quotas, audit trails, or role-based access, you’ll need to build that layer yourself or look elsewhere.

The server-side encryption feature deserves skepticism even in self-hosted scenarios. While AES256 is solid, the password travels in an HTTP header and the server holds the keys. If your threat model includes compromised servers or malicious administrators, this doesn’t help you. The maintainers’ warning about third-party instances is appropriate, but even on your own infrastructure, client-side encryption with GPG or similar tools provides stronger guarantees.

The emphasis on self-hosting throughout the documentation is both a feature and a barrier—if you’re looking for a hosted service rather than infrastructure to deploy, transfer.sh explicitly tells you to go elsewhere. The disclaimer in the README makes this crystal clear: maintainers won’t support public installations, and they recommend everyone host their own instance. This keeps the project focused but limits casual adoption.

Verdict

Use transfer.sh if you’re building automation that needs simple file sharing, running a development team that lives in the terminal, or want a self-hosted alternative to commercial services with complete control over storage backends. It excels when wrapped in scripts, integrated into CI/CD pipelines, or deployed as internal infrastructure where you control both client and server. The pluggable storage architecture means you can start with local disk and migrate to S3 without changing a single curl command.

Skip it if you need multi-user management with permissions, want a polished web interface for non-technical users, or prefer SaaS over self-hosting. Also skip if your security model requires strong guarantees around encryption—use client-side tools like GPG instead. transfer.sh is infrastructure, not a product, and it makes no apologies for that choice.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/cybersecurity/dutchcoders-transfer-sh.svg)](https://starlog.is/api/badge-click/cybersecurity/dutchcoders-transfer-sh)