ngrok websocket tunneling exposes local WebSocket servers through secure public URLs, handling the 101 Switching Protocols upgrade automatically without special configuration. Developers building real-time apps with platforms like VideoSDK use ngrok to test WebSocket connections during local development. Start with the free tier and scale as your testing needs grow.
Introduction
When you build a real-time application with WebSockets, testing locally works fine until an external service needs to reach your server. A payment provider needs to send webhook events to your local endpoint. A frontend running on a different device needs to connect to your development server. A teammate across the country wants to test your work-in-progress real-time feature.
In all these cases, you need a way to expose your local WebSocket server to the public internet quickly and securely. That is where ngrok comes in. ngrok creates a secure tunnel from a public URL to your local machine, letting anyone on the internet reach your localhost services through a temporary or reserved domain.
For WebSocket-based applications specifically, ngrok handles the protocol upgrade handshake transparently. Your real-time connections work through the tunnel as if they were direct. No special flags, no protocol-specific configuration, no separate tunnel type.
By the end of this guide, you will understand how ngrok websocket tunneling works, how to set it up step by step, how to test and secure your connections, and how to troubleshoot the most common issues developers encounter in 2026.
What is ngrok?
ngrok is defined as a tunneling service that creates secure public URLs for local servers. ngrok works by running a lightweight agent process on your machine that establishes an outbound connection to ngrok's cloud edge infrastructure. The edge assigns a public URL and forwards incoming traffic back through that connection to your local server.
The three core components of ngrok are the agent, the edge, and the dashboard. The agent is the process you run locally. The edge is ngrok's cloud infrastructure that receives public traffic and routes it to your agent. The dashboard is a web interface where you monitor active tunnels, inspect traffic, and manage your account.
You authenticate with an authtoken, which ties your tunnels to your ngrok account and determines your available features and limits. ngrok supports both free and paid tiers. The free tier provides random subdomains and basic tunneling capabilities. Paid plans offer reserved domains, custom subdomains, higher connection limits, and advanced security features like IP allow-lists and OAuth integration.
Understanding ngrok websocket Tunneling
WebSockets use an HTTP upgrade handshake to transition from a standard HTTP connection to a persistent bidirectional connection. The client sends an HTTP request with an Upgrade header. The server responds with a 101 Switching Protocols status. From that point, the connection carries WebSocket frames instead of HTTP requests.
ngrok's HTTP tunnels natively support this upgrade process. When a WebSocket client connects to your ngrok public URL, the edge receives the initial HTTP request, recognizes the Upgrade header, and forwards the entire connection through the tunnel to your local server. Your local server performs the 101 handshake, and ngrok passes WebSocket frames back and forth in both directions.
The underlying transport uses TLS at the edge and a persistent TCP connection between the agent and ngrok's cloud. This means your WebSocket traffic is encrypted from the client to the ngrok edge, and the agent connection is also encrypted, protecting your data in transit. According to the W3C WebSocket specification, the protocol is designed to work over a single TCP connection, which aligns directly with ngrok's transport architecture.
How WebSocket Traffic Flows Through ngrok
The path from client to local server involves four distinct stages. First, the WebSocket client initiates a connection to your ngrok public URL using the wss:// scheme. Second, ngrok's edge terminates the TLS connection and inspects the initial HTTP request, detecting the WebSocket upgrade headers. Third, the edge forwards the request through the encrypted tunnel to the ngrok agent running on your machine. Fourth, the agent passes the request to your local server on the configured port, your server responds with the 101 Switching Protocols handshake, and the bidirectional WebSocket connection is established through the full chain.

