Skip to content

Deploying Drop

Introduction

Drop (also known as Filedrop) is an open-source, end-to-end encrypted peer-to-peer file transfer application that prioritizes privacy and ease of use. Built with React and Node.js, Drop uses WebRTC technology to establish direct connections between users, ensuring files are transferred securely without passing through centralized servers. With a minimalist interface, real-time chat functionality, and support for Progressive Web Applications (PWA), Drop provides a modern, privacy-first alternative to traditional file sharing services.

Drop is designed to be:

  • Privacy-First: Complete end-to-end encryption for files, metadata, and chat messages
  • Peer-to-Peer: Direct WebRTC connections eliminate the need for file storage on servers
  • Zero-Knowledge: The server never sees your files or messages
  • Simple: Clean, minimalist interface that requires no signup or authentication
  • Cross-Platform: Works on any device with a modern web browser
  • Self-Hostable: Full control over your deployment and infrastructure
  • Progressive Web App: Install as a native-like app on mobile and desktop

Key features include:

  • End-to-End Encryption: All files and messages are encrypted before transmission
  • Direct Transfer: WebRTC enables peer-to-peer file sharing without server intermediaries
  • Real-Time Chat: Built-in messaging for coordination during file transfers
  • No File Size Limits: Transfer files of any size (limited only by browser capabilities)
  • Multi-File Support: Share multiple files simultaneously
  • Copy-Paste Integration: Easy text sharing through clipboard
  • Room Codes: Simple 4-digit codes for connecting with peers
  • Mobile-Friendly: Responsive design works perfectly on smartphones and tablets

This guide walks you through deploying Drop on Klutch.sh using Docker, including WebRTC configuration, TURN server setup for NAT traversal, environment variables, and production-ready deployment practices.

Why Deploy Drop on Klutch.sh?

Klutch.sh provides an ideal platform for hosting Drop with several key advantages:

  • Automatic Docker Detection: Klutch.sh detects your Dockerfile and builds containers automatically
  • WebRTC-Optimized: Low-latency infrastructure perfect for real-time peer connections
  • Built-in HTTPS: Automatic SSL certificates required for WebRTC functionality
  • Custom Domains: Use your own branded domain for file sharing
  • Environment Management: Securely configure TURN servers and application settings
  • Scalable Signaling: Handle multiple concurrent peer connections efficiently
  • Always Available: 24/7 uptime ensures users can connect anytime
  • No Storage Costs: Peer-to-peer architecture means no file storage needed on servers

Prerequisites

Before deploying Drop to Klutch.sh, ensure you have:

  • A Klutch.sh account (free to get started)
  • A GitHub account for repository hosting
  • Docker installed locally for testing (recommended)
  • Basic understanding of WebRTC, WebSockets, and peer-to-peer networking
  • (Optional) A TURN server for NAT traversal - see Coturn for self-hosting

Understanding Drop Architecture

Drop operates on a peer-to-peer architecture with a lightweight signaling server:

Core Components

WebSocket Signaling Server: Coordinates peer connections and room management

  • Built with Node.js and WebSocket protocol
  • Handles room creation and peer discovery
  • Relays WebRTC signaling messages (SDP offers/answers)
  • Does not see or store any file data
  • Manages connection limits and abuse prevention

React Frontend: Progressive web application interface

  • TypeScript-based React application
  • Handles WebRTC peer connections
  • Implements end-to-end encryption
  • Manages file transfer UI and chat interface
  • Supports PWA features for installation

WebRTC Connections: Direct peer-to-peer data channels

  • Establishes direct connections between browsers
  • Uses STUN servers for peer discovery
  • Falls back to TURN servers when NAT traversal fails
  • Encrypts all data before transmission

Data Flow

  1. User A accesses Drop and creates a room (generates 4-digit code)
  2. WebSocket signaling server assigns User A to a room
  3. User B enters the room code and joins
  4. Peers exchange WebRTC signaling messages via WebSocket
  5. Direct peer-to-peer connection established using WebRTC
  6. Files are encrypted and transferred directly between browsers
  7. Server never sees file contents - only coordination messages

