---
title: "Deploy PairDrop"
description: "Send files straight between two browsers, like AirDrop for the web"
category: "Other"
url: https://railway.com/deploy/pairdrop
---

# Deploy PairDrop

Send files straight between two browsers, like AirDrop for the web

**[Deploy PairDrop on Railway](https://railway.com/template/pairdrop)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/pairdrop/manifest.json

- **Creator:** A3A
- **Category:** Other
- **Total deploys:** 1

## Template content

### pairdrop https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/pairdrop.png

- **Source:** https://github.com/gridalpha/pairdrop-railway
- **Health check:** /config
- **Public domain:** Yes

## Documentation

# Deploy and Host PairDrop on Railway

PairDrop is an open-source, browser-based file transfer tool inspired by Apple's AirDrop. Open the same page on a laptop and a phone, and the two devices find each other automatically and send photos, documents or text from one browser to the other over a WebRTC data channel. Nothing is uploaded or stored, and neither device needs an app, an account or a cable. It is a maintained fork of Snapdrop that adds device pairing and temporary public rooms, so distant devices can transfer too.

Deploy PairDrop on Railway and you get one service, `pairdrop`, built from the [gridalpha/pairdrop-railway](https://github.com/gridalpha/pairdrop-railway) source repository on top of the official `ghcr.io/schlagmichdoch/pairdrop` image. It serves the web app and runs the WebSocket signaling server that introduces two browsers to each other. Railway terminates HTTPS and passes the WebSocket upgrade through, which is how browsers exchange connection offers; file bytes never touch the service. With no stored state, the template needs no database, volume or object storage.

![Diagram of the PairDrop signaling service on Railway](https://res.cloudinary.com/rroe4rtk/image/upload/v1788947455/pairdrop-architecture.png)

## Getting Started with PairDrop on Railway

Click Deploy and wait for the service to go green. There is no installer, sign-up or admin account: open the generated `*.up.railway.app` URL and you are using the app. A radar screen shows your randomly assigned device name, something like "Rose Octopus". Open the same URL on a second device on the same internet connection, and each appears on the other's screen in a second or two.

To send something, click the other device's icon and pick a file. The recipient gets a request naming the sender, the file and its size, and nothing transfers until they accept; images then open with a preview and a download button. For devices on *different* networks, the people icon opens a temporary public room showing a five-letter code and a QR code that any device can enter. The link icon beside it pairs two devices permanently with a six-digit code, so they keep finding each other after both browsers close.

If a device does not appear, check that both leave the internet through the same public IP address; a browser with WebRTC disabled, as some VPN extensions do, cannot connect at all.

![Two PairDrop devices discovering each other on one network](https://res.cloudinary.com/rroe4rtk/image/upload/v1788947459/pairdrop-devices-discovered.png)
![PairDrop showing a received image with its preview](https://res.cloudinary.com/rroe4rtk/image/upload/v1788947460/pairdrop-file-received.png)
![PairDrop temporary public room with its code and QR code](https://res.cloudinary.com/rroe4rtk/image/upload/v1788947461/pairdrop-public-room.png)

## About Hosting PairDrop

Cross-platform file sharing is solved inside one ecosystem and annoying between them. AirDrop stops at Apple devices, Quick Share at Android and Windows, and everything else becomes a cloud upload or a USB cable. PairDrop is the neutral option: a page both devices can open. Teams self-host it to keep internal transfers on their own infrastructure.

Key features:

- Peer-to-peer transfers over encrypted WebRTC data channels, with no app-imposed size limit
- Automatic discovery of every device on the network, with no configuration
- Persistent pairing by six-digit or QR code, surviving a browser restart
- Temporary public rooms for one-off transfers across networks
- Text and clipboard transfers too, with multiple files arriving as a ZIP
- Installable as a progressive web app, with iOS and Android share-menu integration

The architecture is deliberately small. The `pairdrop` service serves the static client and runs a WebSocket signaling server that tells browsers on one public IP address about each other and relays their WebRTC offers. Once they connect it leaves the path entirely, which is why one small container handles a whole team.

## Why Deploy PairDrop on Railway

Railway removes the fiddly parts of self-hosting PairDrop:

- HTTPS on a real domain, which several PairDrop features require
- WebSocket upgrades pass through with no configuration
- The real client IP reaches the app, so discovery groups devices properly
- One stateless container, so redeploys and rollbacks cost nothing
- Push to the source repository to rebuild, or attach a custom domain

## Common Use Cases for Self-Hosted PairDrop

- Moving photos and video off a phone at full quality, with no cloud round trip
- Passing a build artefact or log file between office machines on different operating systems
- Sharing files with a visitor's laptop without adding them to a file server or chat workspace
- Sending a long link or block of text from a phone to a workstation

## Dependencies for PairDrop

PairDrop has no external dependencies — no database, cache or storage. It is built from:

- `ghcr.io/schlagmichdoch/pairdrop:latest` — the official image, a Node.js 22 app on Alpine
- [gridalpha/pairdrop-railway](https://github.com/gridalpha/pairdrop-railway) — one layer on top adding the entrypoint and the proxy-aware defaults below

### Environment Variables Reference

| Variable | Default | Purpose |
|---|---|---|
| `PORT` | `3000` | Port the HTTP and WebSocket server listens on |
| `RATE_LIMIT` | `2` | Proxies in front of the app; also enables the 1000-per-5-minutes limiter |
| `IPV6_LOCALIZE` | `4` | How many segments of an IPv6 address count as one network for discovery |
| `WS_FALLBACK` | `false` | Relay transfers through the server for browsers without WebRTC |
| `STUN_URLS` | `stun:stun.l.google.com:19302` | Comma-separated STUN servers used to negotiate connections |
| `TURN_URLS` | empty | Comma-separated TURN servers, for peers behind restrictive NAT |
| `TURN_USERNAME` | empty | Username for the TURN servers above |
| `TURN_CREDENTIAL` | empty | Password for the TURN servers above |

`IPV6_LOCALIZE` matters more than it looks: every device on an IPv6 network has a unique address, so without it two phones on one Wi-Fi never see each other. The default groups them by `/64` prefix.

### Deployment Dependencies

- Source: [github.com/schlagmichdoch/PairDrop](https://github.com/schlagmichdoch/PairDrop) (GPL-3.0)
- Image: [ghcr.io/schlagmichdoch/pairdrop](https://github.com/schlagmichdoch/PairDrop/pkgs/container/pairdrop)
- Self-hosting guide: [host-your-own.md](https://github.com/schlagmichdoch/PairDrop/blob/master/docs/host-your-own.md)
- Runtime: Node.js 22 on Alpine

## Hardware Requirements for Self-Hosting PairDrop

The service holds a little connection state per device and nothing else, so it is cheap to run.

| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 0.25 vCPU | 0.5 vCPU |
| RAM | 128 MB | 512 MB |
| Storage | None | None |
| Runtime | Node.js 15+ | Node.js 22 |

With `WS_FALLBACK` off those numbers hold at any file size, because files never pass through the container.

## Self-Hosting PairDrop with Docker

The official image runs with no configuration. The smallest useful command:

```
docker run -d --name pairdrop -p 3000:3000 ghcr.io/schlagmichdoch/pairdrop
```

Behind a reverse proxy you must forward the client's address, or every visitor looks like one network and they all discover each other. The proxy must pass `X-Forwarded-For` and allow WebSocket upgrades. A minimal nginx block:

```
location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}
```

Serve it over HTTPS. Persistent pairing, notifications, installing the progressive web app and copying received text all need a secure context, and browsers silently disable them on plain HTTP.

## Is PairDrop Free to Self-Host?

PairDrop is free and open source under the GPL-3.0 licence, with no paid tier, accounts or usage limits. Self-hosting costs only infrastructure, and one small stateless container on Railway is a few dollars a month at most.

## FAQ

**What is PairDrop?**

An open-source web app for sending files and text directly between devices on one network, or between paired devices anywhere. A maintained fork of Snapdrop, it works in any modern browser.

**What does this Railway template deploy?**

One service, `pairdrop`, serving the web app and the WebSocket signaling server. No database, volume or object storage, because the server holds only in-memory connection state.

**Why is there no database in this template?**

There is nothing to store. Pairings live in each browser's local storage, room membership in memory while devices are connected, and files travel browser to browser. A redeploy just reconnects everyone.

**How do I transfer files between devices on different networks with self-hosted PairDrop?**

Use a temporary public room, or pair the devices; both controls are in the top-right toolbar. If a transfer still fails, both peers are behind restrictive NAT: point `TURN_URLS`, `TURN_USERNAME` and `TURN_CREDENTIAL` at a TURN service, which relays when a direct connection is impossible.

**Are my files encrypted when using PairDrop?**

Yes. WebRTC data channels are encrypted end to end with DTLS, and by default the bytes never reach the server. `WS_FALLBACK` changes that, routing transfers through your container where they are readable, so leave it off unless you need it.

**Why do all my devices see each other, or none of them do?**

Discovery groups visitors by public IP address. Everyone seeing everyone means the client address is not reaching the app; nobody appearing means the devices leave through different addresses. This template already carries the proxy settings Railway needs.


## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/pairdrop
