DEV Community

Ahmet YİLDİRİM
Ahmet YİLDİRİM

Posted on

WebRTC + Signaling Server

Building a Zero-Storage Peer-to-Peer File Transfer Service: How We Built KA-UPLOAD

TL;DR: We built a peer-to-peer file transfer service using WebRTC that requires zero server storage, supports unlimited file sizes, and works without signup. Files transfer directly from browser to browser. Here's how we did it.

The Problem with Traditional File Sharing

When you need to send a large file, you're usually stuck with one of these options:

  • Email: Limited to 25MB, files get stuck in spam filters
  • Cloud Storage: Requires upload to a server, privacy concerns, storage costs
  • Traditional Services: WeTransfer, Dropbox Transfer - all require server uploads, file size limits, and signup requirements

What if you could send files directly from your browser to someone else's browser, with zero server storage, unlimited file sizes, and no signup required?

That's exactly what we built with KA-UPLOAD - a peer-to-peer file transfer service that uses WebRTC to enable direct browser-to-browser file transfers.

The Architecture: WebRTC + Signaling Server

Core Technology Stack

  • Frontend: Vanilla JavaScript, Tailwind CSS, WebRTC API
  • Backend: PHP 7.4+ with MySQL for signaling and authentication
  • WebRTC: PeerJS library for simplified peer-to-peer connections
  • Desktop App: Electron for native desktop experience
  • Payment Processing: Stripe for subscription management

How It Works: The Technical Deep Dive

1. Signaling Phase

When a user wants to send a file, they create a transfer link. This link contains a unique code that acts as a "room identifier" for the WebRTC connection.

// Sender creates a peer connection
const peer = new Peer(linkCode, {
    host: 'peerjs-server.com',
    port: 443,
    path: '/',
    secure: true
});
Enter fullscreen mode Exit fullscreen mode

The signaling server (PeerJS cloud service) helps establish the initial connection between peers, but once connected, all data flows directly between browsers.

2. Peer Discovery

The receiver visits the share link (e.g., ka-upload.com/d/abc123). The page loads a WebRTC client that:

  1. Connects to the same PeerJS server
  2. Uses the link code to find the sender's peer ID
  3. Establishes a direct peer-to-peer connection
// Receiver connects to sender
const connection = peer.connect(senderPeerId);
connection.on('open', () => {
    // Direct connection established!
    // No server involved in data transfer
});
Enter fullscreen mode Exit fullscreen mode

3. File Streaming

Files are streamed in 8KB chunks using WebRTC DataChannels:

// Sender streams file in chunks
const chunkSize = 8 * 1024; // 8KB chunks
const fileStream = fs.createReadStream(filePath, { 
    highWaterMark: chunkSize 
});

fileStream.on('data', (chunk) => {
    // Convert to base64 for JSON transmission
    const base64 = chunk.toString('base64');

    // Send via WebRTC DataChannel
    dataChannel.send(JSON.stringify({
        type: 'file-chunk',
        data: base64,
        chunkIndex: chunkIndex++,
        size: chunk.length
    }));
});
Enter fullscreen mode Exit fullscreen mode

Why 8KB chunks?

  • 8KB binary → ~10.67KB base64 → ~12KB JSON
  • Well under WebRTC's 64KB message limit
  • Optimal balance between speed and reliability
  • Reduces memory overhead for large files

4. Zero Server Storage

The key innovation: files never touch our servers. The PHP backend only handles:

  • Link creation and metadata storage
  • User authentication
  • Signaling coordination
  • Payment processing

The actual file data flows directly from sender to receiver via WebRTC.

Security Implementation

End-to-End Encryption

WebRTC provides built-in encryption (DTLS-SRTP) for all data channels. Files are encrypted in transit without any additional code needed.

Additional Security Layers

  1. Password Protection: Optional password for transfer links
  2. Link Expiration: Automatic expiration (24 hours free, up to 30 days for Pro)
  3. Rate Limiting: Server-side rate limiting to prevent abuse
  4. SQL Injection Protection: PDO prepared statements
  5. XSS Prevention: Input sanitization and output escaping
  6. CSRF Protection: Token-based protection for forms