Port and Protocol Requirements

  • HTTP/HTTPS: Port 5000 (internal) for web interface and signaling
  • WebSocket: Upgraded from HTTP connection for real-time signaling
  • STUN: UDP 3478 for NAT traversal and peer discovery
  • TURN: TCP 3478 and UDP 49152-65535 (if using TURN server)

Installation and Setup

Step 1: Create Your Project Repository

Create a new directory for your Drop deployment:

Terminal window
mkdir drop-klutch
cd drop-klutch
git init

Step 2: Create the Dockerfile

Create a Dockerfile in your project root. Klutch.sh automatically detects and builds from this file:

# Build stage - compile frontend and prepare application
FROM node:20-alpine AS build
WORKDIR /app
# Install build dependencies
RUN apk add --no-cache bash git
# Clone Drop repository
RUN git clone https://github.com/mat-sz/filedrop.git .
# Install dependencies using Corepack (Yarn Berry)
RUN corepack enable && corepack yarn install
# Build frontend application
RUN corepack yarn build
# Move built frontend to separate location
RUN mv web/build web_build && rm -rf web
# Clean up build artifacts to reduce image size
RUN rm -rf node_modules && \
corepack yarn cache clean && \
rm -rf /root/.npm
# Install production dependencies only
RUN corepack yarn install --production
# Production stage - minimal runtime image
FROM node:20-alpine
WORKDIR /app
# Install runtime dependencies
RUN apk add --no-cache bash
# Enable Corepack for Yarn
RUN corepack enable
# Copy application files from build stage
COPY --from=build /app /app
# Set environment variables
ENV NODE_ENV=production \
WS_HOST=0.0.0.0 \
WS_PORT=5000 \
WS_STATIC_ROOT=../web_build \
WS_APP_NAME=Drop
# Expose signaling server port
EXPOSE 5000
# Health check to verify server is running
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD node -e "require('http').get('http://localhost:5000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1); });"
# Start production server
CMD ["corepack", "yarn", "start:prod"]

Dockerfile Explanation:

  • Multi-stage build: Separates build and runtime for smaller final image
  • Corepack: Uses Yarn Berry (Yarn 3+) via Node.js built-in Corepack
  • Frontend build: Compiles React application to static files
  • Production deps only: Reduces image size by excluding dev dependencies
  • Health check: Monitors server availability
  • Port 5000: Default signaling server port

Step 3: Create Environment Configuration

Create a .env.example file documenting all configuration options:

# Drop (Filedrop) Environment Configuration
# Application Settings
NODE_ENV=production
WS_APP_NAME=Drop
WS_ABUSE_EMAIL=abuse@yourdomain.com
# Server Configuration
WS_HOST=0.0.0.0
WS_PORT=5000
WS_STATIC_ROOT=../web_build
# Security Settings
WS_USE_X_FORWARDED_FOR=1
WS_REQUIRE_CRYPTO=1
# Connection Limits
WS_MAX_SIZE=65536
WS_MAX_NETWORK_CLIENTS=64
# WebRTC STUN Configuration
STUN_SERVER=stun:stun1.l.google.com:19302
# TURN Server Configuration (Optional - for NAT traversal)
TURN_MODE=default
TURN_SERVER=
TURN_USERNAME=
TURN_CREDENTIAL=
TURN_SECRET=
TURN_EXPIRY=3600
# Notice Configuration (Optional)
NOTICE_TEXT=
NOTICE_URL=
# Build-time Configuration (optional)
VITE_APP_NAME=Drop