Setting Up ngrok for WebSockets
Getting ngrok running for WebSocket development requires four prerequisite steps: creating an account, installing the agent, authenticating, and starting a tunnel.
First, sign up for an ngrok account at ngrok.com. You can start with the free tier, which provides everything you need for local development and testing. After creating your account, download the ngrok agent for your operating system. ngrok provides binaries for macOS, Windows, and Linux, plus package manager installations for Homebrew, Chocolatey, and apt.
After installation, authenticate your agent by configuring your authtoken. This token links your local agent to your ngrok account and unlocks your plan's features. You can find your authtoken in the ngrok dashboard under the authentication section. The agent stores it locally so you only need to configure it once.
Finally, start a tunnel pointing at the local port where your WebSocket server runs. The ngrok agent connects to the nearest edge region automatically and assigns you a public URL. That URL supports both HTTP and WebSocket traffic on the same endpoint, so your real-time connections work alongside any regular HTTP routes your application exposes.
Choosing the Right Tunnel Command
ngrok uses a simple syntax for starting tunnels. You specify the protocol and the local port number. For WebSocket development, you use the same HTTP tunnel command you would use for any web service. The reason no special WebSocket flag exists is that ngrok's HTTP tunnels handle the protocol upgrade automatically. When the edge sees an Upgrade header in an incoming request, it treats the connection as a WebSocket and maintains the persistent connection through the tunnel.
This means if your application serves both a REST API and WebSocket connections on the same port, both work through a single ngrok tunnel without any additional setup. Developers building real-time communication apps with VideoSDK often run their signaling server locally and use ngrok to expose it for testing across devices and team members.
Configuring a Persistent Tunnel with ngrok.yml
For developers who start tunnels frequently, ngrok supports a configuration file that lets you define named tunnels with predefined settings. This file lives in your home directory and allows you to specify the local port, protocol, region, custom domain on paid plans, and additional options like TLS termination behavior or request headers.
The configuration file also supports multiple tunnel definitions, so you can start different tunnels for different projects with a single command referencing the tunnel name. Region selection in the config file is particularly useful for WebSocket development because choosing an edge region close to your machine reduces latency, which matters for real-time connections. You can read more about configuration options in the ngrok documentation.
Testing Your WebSocket Connection
After starting your ngrok tunnel, you should verify that WebSocket connections work end-to-end. Three practical methods cover most testing scenarios.
First, use your browser's developer tools. Open the Network tab, filter by WebSocket connections, and connect your frontend to the ngrok public URL. You should see the initial HTTP request with a 101 response code, followed by WebSocket frames in the messages tab. This confirms the upgrade handshake succeeded and data is flowing in both directions.
Second, use an online WebSocket echo service. Several free tools let you connect to a WebSocket URL and send test messages. Point the tool at your ngrok URL, send a message, and check whether your local server receives and responds correctly. This is useful when you want to test without writing a frontend.
Third, use ngrok's built-in inspection UI. When you start a tunnel, ngrok displays a local web interface that shows all traffic passing through the tunnel. You can inspect HTTP headers, WebSocket frames, connection metadata, and response codes in real time. This is invaluable for debugging because you see exactly what ngrok receives and forwards.
Pay special attention to the 101 Switching Protocols response. If you see it, the upgrade succeeded. If you see a 400 or 500 response instead, your local server may not be handling the WebSocket upgrade correctly, or there may be a sub-protocol mismatch.
Performance Considerations
Adding a tunnel between your client and server introduces latency. For WebSocket applications where real-time responsiveness matters, understanding this overhead is important.
ngrok adds two sources of latency: the round trip through ngrok's edge servers and the encryption and decryption at each hop. In practice, the added latency typically ranges from 10 to 50 milliseconds depending on your geographic distance from the nearest ngrok edge region. For most real-time applications like chat, notifications, and presence updates, this is negligible. For latency-sensitive applications like multiplayer gaming or real-time video signaling, it may be noticeable during testing.
The free tier has bandwidth limits that can affect WebSocket performance under heavy load. If you are streaming large amounts of data through the tunnel, such as binary WebSocket frames for file transfer or media, you may hit these limits. Paid plans offer higher bandwidth ceilings and dedicated capacity.
To minimize latency, select an edge region close to your machine. ngrok operates edge regions in North America, Europe, Asia, and Australia. The agent auto-selects the nearest region, but you can override this in your configuration file. Enabling TCP keep-alive on your WebSocket connections also helps prevent the tunnel from dropping idle connections, which some network configurations close after a period of inactivity.
Monitor performance using the ngrok dashboard, which shows connection counts, data transfer volumes, and response time metrics for your active tunnels. You can check current pricing and bandwidth limits on the ngrok pricing page.
Security Best Practices
Exposing a local server to the public internet carries inherent risks. Even for development purposes, you should follow basic security practices when using ngrok websocket tunnels.
Always use the wss:// scheme for your WebSocket connections. ngrok's edge terminates TLS automatically, so your public URL always supports encrypted connections. Using ws:// (unencrypted) is possible but exposes your traffic to interception. Your local server does not need its own TLS certificate because ngrok handles termination at the edge.
Restrict access to your tunnel when possible. ngrok supports HTTP basic authentication on paid plans, which requires a username and password before any traffic reaches your local server. You can also configure IP allow-lists to restrict access to specific addresses. This is useful when only your frontend server or a known set of testers need access.
Rotate your authtoken periodically. If your authtoken is compromised, an attacker could start tunnels pointing to their own servers using your account. Treat your authtoken like any other credential: do not commit it to version control, do not share it publicly, and regenerate it from the ngrok dashboard if you suspect exposure.
Be cautious about what your local server exposes. When you start an ngrok tunnel, anyone with the URL can access your service. If your development server has debug endpoints, admin panels, or sensitive data, consider protecting those routes independently of ngrok.
Common ngrok websocket Issues and Solutions
Even with straightforward setup, developers encounter recurring issues with ngrok websocket connections. Here are the most frequent problems and how to resolve them.
Connection drops after a period of inactivity. Some network configurations and cloud providers close idle TCP connections after a timeout. If your WebSocket connection goes quiet for a minute or two, the tunnel may drop. The fix is to implement WebSocket ping and pong frames at the application level, sending a heartbeat every 20 to 30 seconds to keep the connection alive. You can also enable TCP keep-alive on the ngrok agent connection through your configuration file.
Invalid Upgrade Header or 400 Bad Request on connection. This typically means the WebSocket client is not sending the correct Upgrade headers, or the local server is not configured to accept WebSocket connections on the expected path. Verify that your client is using the wss:// scheme and that your server's WebSocket endpoint matches the path in the URL. Also check that your server framework has WebSocket support enabled and is listening on the correct route.
Mismatched sub-protocols. WebSocket clients can request specific sub-protocols in the connection headers. If your server does not support the requested sub-protocol, the connection fails. Check your client's sub-protocol declaration and ensure your server either supports it or handles the mismatch gracefully by selecting a fallback protocol or rejecting the connection with a clear error.
Tunnel URL changes on restart. The free tier assigns a random subdomain each time you start a tunnel. If your frontend is hardcoded to a specific URL, it breaks when you restart ngrok. The solution is to use a reserved domain (available on paid plans) or to dynamically read the tunnel URL from the ngrok local API and pass it to your frontend.
HTTPS redirect issues. Some server frameworks automatically redirect HTTP to HTTPS. When ngrok forwards traffic, the redirect can create a loop or break the WebSocket upgrade. Disable automatic HTTPS redirects on your local server when testing through ngrok, or configure your server to trust the forwarded protocol header that ngrok sends.

