Transfer.zip self-hosted sharing with tus and WebRTC
A self-hostable complete file-sharing solution that focuses on reliability, security and ease of use.
At a glance
- What is it?
- Transfer.zip combines resumable server-stored uploads with browser-based WebRTC transfers. It suits operators who want a self-hosted service, while browser, firewall, and repository-branch constraints define where it fits.
- Who is it for?
- Adopt Transfer.zip when self-hosting, resumable tus uploads, local or S3-compatible storage, and browser-based Quick Transfers are concrete requirements. Do not rely on it for unattended Quick Transfers, Firefox mobile sending, buggy Safari paths, or zero-byte Quick Transfer files.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 11 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Transfer.zip separates stored sharing from peer delivery
Transfer.zip addresses file sharing for operators who want to run the website, database, signaling service, and file-processing infrastructure themselves. It is designed for two distinct use cases. Stored Transfers place a file on local disk or an S3-compatible backend until its expiry date. Quick Transfers stream a file directly between browsers and do not retain the file on Transfer.zip servers.
That distinction matters when judging the project. Stored Transfers resemble the temporary delivery model used by services such as WeTransfer, but add resumable and chunked upload behavior through the tus protocol. Quick Transfers instead depend on two participants being online and on WebRTC negotiation succeeding. The repository also supports transfer requests, which allow another person to upload a requested file for later retrieval, and branded transfer pages with a custom icon and background. The README says that branding currently requires an S3 bucket.
The intended users are therefore broader than a single category. An operator may run the service for an organization or community, while recipients interact through browser transfer pages. A sender choosing Quick Transfer assumes simultaneous availability. A sender choosing Stored Transfer accepts server-side retention until the configured expiry. This is a practical design, but it is not one universal transfer behavior hidden behind a single interface.
Quick Transfer data flow uses WebRTC, AES-GCM, and WebSockets
Quick Transfer uses WebRTC for peer-to-peer data transfer. According to the README, the file stream passes directly between participants and is not stored on Transfer.zip servers. A signaling server, implemented with Node.js and WebSockets, helps peers discover one another. The README states that sensitive file data does not pass through that signaling server.
The browser generates a 256-bit key, and file data is encrypted with AES-GCM. The resulting link contains the information needed for the browser workflow, while the QR code can carry both the file link and encryption key. This avoids a central file copy, but it also means that loss of the key cannot be handled like recovery of a server-stored transfer.
Network conditions determine whether WebRTC remains direct. Some firewalls prevent the necessary peer connection. In that case, the application can use the signaling server as a relay. The README says relay transfers are forced for files larger than 10MB because WebRTC was producing slower transfers in practice. This is an important boundary: “peer-to-peer” does not guarantee that every transfer avoids a server. It guarantees the documented direct path where connectivity and transfer size permit it.
Stored Transfers use tus, MongoDB, workers, and configurable storage
Stored Transfers use tus for resumable, chunked uploads. If an upload or download is interrupted by a network problem, the protocol allows the operation to resume rather than forcing a full restart. That makes the mode more suitable for large files and unstable connections than a conventional single-request upload.
Repository files show a multi-service deployment. `docker-compose.yml` defines `mongo`, `next`, `signaling-server`, and `worker`. MongoDB persists application data in `./_db`, while the worker receives a named `worker_data` volume. The web service is built from `next`, and the signaling service from `signaling-server`. The README identifies the application stack as Next.js, WebRTC, WebSockets, Node.js, Fastify, MongoDB, and zip.js.
Transfer.zip supports local disk and S3-compatible APIs for file storage. This gives an operator a choice between infrastructure already present and a separately managed object store. However, the `docker-compose.yml` shown here does not mount a host directory for uploaded files. That mount or equivalent configuration may be handled elsewhere, so operators must consult `SELFHOSTING.md` before assuming where files are persisted. The repository also includes Caddy-related Compose and deployment files, indicating that TLS and public routing are part of the intended deployment path rather than incidental packaging.
Self-hosting begins with repository configuration and exposed local ports
The README points self-hosters to `SELFHOSTING.md`. The repository includes `.env.example`, Compose files, Caddy configuration, and scripts including `setup-dev.sh`, `local-dev.sh`, and `deploy-caddy.sh`. Since the full contents of `SELFHOSTING.md` are not shown here, the following is the concrete configuration visible in `.env.example` and `docker-compose.yml`, not a replacement for that guide.
The example environment defines MongoDB initialization values, the database name, forwarding ports, and Caddy settings:
MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=changeme
MONGODB_HOST_PORT=27017
MONGODB_FORWARD_PORT=27017
MONGODB_DB_NAME=transfer-zip
WEB_SERVER_FORWARD_PORT=9001
SIGNALING_SERVER_FORWARD_PORT=9002
CADDY_DOMAIN=your-domain.tld
[email protected]The Compose topology binds the relevant services to localhost and leaves public TLS termination to the separately supplied Caddy setup. The visible service definitions are:
services:
mongo:
image: mongo:8.0-noble
restart: unless-stopped
next:
build: next
restart: unless-stopped
signaling-server:
build: signaling-server
restart: unless-stopped
worker:
build: worker
restart: unless-stoppedThis excerpt does not show the full launch command, so operators should use the deployment instructions in `SELFHOSTING.md`. They must replace `changeme`, `your-domain.tld`, and `[email protected]` rather than deploying the example values unchanged. They should also decide whether local disk or S3-compatible storage is required before considering the instance ready for recipients.
MongoDB deployment and branch selection affect operational readiness
The default `mongo:8.0-noble` image has a direct CPU requirement that the repository calls out in `docker-compose.yml`. A commented alternative uses `mongo:4.4` for CPUs that do not support AVX instructions. This is not a minor image preference. A MongoDB image that cannot execute on the host CPU can prevent the service from starting, and the Compose file does not remove that responsibility from the operator.
The configuration also exposes MongoDB only on `127.0.0.1` by default:
ports:
- 127.0.0.1:${MONGODB_FORWARD_PORT:-27017}:27017The web and signaling server use the same localhost-binding pattern, with defaults of 9001 and 9002 respectively. This is a sensible deployment boundary when Caddy or another reverse proxy handles public traffic, but it also means that the reverse proxy must reach the intended container ports. Publishing a service broadly without authentication, firewall rules, and TLS would create a different security model from the repository's apparent design.
Branch choice is another operational fact. The README says `main` is intended for self-hosting, while `production` contains the code running in production, and that the branches can differ when functionality has not yet been ported to the self-hosted version. An operator evaluating features from the hosted service should compare branches instead of assuming identical behavior. There are no GitHub releases, so the repository history and branch comparison are more useful upgrade references than a release version.
Known browser and network failures narrow Quick Transfer suitability
Transfer.zip documents several boundaries that should affect adoption. Quick Transfers only work while both users are online. A recipient who closes the page cannot receive the file later through that transfer, so the workflow differs from Stored Transfers. The sender and recipient also need compatible browser behavior for the WebRTC and WebSocket path.
The README reports that zero-byte files can get stuck during Quick Transfer. It says Firefox mobile cannot currently send Quick Transfer files and suggests that a changed file path may be involved. It also reports buggy sending behavior in some Safari browsers, where Safari may terminate the WebSocket connection when the window loses focus. These are specific implementation limitations, not generic warnings about browser support.
The 10MB relay threshold adds another decision point. Smaller files can use the direct WebRTC route when it is technically possible, while larger files are sent through the signaling server as a relay even if direct WebRTC would work. This changes both privacy properties and performance characteristics. Operators should test the browsers, devices, firewalls, and file sizes their users actually need. For stored delivery, confirm tus behavior and expiry configuration through the self-hosting documentation instead of assuming Quick Transfer limitations apply identically.
Transfer.zip versus a conventional upload service
The real alternative is a conventional server-backed file-sharing service that stores uploads and exposes them through a download link for a defined period. Such a service can keep sender and recipient schedules independent, which is easier when a recipient is offline. Transfer.zip offers resumable tus uploads and self-hosted storage, but Quick Transfers deliberately trade that availability model for direct browser delivery and encryption.
A S3-compatible storage path is another differentiator, but it is not identical to running the entire service yourself. The repository supports storing transfer files through an S3-compatible API, while application services still include MongoDB, the web application, signaling, and workers. A hosted object store can therefore reduce local file-storage work without eliminating application deployment.
The AGPL-3.0 license matters for operators evaluating how they distribute modifications or network-facing deployments. The repository identifies the project as open source under that license. This article does not provide legal advice, but the license file should be reviewed alongside the deployment plan. Upgrade cost is also operational: there are no GitHub releases, and self-hosters must track repository changes while checking the stated difference between `main` and `production`.
Editorial conclusion
Adopt Transfer.zip when self-hosting, resumable tus uploads, local or S3-compatible storage, and browser-based Quick Transfers are concrete requirements. Do not rely on it for unattended Quick Transfers, Firefox mobile sending, buggy Safari paths, or zero-byte Quick Transfer files. Check `SELFHOSTING.md`, MongoDB CPU support, storage retention, network topology, and branch differences before deployment.
Frequently asked questions
How do I self-host Transfer.zip?
The README directs self-hosters to `SELFHOSTING.md`. The repository includes `docker-compose.yml`, `.env.example`, Caddy files, and services for MongoDB, Next.js, the signaling server, and the worker, but the README does not reproduce the guide's complete launch steps.
Does Transfer.zip support end-to-end encrypted file transfers?
Yes. The README describes Quick Transfers as end-to-end encrypted peer-to-peer transfers using AES-GCM with a client-side 256-bit key. The signaling server is used for peer discovery and may act as a relay, so not every Quick Transfer uses a direct peer route.
Are Transfer.zip uploads resumable?
Yes. Stored Transfers use the tus protocol for resumable, chunked uploads and downloads. Files are retained on local disk or an S3-compatible backend until the transfer expiry date, when they are permanently deleted.
What browsers have known Quick Transfer problems?
The README says Firefox mobile cannot currently send Quick Transfer files and that some Safari browsers may terminate the WebSocket connection when the window loses focus. It also documents zero-byte Quick Transfer files getting stuck during transmission.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/robinkarlberg-transfer-zip-web)Was this useful?