Key Configuration Options:

  • WS_APP_NAME: Branding for your Drop instance
  • WS_ABUSE_EMAIL: Contact email for abuse reports
  • WS_USE_X_FORWARDED_FOR: Must be 1 when behind Klutch.sh proxy
  • WS_REQUIRE_CRYPTO: Enforces HTTPS for all connections
  • WS_MAX_NETWORK_CLIENTS: Limits users per room (default 64)
  • TURN_MODE: Set to hmac for time-limited TURN credentials

Step 4: Create .dockerignore File

Create .dockerignore to exclude unnecessary files from the build:

.git
.github
.gitignore
node_modules
npm-debug.log
yarn-error.log
*.md
.env
.env.local
.DS_Store
docs/
tests/

Step 5: Add Documentation Files

Create README.md with deployment instructions:

# Drop on Klutch.sh
End-to-end encrypted peer-to-peer file sharing application.
## Features
- End-to-end encrypted file transfers
- Peer-to-peer connections via WebRTC
- No file size limits (browser-dependent)
- Real-time chat functionality
- Progressive Web App support
- No signup or authentication required
## Deployment
This Drop instance is deployed on Klutch.sh with automatic Docker builds.
### Environment Variables
Configure the following in the Klutch.sh dashboard:
- `WS_APP_NAME`: Your instance name
- `WS_ABUSE_EMAIL`: Contact email for reports
- `WS_USE_X_FORWARDED_FOR`: Set to `1`
- `WS_REQUIRE_CRYPTO`: Set to `1` for HTTPS enforcement
- `STUN_SERVER`: STUN server for peer discovery
- `TURN_*`: Optional TURN server configuration for NAT traversal
### TURN Server Setup
For users behind restrictive NATs, configure a TURN server:
1. Deploy Coturn or use a managed TURN service
2. Set `TURN_MODE=hmac` for secure time-limited credentials
3. Configure `TURN_SERVER`, `TURN_SECRET`, and `TURN_EXPIRY`
## Usage
1. Visit your deployed Drop instance
2. Click "Create Room" to generate a 4-digit code
3. Share the code with intended recipient
4. Recipient enters code to join room
5. Transfer files directly via encrypted peer connection
## License
BSD-3-Clause-Clear (Filedrop) - See original repository for details

Step 6: Initialize Git and Push to GitHub

Terminal window
# Initialize git repository
git init
# Add all files
git add Dockerfile .dockerignore .env.example README.md
# Commit files
git commit -m "Initial Drop deployment configuration"
# Add GitHub remote (replace with your repository URL)
git remote add origin https://github.com/yourusername/drop-klutch.git
# Push to GitHub
git branch -M main
git push -u origin main

Deploying to Klutch.sh

Step 1: Create New App

  1. Navigate to the Klutch.sh dashboard
  2. Click **Create New App** or **New Deployment**
  3. Select **GitHub** as your source
  4. Authenticate with GitHub if not already connected
  5. Choose your Drop repository from the list
  6. Select the `main` branch for deployment