Alternative Approaches
ngrok is not the only option for exposing local WebSocket servers. Several alternatives exist, each with different trade-offs.
LocalTunnel is an open-source alternative that provides random public URLs for local ports. It supports WebSockets but has less robust infrastructure and no built-in inspection UI. It is free and easy to use but less reliable for sustained development sessions.
Cloudflare Tunnel creates secure tunnels from your machine to Cloudflare's edge network. It supports WebSockets and offers strong security features, but setup is more involved than ngrok and requires a Cloudflare account with a configured domain.
SSH reverse tunneling is a DIY approach using a public server as a relay. You forward a remote port to your local port through SSH. This works for WebSockets but requires you to manage your own server, TLS certificates, and firewall rules. It is free if you already have a public server but demands more operational effort.
For most developers, ngrok strikes the best balance of ease, reliability, and features for WebSocket development. The free tier is sufficient for individual development, and the paid plans scale well for team workflows.
Definitions Glossary
WebSocket: A communication protocol that provides full-duplex, persistent connections over a single TCP connection, initiated via an HTTP upgrade handshake.
ngrok Edge: ngrok's cloud infrastructure that receives public traffic, terminates TLS, and forwards requests through encrypted tunnels to the ngrok agent.
ngrok Agent: A lightweight process running on your local machine that maintains an outbound connection to ngrok's edge and forwards traffic to your local server.
101 Switching Protocols: The HTTP response status code indicating that the server has agreed to upgrade the connection from HTTP to the WebSocket protocol.
TLS Termination: The process of decrypting encrypted traffic at an intermediary point (ngrok's edge) so the remaining connection can proceed to the destination server.
Authtoken: A credential that links the ngrok agent to your ngrok account, determining available features, limits, and tunnel permissions.
Key Takeaways
- ngrok websocket tunneling requires no special configuration because HTTP tunnels handle the WebSocket upgrade handshake automatically.
- The free tier provides random subdomains suitable for individual development, while paid plans offer reserved domains and advanced security features.
- Always use the wss:// scheme to ensure encrypted WebSocket connections through ngrok's TLS-terminating edge.
- Selecting a nearby edge region and enabling TCP keep-alive are the two most effective ways to reduce latency and prevent idle connection drops.
- ngrok's built-in inspection UI is the fastest way to debug WebSocket issues, showing headers, frames, and response codes in real time.
- Developers building real-time apps with VideoSDK can use ngrok to expose local signaling servers for cross-device testing during development.
Conclusion
ngrok websocket tunneling solves a fundamental development problem: getting public traffic to your local WebSocket server without deploying to a remote host. The setup is straightforward, the protocol support is native, and the free tier covers most individual development needs. Focus on security from the start by using wss://, restricting access where possible, and rotating your authtoken. Monitor performance through the ngrok dashboard and choose an edge region close to your machine for the lowest latency. If you are building real-time communication features, explore the VideoSDK code samples for integration patterns that work well with local tunneling. What are you building with WebSockets? Drop a comment below and let me know what kind of real-time use case you are working on.
Code Examples
Below are some practical examples of configuration and code snippets to help you get started with ngrok and websockets.
Configuration File (ngrok.yml)
YAML
1authtoken: <YOUR_AUTH_TOKEN>
2tunnels:
3 websocket:
4 proto: http
5 addr: 3000
6 bind_tls: trueNode.js WebSocket Client
JavaScript
1const WebSocket = require('ws');
2
3const ws = new WebSocket('wss://<YOUR_NGROK_SUBDOMAIN>.ngrok.io');
4
5ws.on('open', function open() {
6 console.log('connected');
7 ws.send(Date.now());
8});
9
10ws.on('close', function close() {
11 console.log('disconnected');
12});
13
14ws.on('message', function incoming(data) {
15 console.log(`Roundtrip time: ${Date.now() - data} ms`);
16 setTimeout(function timeout() {
17 ws.send(Date.now());
18 }, 500);
19});Python WebSocket Client
Python
1import websocket
2import time
3
4def on_message(ws, message):
5 print(f"Received message: {message}")
6
7def on_error(ws, error):
8 print(f"Error: {error}")
9
10def on_close(ws):
11 print("Connection closed")
12
13def on_open(ws):
14 def run(*args):
15 for i in range(3):
16 time.sleep(1)
17 ws.send(f"Hello {i}")
18 time.sleep(1)
19 ws.close()
20 run()
21
22if __name__ == "__main__":
23 websocket.enableTrace(True)
24 ws = websocket.WebSocketApp("wss://<YOUR_NGROK_SUBDOMAIN>.ngrok.io",
25 on_message=on_message,
26 on_error=on_error,
27 on_close=on_close)
28 ws.on_open = on_open
29 ws.run_forever()These examples demonstrate how to set up a websocket client in both Node.js and Python, connecting to a server exposed through ngrok.
Conclusion
Using ngrok with websockets can significantly enhance your development workflow by providing a simple, secure, and effective way to expose your local servers to the internet. This combination is particularly useful for real-time applications requiring persistent and reliable connections. By following the steps outlined in this guide, you can set up and configure ngrok to work seamlessly with your websocket applications, enabling efficient testing and debugging processes. Explore the advanced features of ngrok to further optimize and secure your setups, ensuring a robust development environment.
Free $20 Balance for AI Voice Agents & Video Calls
FAQ