// Example: Secure link creation
function createTransferLink($userId, $password = null) {
    $linkCode = bin2hex(random_bytes(16)); // 32-char secure code
    $expiresAt = date('Y-m-d H:i:s', time() + 86400); // 24 hours

    // Hash password if provided
    $passwordHash = $password ? password_hash($password, PASSWORD_BCRYPT) : null;

    // Store only metadata, not file data
    $stmt = $pdo->prepare("
        INSERT INTO transfer_links 
        (link_code, user_id, password_hash, expires_at) 
        VALUES (?, ?, ?, ?)
    ");
    $stmt->execute([$linkCode, $userId, $passwordHash, $expiresAt]);

    return $linkCode;
}
Enter fullscreen mode Exit fullscreen mode

Performance Optimizations

1. Chunked Streaming

Instead of loading entire files into memory, we stream in 8KB chunks:

// Efficient chunked reading
const fileStream = fs.createReadStream(filePath, { 
    highWaterMark: 8 * 1024 
});
Enter fullscreen mode Exit fullscreen mode

This allows transferring files of any size without memory issues.

2. Base64 Encoding

We use base64 encoding for binary data transmission over WebRTC DataChannels, which only support strings. The overhead (~33%) is acceptable for the convenience of direct browser-to-browser transfer.

3. Progress Tracking

Real-time progress updates without polling:

connection.on('data', (data) => {
    if (data.type === 'file-chunk') {
        receivedBytes += data.size;
        const progress = (receivedBytes / fileSize) * 100;
        updateProgressBar(progress);
    }
});
Enter fullscreen mode Exit fullscreen mode

4. Connection Resilience

The system handles:

  • Network interruptions
  • NAT traversal (via STUN/TURN servers)
  • Browser compatibility (Chrome, Firefox, Safari, Edge)
  • Automatic reconnection attempts

Desktop App Integration

We built an Electron-based desktop app that integrates seamlessly with the web service:

  • Always-on Background Mode: Runs in system tray
  • Auto-start: Launches on system boot
  • Same WebRTC Technology: Uses identical peer-to-peer connection
  • Native File Selection: Better UX than browser file picker

The desktop app uses the same 8KB chunk streaming and connects to the same signaling infrastructure.

API for Developers

We provide a RESTful API for developers to integrate file transfer into their applications:

// Create a transfer link via API
const response = await fetch('https://ka-upload.com/api/links/create.php', {
    method: 'POST',
    headers: {
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        expires_hours: 24,
        password: 'optional-password'
    })
});
Enter fullscreen mode Exit fullscreen mode

Rate Limits:

  • Free tier: 100 requests/hour
  • Premium: 1,000 requests/hour
  • Pro: 10,000 requests/hour

Challenges and Solutions

Challenge 1: NAT Traversal

Problem: Many users are behind NATs/firewalls that block direct peer connections.

Solution:

  • Use PeerJS cloud service (includes STUN/TURN servers)
  • Automatic fallback to relay servers when direct connection fails
  • Transparent to users - works in most network configurations

Challenge 2: Large File Handling

Problem: Browsers have memory limits, and loading entire files causes crashes.

Solution:

  • Stream files in 8KB chunks
  • Process chunks as they arrive
  • Never load entire file into memory
  • Works for files of any size

Challenge 3: Simultaneous Connection Requirement

Problem: Both sender and receiver must be online at the same time.

Solution:

  • Clear messaging to users about this requirement
  • Desktop app can stay online in background
  • Future: Add queue system for offline receivers

Real-World Performance

In testing, we've achieved:

  • Transfer speeds: Limited only by users' internet connections
  • File sizes: Successfully tested with files up to 50GB+
  • Concurrent transfers: Multiple simultaneous transfers supported
  • Uptime: 99.9%+ reliability with PeerJS cloud infrastructure

Future Enhancements

  1. Resume Support: Resume interrupted transfers
  2. Multiple Files: Transfer multiple files in one session
  3. Mobile Apps: Native iOS/Android apps
  4. TURN Server: Self-hosted TURN server for better NAT traversal
  5. Analytics Dashboard: Transfer statistics and insights
  6. Webhook Support: Notify external services on transfer completion

Lessons Learned

  1. WebRTC is powerful but complex: The signaling phase requires careful coordination
  2. Chunk size matters: 8KB provides optimal balance for most use cases
  3. User education is key: Users need to understand the peer-to-peer model
  4. Fallbacks are essential: Always have relay servers for NAT traversal
  5. Privacy sells: Users appreciate zero-storage architecture

Conclusion

Building a zero-storage file transfer service with WebRTC was challenging but rewarding. The result is a service that:

  • ✅ Respects user privacy (no server storage)
  • ✅ Handles unlimited file sizes
  • ✅ Works without signup
  • ✅ Provides real-time transfer speeds
  • ✅ Offers enterprise-grade security

The technology stack (WebRTC + PHP + Electron) proved to be the right choice for building a production-ready peer-to-peer file transfer service.

Try it out: ka-upload.com

API Documentation: ka-upload.com/api


Discussion

Have you built something with WebRTC? What challenges did you face? Share your experiences in the comments below!

Questions about the implementation? Feel free to ask - I'm happy to dive deeper into any part of the architecture.


Tags: #webrtc #javascript #php #p2p #filetransfer #webdev #programming #tutorial #showdev

Top comments (0)