Step 2: Configure Application Settings

  1. **App Name**: Choose a unique name (e.g., `drop-filetransfer`)
  2. **Traffic Type**: Select **HTTP** traffic
  3. **Internal Port**: Set to `5000` (Drop's WebSocket signaling server port)

Important: Drop requires HTTP traffic mode for WebSocket upgrades. The signaling server listens on port 5000 internally.

Step 3: Set Environment Variables

In the Klutch.sh dashboard, configure these environment variables:

Required Variables:

WS_APP_NAME=Drop
WS_HOST=0.0.0.0
WS_PORT=5000
WS_STATIC_ROOT=../web_build
WS_USE_X_FORWARDED_FOR=1
WS_REQUIRE_CRYPTO=1

Recommended Variables:

WS_ABUSE_EMAIL=abuse@yourdomain.com
WS_MAX_NETWORK_CLIENTS=64
STUN_SERVER=stun:stun1.l.google.com:19302

Optional TURN Server (for better connectivity):

TURN_MODE=hmac
TURN_SERVER=turn:your-turn-server.com:3478
TURN_SECRET=your-turn-server-secret
TURN_EXPIRY=3600

Optional Branding:

VITE_APP_NAME=YourBrand Drop
NOTICE_TEXT=Welcome to secure file sharing
NOTICE_URL=https://yourdomain.com

Step 4: Deploy Application

  1. Click **Deploy** or **Create App**
  2. Klutch.sh will automatically detect the Dockerfile and build your container
  3. Wait for the build to complete (typically 3-5 minutes)
  4. Once deployed, your app will be available at `https://your-app-name.klutch.sh`

Step 5: Verify Deployment

Test your Drop instance:

  1. Navigate to `https://your-app-name.klutch.sh`
  2. Click **Create Room** - you should see a 4-digit code
  3. Open an incognito/private window and enter the code
  4. Verify both peers see each other connected
  5. Test file transfer by dragging a file to the window

Configuring TURN Server for NAT Traversal

While STUN servers work for many users, some network configurations require TURN servers for successful peer connections. Here’s how to set up Coturn as a TURN server:

Option 1: Deploy Coturn Separately

Deploy Coturn as a separate TCP application on Klutch.sh:

Coturn Dockerfile:

FROM coturn/coturn:latest
# Copy configuration
COPY turnserver.conf /etc/coturn/turnserver.conf
# Expose TURN ports
EXPOSE 3478/tcp
EXPOSE 3478/udp
EXPOSE 49152-65535/udp
CMD ["turnserver", "-c", "/etc/coturn/turnserver.conf"]

turnserver.conf:

listening-port=3478
fingerprint
lt-cred-mech
use-auth-secret
static-auth-secret=YOUR_TURN_SECRET_HERE
realm=example-app.klutch.sh
total-quota=100
bps-capacity=0
stale-nonce=600
no-multicast-peers

Deploy this as a TCP service on Klutch.sh with port 8000 external, 3478 internal.

Option 2: Use Managed TURN Services

Consider managed TURN providers for production:

Configure in Drop environment variables:

TURN_MODE=default
TURN_SERVER=turn:global.turn.twilio.com:3478?transport=tcp
TURN_USERNAME=your-twilio-username
TURN_CREDENTIAL=your-twilio-credential

For HMAC-based authentication:

TURN_MODE=hmac
TURN_SERVER=turn:your-turn-server.com:3478
TURN_SECRET=shared-secret-with-turn-server
TURN_EXPIRY=3600

Getting Started with Drop

Basic File Transfer

Sender (User A):

  1. Navigate to your Drop instance
  2. Click Create Room button
  3. Note the 4-digit code displayed (e.g., 1234)
  4. Share code with recipient via secure channel

Receiver (User B):

  1. Navigate to same Drop instance
  2. Enter 4-digit code in input field
  3. Click Join or press Enter
  4. Wait for connection to establish

Transfer Files:

  1. Once connected, drag files onto window
  2. Or click upload button to select files
  3. Files transfer directly between browsers
  4. Progress bar shows transfer status

Using Chat Feature

While connected in a room:

  1. Type message in chat input at bottom
  2. Press Enter to send
  3. Messages are end-to-end encrypted
  4. Use for coordinating file transfers

Copy-Paste Text Sharing

Share text quickly:

  1. Copy text to clipboard
  2. In Drop, click paste icon or press Ctrl+V (Cmd+V on Mac)
  3. Text appears in chat for recipient
  4. Recipient can copy from chat

Multiple Files

Transfer multiple files simultaneously:

  1. Select multiple files in file picker
  2. Or drag multiple files onto window
  3. Each file transfers independently
  4. Can cancel individual transfers

Mobile Usage

Drop works seamlessly on mobile:

  1. Visit Drop URL on mobile browser
  2. Use Share menu to send files
  3. Or use camera to capture and share
  4. Install as PWA for app-like experience

Sample Code Examples

JavaScript - WebRTC Connection

// Example: Establishing WebRTC peer connection
const configuration = {
iceServers: [
{ urls: 'stun:stun1.l.google.com:19302' },
{
urls: 'turn:your-turn-server.com:3478',
username: 'turnuser',
credential: 'turnpass'
}
]
};
const peerConnection = new RTCPeerConnection(configuration);
// Create data channel for file transfer
const dataChannel = peerConnection.createDataChannel('filetransfer', {
ordered: true
});
dataChannel.onopen = () => {
console.log('Data channel opened');
// Ready to transfer files
};
dataChannel.onmessage = (event) => {
// Handle incoming file chunks
const chunk = event.data;
console.log('Received chunk:', chunk.byteLength, 'bytes');
};
// Send file in chunks
function sendFile(file) {
const chunkSize = 16384; // 16KB chunks
const fileReader = new FileReader();
let offset = 0;
fileReader.onload = (e) => {
dataChannel.send(e.target.result);
offset += e.target.result.byteLength;
if (offset < file.size) {
readSlice(offset);
} else {
console.log('File transfer complete');
}
};
function readSlice(o) {
const slice = file.slice(o, o + chunkSize);
fileReader.readAsArrayBuffer(slice);
}
readSlice(0);
}

JavaScript - WebSocket Signaling

// Connect to Drop signaling server
const ws = new WebSocket('wss://example-app.klutch.sh');
ws.onopen = () => {
console.log('Connected to signaling server');
// Create or join room
ws.send(JSON.stringify({
type: 'create-room',
roomCode: '1234'
}));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
switch(message.type) {
case 'room-created':
console.log('Room created:', message.roomCode);
break;
case 'peer-joined':
console.log('Peer joined room');
// Initiate WebRTC connection
createOffer();
break;
case 'webrtc-offer':
// Handle WebRTC offer from peer
handleOffer(message.offer);
break;
case 'webrtc-answer':
// Handle WebRTC answer from peer
handleAnswer(message.answer);
break;
case 'ice-candidate':
// Add ICE candidate for NAT traversal
addIceCandidate(message.candidate);
break;
}
};
// Send WebRTC offer to peer via signaling
function createOffer() {
peerConnection.createOffer()
.then(offer => peerConnection.setLocalDescription(offer))
.then(() => {
ws.send(JSON.stringify({
type: 'webrtc-offer',
offer: peerConnection.localDescription
}));
});
}

TypeScript - File Encryption

// Example: Encrypting files before transfer
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
interface EncryptedFile {
data: ArrayBuffer;
iv: Uint8Array;
filename: string;
mimeType: string;
}
async function encryptFile(
file: File,
key: CryptoKey
): Promise<EncryptedFile> {
// Generate random initialization vector
const iv = randomBytes(16);
// Read file as array buffer
const fileBuffer = await file.arrayBuffer();
// Encrypt file data
const encryptedData = await crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: iv
},
key,
fileBuffer
);
return {
data: encryptedData,
iv: new Uint8Array(iv),
filename: file.name,
mimeType: file.type
};
}
async function decryptFile(
encryptedFile: EncryptedFile,
key: CryptoKey
): Promise<File> {
// Decrypt file data
const decryptedData = await crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: encryptedFile.iv
},
key,
encryptedFile.data
);
// Create File object from decrypted data
return new File(
[decryptedData],
encryptedFile.filename,
{ type: encryptedFile.mimeType }
);
}
// Generate shared encryption key using ECDH
async function generateSharedKey(): Promise<CryptoKey> {
const keyPair = await crypto.subtle.generateKey(
{
name: 'ECDH',
namedCurve: 'P-256'
},
true,
['deriveKey']
);
// Exchange public keys with peer via signaling
// Derive shared key from peer's public key
const sharedKey = await crypto.subtle.deriveKey(
{
name: 'ECDH',
public: peerPublicKey
},
keyPair.privateKey,
{
name: 'AES-GCM',
length: 256
},
false,
['encrypt', 'decrypt']
);
return sharedKey;
}

