Skip to content
Low Level Design Mastery Logo
LowLevelDesign Mastery

Design Ngrok Tool

Design a secure, multi-protocol tunneling service for local-to-internet exposure.

Design a secure tunneling service that allows developers to expose their local servers to the internet without complex network configurations. The system should support multiple protocols (HTTP, HTTPS, TCP), provide real-time traffic inspection, handle authentication, and manage concurrent tunnel connections while ensuring data security and high availability.

In this problem, you’ll design the coordination between a public TunnelServer and a local ClientAgent, ensuring that traffic is securely routed and inspected in real-time.


Design a service that provides public URLs for local servers, handling the secure routing of requests through established persistent tunnels.

Functional Requirements:

  • Tunnel Creation: Allow users to request a tunnel for a specific local port and protocol.
  • URL Generation: Assign unique, public-facing URLs (e.g., xyz.tunnel.io).
  • Bidirectional Routing: Forward public requests to the local agent and return local responses.
  • Lifecycle Management: Track states like CREATING, ACTIVE, and DISCONNECTED.
  • Traffic Inspection: Log and display real-time request/response data.
  • Multi-protocol Support: Handle HTTP, HTTPS, and raw TCP traffic.

Non-Functional Requirements:

  • Security: Ensure all data moving through the tunnel is encrypted.
  • Availability: Handle automatic reconnection if the link is interrupted.
  • Scalability: Support thousands of concurrent tunnels per server.
  • Low Overhead: Minimize latency introduced by the forwarding hop.

The system coordinates between the TunnelServer (Public) and the ClientAgent (Private).

Diagram
classDiagram
    class TunnelServer {
        -Map~String, Tunnel~ activeTunnels
        -AuthService auth
        +createTunnel(userId, port)
        +routeTraffic(publicUrl, data)
    }
    
    class Tunnel {
        -String publicUrl
        -TunnelState state
        -ProtocolHandler handler
        -Connection agentLink
        +transitionState(newState)
    }
    
    class ClientAgent {
        -String apiToken
        -int localPort
        +connectToServer()
        +forwardToLocal(data)
    }

    class ProtocolHandler {
        <<interface>>
        +handle(data)
    }

    TunnelServer "1" *-- "many" Tunnel
    Tunnel --> TunnelState
    Tunnel --> ProtocolHandler
    ClientAgent --> Tunnel

Diagram

Since the local server is behind a firewall, the server cannot “call” the agent.

Solution: The Client-Initiated Persistent Connection. The agent initiates a long-lived TCP or WebSocket connection to the server. The server keeps this socket open. When traffic arrives at the public URL, the server “reuses” this existing socket to push data down to the agent.

Network blips happen. If the socket closes, the tunnel shouldn’t just vanish.

Solution: Use the State Pattern. When the socket drops, the tunnel moves to DISCONNECTED. The agent starts an exponential backoff retry logic. If it reconnects within a timeout (e.g., 5 minutes), the state moves back to ACTIVE and the same public URL is preserved.

Routing raw TCP traffic is very different from parsing HTTP headers for inspection.

Solution: Use the Strategy Pattern. The Tunnel object holds a ProtocolHandler. For HTTP, the handler parses headers and notifies TrafficObservers. For TCP, the handler just pipes raw bytes as fast as possible.


By solving this problem, you’ll master:

  • Network Proxy Logic - Building bridges across firewalls.
  • State Machines - Managing complex connection lifecycles.
  • Protocol Abstraction - Handling HTTP vs TCP uniformly.
  • Real-time Inspection - Using the Observer pattern for live data logging.

Ready to see the full implementation? Open the interactive playground to access:

  • 🎯 Step-by-step guidance through the 8-step LLD approach
  • 📊 Interactive UML builder to visualize your design
  • 💻 Complete Code Solutions in Python, Java, C++, TypeScript, JavaScript, C#
  • 🤖 AI-powered review of your design and code

After mastering Ngrok, try these similar problems: