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
- User A accesses Drop and creates a room (generates 4-digit code)
- WebSocket signaling server assigns User A to a room
- User B enters the room code and joins
- Peers exchange WebRTC signaling messages via WebSocket
- Direct peer-to-peer connection established using WebRTC
- Files are encrypted and transferred directly between browsers
- 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:
mkdir drop-klutchcd drop-klutchgit initStep 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 applicationFROM node:20-alpine AS build
WORKDIR /app
# Install build dependenciesRUN apk add --no-cache bash git
# Clone Drop repositoryRUN git clone https://github.com/mat-sz/filedrop.git .
# Install dependencies using Corepack (Yarn Berry)RUN corepack enable && corepack yarn install
# Build frontend applicationRUN corepack yarn build
# Move built frontend to separate locationRUN mv web/build web_build && rm -rf web
# Clean up build artifacts to reduce image sizeRUN rm -rf node_modules && \ corepack yarn cache clean && \ rm -rf /root/.npm
# Install production dependencies onlyRUN corepack yarn install --production
# Production stage - minimal runtime imageFROM node:20-alpine
WORKDIR /app
# Install runtime dependenciesRUN apk add --no-cache bash
# Enable Corepack for YarnRUN corepack enable
# Copy application files from build stageCOPY --from=build /app /app
# Set environment variablesENV NODE_ENV=production \ WS_HOST=0.0.0.0 \ WS_PORT=5000 \ WS_STATIC_ROOT=../web_build \ WS_APP_NAME=Drop
# Expose signaling server portEXPOSE 5000
# Health check to verify server is runningHEALTHCHECK --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 serverCMD ["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 SettingsNODE_ENV=productionWS_APP_NAME=DropWS_ABUSE_EMAIL=abuse@yourdomain.com
# Server ConfigurationWS_HOST=0.0.0.0WS_PORT=5000WS_STATIC_ROOT=../web_build
# Security SettingsWS_USE_X_FORWARDED_FOR=1WS_REQUIRE_CRYPTO=1
# Connection LimitsWS_MAX_SIZE=65536WS_MAX_NETWORK_CLIENTS=64
# WebRTC STUN ConfigurationSTUN_SERVER=stun:stun1.l.google.com:19302
# TURN Server Configuration (Optional - for NAT traversal)TURN_MODE=defaultTURN_SERVER=TURN_USERNAME=TURN_CREDENTIAL=TURN_SECRET=TURN_EXPIRY=3600
# Notice Configuration (Optional)NOTICE_TEXT=NOTICE_URL=
# Build-time Configuration (optional)VITE_APP_NAME=DropKey Configuration Options:
WS_APP_NAME: Branding for your Drop instanceWS_ABUSE_EMAIL: Contact email for abuse reportsWS_USE_X_FORWARDED_FOR: Must be1when behind Klutch.sh proxyWS_REQUIRE_CRYPTO: Enforces HTTPS for all connectionsWS_MAX_NETWORK_CLIENTS: Limits users per room (default 64)TURN_MODE: Set tohmacfor time-limited TURN credentials
Step 4: Create .dockerignore File
Create .dockerignore to exclude unnecessary files from the build:
.git.github.gitignorenode_modulesnpm-debug.logyarn-error.log*.md.env.env.local.DS_Storedocs/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 service2. Set `TURN_MODE=hmac` for secure time-limited credentials3. Configure `TURN_SERVER`, `TURN_SECRET`, and `TURN_EXPIRY`
## Usage
1. Visit your deployed Drop instance2. Click "Create Room" to generate a 4-digit code3. Share the code with intended recipient4. Recipient enters code to join room5. Transfer files directly via encrypted peer connection
## License
BSD-3-Clause-Clear (Filedrop) - See original repository for detailsStep 6: Initialize Git and Push to GitHub
# Initialize git repositorygit init
# Add all filesgit add Dockerfile .dockerignore .env.example README.md
# Commit filesgit 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 GitHubgit branch -M maingit push -u origin mainDeploying to Klutch.sh
Step 1: Create New App
- Navigate to the Klutch.sh dashboard
- Click **Create New App** or **New Deployment**
- Select **GitHub** as your source
- Authenticate with GitHub if not already connected
- Choose your Drop repository from the list
- Select the `main` branch for deployment
Step 2: Configure Application Settings
- **App Name**: Choose a unique name (e.g., `drop-filetransfer`)
- **Traffic Type**: Select **HTTP** traffic
- **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=DropWS_HOST=0.0.0.0WS_PORT=5000WS_STATIC_ROOT=../web_buildWS_USE_X_FORWARDED_FOR=1WS_REQUIRE_CRYPTO=1Recommended Variables:
WS_ABUSE_EMAIL=abuse@yourdomain.comWS_MAX_NETWORK_CLIENTS=64STUN_SERVER=stun:stun1.l.google.com:19302Optional TURN Server (for better connectivity):
TURN_MODE=hmacTURN_SERVER=turn:your-turn-server.com:3478TURN_SECRET=your-turn-server-secretTURN_EXPIRY=3600Optional Branding:
VITE_APP_NAME=YourBrand DropNOTICE_TEXT=Welcome to secure file sharingNOTICE_URL=https://yourdomain.comStep 4: Deploy Application
- Click **Deploy** or **Create App**
- Klutch.sh will automatically detect the Dockerfile and build your container
- Wait for the build to complete (typically 3-5 minutes)
- Once deployed, your app will be available at `https://your-app-name.klutch.sh`
Step 5: Verify Deployment
Test your Drop instance:
- Navigate to `https://your-app-name.klutch.sh`
- Click **Create Room** - you should see a 4-digit code
- Open an incognito/private window and enter the code
- Verify both peers see each other connected
- 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 configurationCOPY turnserver.conf /etc/coturn/turnserver.conf
# Expose TURN portsEXPOSE 3478/tcpEXPOSE 3478/udpEXPOSE 49152-65535/udp
CMD ["turnserver", "-c", "/etc/coturn/turnserver.conf"]turnserver.conf:
listening-port=3478fingerprintlt-cred-mechuse-auth-secretstatic-auth-secret=YOUR_TURN_SECRET_HERErealm=example-app.klutch.shtotal-quota=100bps-capacity=0stale-nonce=600no-multicast-peersDeploy 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=defaultTURN_SERVER=turn:global.turn.twilio.com:3478?transport=tcpTURN_USERNAME=your-twilio-usernameTURN_CREDENTIAL=your-twilio-credentialFor HMAC-based authentication:
TURN_MODE=hmacTURN_SERVER=turn:your-turn-server.com:3478TURN_SECRET=shared-secret-with-turn-serverTURN_EXPIRY=3600Getting Started with Drop
Basic File Transfer
Sender (User A):
- Navigate to your Drop instance
- Click Create Room button
- Note the 4-digit code displayed (e.g., 1234)
- Share code with recipient via secure channel
Receiver (User B):
- Navigate to same Drop instance
- Enter 4-digit code in input field
- Click Join or press Enter
- Wait for connection to establish
Transfer Files:
- Once connected, drag files onto window
- Or click upload button to select files
- Files transfer directly between browsers
- Progress bar shows transfer status
Using Chat Feature
While connected in a room:
- Type message in chat input at bottom
- Press Enter to send
- Messages are end-to-end encrypted
- Use for coordinating file transfers
Copy-Paste Text Sharing
Share text quickly:
- Copy text to clipboard
- In Drop, click paste icon or press Ctrl+V (Cmd+V on Mac)
- Text appears in chat for recipient
- Recipient can copy from chat
Multiple Files
Transfer multiple files simultaneously:
- Select multiple files in file picker
- Or drag multiple files onto window
- Each file transfers independently
- Can cancel individual transfers
Mobile Usage
Drop works seamlessly on mobile:
- Visit Drop URL on mobile browser
- Use Share menu to send files
- Or use camera to capture and share
- Install as PWA for app-like experience
Sample Code Examples
JavaScript - WebRTC Connection
// Example: Establishing WebRTC peer connectionconst 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 transferconst 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 chunksfunction 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 serverconst 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 signalingfunction 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 transferimport { 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 ECDHasync 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 connectivityimport asyncioimport websocketsimport 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 testasyncio.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 responseHTTP_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 1fi
# Check WebSocket upgrade supportWS_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 loadsFRONTEND_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 1fi
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 FileShareRuntime environment variables:
WS_APP_NAME=YourCompany FileShareNOTICE_TEXT=Secure file sharing powered by YourCompanyNOTICE_URL=https://yourcompany.com/helpCustom 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 thumbnailsWS_MAX_SIZE=131072
# Enable abuse email for reportingWS_ABUSE_EMAIL=abuse@yourdomain.comSecurity 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 credentialsTURN_MODE=hmacTURN_SECRET=long-random-secret-stringTURN_EXPIRY=3600
# Enable secure TURN over TLSTURN_SERVER=turns:your-turn-server.com:5349Monitoring and Logging
Monitor your Drop instance:
// Add logging middlewareconst express = require('express');const app = express();
app.use((req, res, next) => { console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`); next();});
// Track WebSocket connectionslet 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 metricsapp.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=1is 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 credentialsTURN_MODE=hmac
# Shorter expiry for better security (seconds)TURN_EXPIRY=1800
# Use secure TURN over TLSTURN_SERVER=turns:turn.example.com:5349
# Strong random secretTURN_SECRET=use-long-random-string-herePerformance 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 caseWS_MAX_NETWORK_CLIENTS=8 # For small teamsWS_MAX_NETWORK_CLIENTS=32 # For larger groups
# Adjust message size for larger thumbnailsWS_MAX_SIZE=131072 # 128KB for high-quality previewsLoad 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:
- Keep Dockerfile and configuration in version control
- Document TURN server configuration
- Test redeployment process regularly
- Monitor uptime with external service
- 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_CRYPTOto enforce HTTPS - Use TURN over TLS for relay traffic
Abuse Prevention:
# Set abuse contact emailWS_ABUSE_EMAIL=abuse@yourdomain.com
# Limit connections per roomWS_MAX_NETWORK_CLIENTS=64
# Monitor for unusual activity# - High connection rates# - Unusual message patterns# - Bandwidth spikesAccess 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:
- Deploy multiple Drop instances behind load balancer
- Use WebSocket-aware load balancing (sticky sessions)
- Share TURN server across instances
- 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:
-
NAT/Firewall Issues:
- Configure TURN server for relay
- Verify TURN credentials are correct
- Check TURN server ports are accessible
- Test with
TURN_MODE=hmacfor better security
-
HTTPS Not Configured:
- Verify
WS_REQUIRE_CRYPTO=1is set - Access via HTTPS URL (Klutch.sh provides automatically)
- Check browser console for security errors
- Verify
-
Incorrect STUN/TURN Configuration:
# Verify configurationSTUN_SERVER=stun:stun1.l.google.com:19302TURN_SERVER=turn:your-server.com:3478TURN_USERNAME=usernameTURN_CREDENTIAL=password -
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:
-
Browser Compatibility:
- Use modern browsers (Chrome, Firefox, Safari, Edge)
- Ensure WebRTC is enabled in browser settings
- Check browser console for errors
-
File Size Limits:
- Check browser memory limits
- Try smaller files first
- Monitor browser console for memory errors
-
Network Quality:
- Verify stable internet connection
- Check for packet loss or high latency
- Consider using TURN server for poor connections
-
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:
-
Proxy Timeout:
# Increase WebSocket idle timeout# (Configure at infrastructure level) -
Connection Limits:
# Check if hitting connection limitsWS_MAX_NETWORK_CLIENTS=64 -
Server Resources:
- Monitor Drop container CPU/memory usage
- Check Klutch.sh logs for OOM errors
- Scale up container resources if needed
-
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:
-
Use TURN Server:
- Configure TURN for relay when direct P2P is slow
- Choose geographically close TURN server
- Monitor TURN server bandwidth
-
Network Conditions:
- Test internet speed on both peers
- Check for bandwidth throttling
- Verify low latency to signaling server
-
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:
-
Room Expired:
- Rooms are ephemeral and expire when creator leaves
- Create new room if needed
- Ensure both users are online simultaneously
-
Incorrect Code:
- Verify 4-digit code is entered correctly
- Check for typos (similar looking characters)
- Create new room if unsure
-
Connection Limit Reached:
# Check if room is fullWS_MAX_NETWORK_CLIENTS=64 -
Server Issues:
- Verify Drop is running and accessible
- Check Klutch.sh deployment logs
- Restart deployment if needed
Debugging Tools
Browser Console:
// Check WebRTC connection statepeerConnection.connectionStatepeerConnection.iceConnectionState
// View ICE candidatespeerConnection.onicecandidate = (event) => { if (event.candidate) { console.log('ICE candidate:', event.candidate); }};
// Monitor data channeldataChannel.onopen = () => console.log('Data channel open');dataChannel.onclose = () => console.log('Data channel closed');dataChannel.onerror = (error) => console.error('Data channel error:', error);Server Logs:
# View Klutch.sh deployment logs# Available in Klutch.sh dashboard
# Look for WebSocket connection events# Monitor room creation/join events# Check for error messagesNetwork Testing:
# Test STUN server connectivitynpm install -g stun
# Test TURN serverturnutils_uclient -v -u username -w password turn:your-server.com:3478Additional Resources
- Drop (Filedrop) GitHub Repository
- Official Drop Instance
- WebRTC Documentation
- MDN WebRTC Guide
- Coturn TURN Server
- Twilio STUN/TURN
- WebSocket API Documentation
- Web Crypto API (SubtleCrypto)
Related Guides
- Looking for database storage? See our PostgreSQL deployment guide
- Need Redis for session storage? Check our Redis guide
- Building with React? See our Node.js framework guides
- Want real-time features? See our Chitchatter guide for WebRTC chat
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.