Python - Testing WebSocket Signaling

# Test Drop signaling server connectivity
import asyncio
import websockets
import json
async def test_drop_signaling():
uri = "wss://example-app.klutch.sh"
async with websockets.connect(uri) as websocket:
print("Connected to Drop signaling server")
# Create room
await websocket.send(json.dumps({
"type": "create-room",
"roomCode": "1234"
}))
# Listen for messages
async for message in websocket:
data = json.loads(message)
print(f"Received: {data['type']}")
if data['type'] == 'room-created':
print(f"Room created: {data['roomCode']}")
break
# Run test
asyncio.run(test_drop_signaling())

Bash - Health Check Script

#!/bin/bash
# Health check script for Drop deployment
DROP_URL="https://example-app.klutch.sh"
# Check HTTP response
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$DROP_URL")
if [ "$HTTP_CODE" -eq 200 ]; then
echo "✓ Drop is responding (HTTP $HTTP_CODE)"
else
echo "✗ Drop returned HTTP $HTTP_CODE"
exit 1
fi
# Check WebSocket upgrade support
WS_CHECK=$(curl -s -I "$DROP_URL" | grep -i "upgrade")
if [ -n "$WS_CHECK" ]; then
echo "✓ WebSocket support detected"
else
echo "⚠ WebSocket support not confirmed"
fi
# Check if frontend loads
FRONTEND_CHECK=$(curl -s "$DROP_URL" | grep -i "filedrop\|drop")
if [ -n "$FRONTEND_CHECK" ]; then
echo "✓ Frontend loaded successfully"
else
echo "✗ Frontend not loading properly"
exit 1
fi
echo "✓ All health checks passed"

Advanced Configuration

Custom Branding

Customize Drop’s appearance and branding:

Build-time environment variables (set before building):

VITE_APP_NAME=YourCompany FileShare

Runtime environment variables:

WS_APP_NAME=YourCompany FileShare
NOTICE_TEXT=Secure file sharing powered by YourCompany
NOTICE_URL=https://yourcompany.com/help

Custom domain: Configure a custom domain in Klutch.sh dashboard for branded URLs.

Connection Limits and Performance

Tune performance for your use case:

# Maximum users per room (default: 64)
WS_MAX_NETWORK_CLIENTS=32
# Maximum WebSocket message size in bytes (default: 65536)
# Should accommodate preview thumbnails
WS_MAX_SIZE=131072
# Enable abuse email for reporting
WS_ABUSE_EMAIL=abuse@yourdomain.com

Security Hardening

Enhance security for production deployments:

# Require HTTPS for all connections (recommended)
WS_REQUIRE_CRYPTO=1
# Trust X-Forwarded-For header (required behind Klutch.sh proxy)
WS_USE_X_FORWARDED_FOR=1
# Use TURN with HMAC authentication for time-limited credentials
TURN_MODE=hmac
TURN_SECRET=long-random-secret-string
TURN_EXPIRY=3600
# Enable secure TURN over TLS
TURN_SERVER=turns:your-turn-server.com:5349

Monitoring and Logging

Monitor your Drop instance:

// Add logging middleware
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
next();
});
// Track WebSocket connections
let activeConnections = 0;
wss.on('connection', (ws) => {
activeConnections++;
console.log(`New connection. Total: ${activeConnections}`);
ws.on('close', () => {
activeConnections--;
console.log(`Connection closed. Total: ${activeConnections}`);
});
});
// Health endpoint with metrics
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
uptime: process.uptime(),
activeConnections,
memory: process.memoryUsage(),
timestamp: new Date().toISOString()
});
});

Production Best Practices

HTTPS Configuration

Drop requires HTTPS for WebRTC to function properly:

  • Klutch.sh provides automatic HTTPS certificates
  • Ensure WS_REQUIRE_CRYPTO=1 is set
  • Use secure WebSocket connections (wss://)
  • Configure TURN with TLS (turns://) for enhanced security

TURN Server Recommendations

For production deployments with global users:

Self-Hosted Coturn:

  • Deploy on separate infrastructure with dedicated bandwidth
  • Configure HMAC authentication for security
  • Monitor TURN server bandwidth usage
  • Plan for UDP ports 49152-65535 availability
  • Budget for data transfer costs

Managed TURN Services:

  • Lower operational overhead
  • Global presence reduces latency
  • Pay-as-you-go pricing
  • Automatic scaling
  • Built-in monitoring

TURN Configuration Best Practices:

# Use HMAC for time-limited credentials
TURN_MODE=hmac
# Shorter expiry for better security (seconds)
TURN_EXPIRY=1800
# Use secure TURN over TLS
TURN_SERVER=turns:turn.example.com:5349
# Strong random secret
TURN_SECRET=use-long-random-string-here

Performance Optimization

Resource Allocation:

  • Drop signaling server is lightweight (512MB RAM sufficient for most deployments)
  • WebRTC peer connections happen client-side (no server bandwidth for files)
  • Scale horizontally for high concurrent connections
  • Monitor WebSocket connection counts

Connection Management:

# Limit room size based on use case
WS_MAX_NETWORK_CLIENTS=8 # For small teams
WS_MAX_NETWORK_CLIENTS=32 # For larger groups
# Adjust message size for larger thumbnails
WS_MAX_SIZE=131072 # 128KB for high-quality previews

Load Balancing: For high-traffic deployments:

  • Deploy multiple Drop instances
  • Use consistent hashing for room assignment
  • Share TURN server across instances
  • Monitor individual instance health

Backup and Disaster Recovery

Drop is stateless and requires no backup:

  • No user data stored on server
  • Peer connections are ephemeral
  • Configuration stored in environment variables
  • Easy to redeploy from Dockerfile

Disaster Recovery Plan:

  1. Keep Dockerfile and configuration in version control
  2. Document TURN server configuration
  3. Test redeployment process regularly
  4. Monitor uptime with external service
  5. Plan for TURN server failover

Security Considerations

Network Security:

  • Drop never sees file contents (end-to-end encrypted)
  • Server only handles signaling messages
  • Enable WS_REQUIRE_CRYPTO to enforce HTTPS
  • Use TURN over TLS for relay traffic

Abuse Prevention:

# Set abuse contact email
WS_ABUSE_EMAIL=abuse@yourdomain.com
# Limit connections per room
WS_MAX_NETWORK_CLIENTS=64
# Monitor for unusual activity
# - High connection rates
# - Unusual message patterns
# - Bandwidth spikes

Access Control (optional enhancements):

  • Add authentication layer via reverse proxy
  • Implement rate limiting for room creation
  • Use firewall rules to restrict access by geography
  • Monitor room creation patterns

Scaling Strategies

Horizontal Scaling:

  1. Deploy multiple Drop instances behind load balancer
  2. Use WebSocket-aware load balancing (sticky sessions)
  3. Share TURN server across instances
  4. Monitor per-instance connection counts

Vertical Scaling:

  • Increase container resources for high concurrent connections
  • Monitor CPU usage during peak times
  • Scale WebSocket connection limits

Geographic Distribution:

  • Deploy Drop instances in multiple regions
  • Use geo-routing for lowest latency
  • Deploy regional TURN servers
  • Monitor connection success rates by region

Troubleshooting

Issue: Connection Fails Between Peers

Symptoms: Users in same room cannot establish peer connection

Possible Causes and Solutions:

  1. NAT/Firewall Issues:

    • Configure TURN server for relay
    • Verify TURN credentials are correct
    • Check TURN server ports are accessible
    • Test with TURN_MODE=hmac for better security
  2. HTTPS Not Configured:

    • Verify WS_REQUIRE_CRYPTO=1 is set
    • Access via HTTPS URL (Klutch.sh provides automatically)
    • Check browser console for security errors
  3. Incorrect STUN/TURN Configuration:

    # Verify configuration
    STUN_SERVER=stun:stun1.l.google.com:19302
    TURN_SERVER=turn:your-server.com:3478
    TURN_USERNAME=username
    TURN_CREDENTIAL=password
  4. WebSocket Connection Failed:

    • Check Drop is running and accessible
    • Verify WebSocket upgrade is working
    • Test with: curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" https://your-app.klutch.sh

Issue: Files Not Transferring

Symptoms: Connection established but files don’t transfer

Solutions:

  1. Browser Compatibility:

    • Use modern browsers (Chrome, Firefox, Safari, Edge)
    • Ensure WebRTC is enabled in browser settings
    • Check browser console for errors
  2. File Size Limits:

    • Check browser memory limits
    • Try smaller files first
    • Monitor browser console for memory errors
  3. Network Quality:

    • Verify stable internet connection
    • Check for packet loss or high latency
    • Consider using TURN server for poor connections
  4. Encryption Issues:

    • Verify both peers support WebCrypto API
    • Check for TLS/SSL errors
    • Ensure HTTPS is properly configured

Issue: WebSocket Connection Drops

Symptoms: Signaling connection disconnects frequently

Solutions:

  1. Proxy Timeout:

    # Increase WebSocket idle timeout
    # (Configure at infrastructure level)
  2. Connection Limits:

    # Check if hitting connection limits
    WS_MAX_NETWORK_CLIENTS=64
  3. Server Resources:

    • Monitor Drop container CPU/memory usage
    • Check Klutch.sh logs for OOM errors
    • Scale up container resources if needed
  4. Network Issues:

    • Check for network instability
    • Verify DNS resolution
    • Test from different networks

Issue: High Latency or Slow Transfers

Symptoms: File transfers are slower than expected

Solutions:

  1. Use TURN Server:

    • Configure TURN for relay when direct P2P is slow
    • Choose geographically close TURN server
    • Monitor TURN server bandwidth
  2. Network Conditions:

    • Test internet speed on both peers
    • Check for bandwidth throttling
    • Verify low latency to signaling server
  3. Browser Performance:

    • Close unnecessary browser tabs
    • Disable browser extensions
    • Try different browser

Issue: Room Code Not Working

Symptoms: Cannot join room with valid code

Solutions:

  1. Room Expired:

    • Rooms are ephemeral and expire when creator leaves
    • Create new room if needed
    • Ensure both users are online simultaneously
  2. Incorrect Code:

    • Verify 4-digit code is entered correctly
    • Check for typos (similar looking characters)
    • Create new room if unsure
  3. Connection Limit Reached:

    # Check if room is full
    WS_MAX_NETWORK_CLIENTS=64
  4. Server Issues:

    • Verify Drop is running and accessible
    • Check Klutch.sh deployment logs
    • Restart deployment if needed

Debugging Tools

Browser Console:

// Check WebRTC connection state
peerConnection.connectionState
peerConnection.iceConnectionState
// View ICE candidates
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
console.log('ICE candidate:', event.candidate);
}
};
// Monitor data channel
dataChannel.onopen = () => console.log('Data channel open');
dataChannel.onclose = () => console.log('Data channel closed');
dataChannel.onerror = (error) => console.error('Data channel error:', error);

Server Logs:

Terminal window
# View Klutch.sh deployment logs
# Available in Klutch.sh dashboard
# Look for WebSocket connection events
# Monitor room creation/join events
# Check for error messages

Network Testing:

Terminal window
# Test STUN server connectivity
npm install -g stun
# Test TURN server
turnutils_uclient -v -u username -w password turn:your-server.com:3478

Additional Resources


You now have a fully functional Drop instance deployed on Klutch.sh! Users can securely transfer files with end-to-end encryption, knowing their data never touches your servers. Configure TURN for global reliability, customize branding for your organization, and scale as your user base grows.