Password-Protect a Local TCP Service with Ngrok Authtunnel
Use Ngrok Authtunnel to require HTTP Basic Auth at the edge before forwarding TCP traffic to a local service, keeping unauthenticated clients off your local port.
03 Sept 2025, 06:55 UTC

The problem: an open TCP tunnel is an open door
Ngrok exposes a local port to the internet through a public endpoint. The ngrok process authenticates itself to the ngrok control plane using your authtoken, but that authentication does not extend to clients connecting to your forwarded port. If you tunnel a database, Redis instance, or internal API, anyone who discovers the public address can connect. The useful fix is to enable Authtunnel, an ngrok feature that requires HTTP Basic Auth at the ngrok edge before raw TCP traffic is forwarded to your local service.
How Authtunnel works
Authtunnel applies to TCP tunnels. When a client connects to the public ngrok address, the ngrok edge terminates the TLS connection and checks for valid basic-auth credentials. If the credentials are missing or incorrect, the edge closes the connection. If they match, the edge forwards the TCP stream through the tunnel to the local address and port you configured. Your local service still receives unauthenticated TCP connections from inside the tunnel, so it does not need to implement its own login page, but unauthorized clients are rejected before they reach your machine.
Worked configuration
Run the commands on the host where the local service is running. No elevated permissions are required, but the ngrok process must be able to bind to the local port and reach the ngrok control plane over the network.
# Example ngrok config.yml. Syntax varies by release; verify against your installed version.
version: "2"
authtoken: YOUR_NGROK_AUTHTOKEN
tunnels:
protected_tcp:
proto: tcp
addr: LOCAL_PORT
authtunnel:
username: USERNAME
password: PASSWORD
Replace the placeholders:
YOUR_NGROK_AUTHTOKENis your ngrok authtoken from the dashboard.LOCAL_PORTis the port your local service listens on, for example 5432 for PostgreSQL or 6379 for Redis.USERNAMEandPASSWORDare the credentials clients must present to the ngrok edge.
Start the tunnel:
ngrok start --config=ngrok.yml protected_tcp
Expected checks:
- The console prints a public forwarding address, for example
tcp://0.tcp.ngrok.io:12345. - The ngrok web UI at
http://127.0.0.1:4040shows the tunnel as online.
Risks: this exposes your local port to the internet. Credentials travel from the client to the ngrok edge over TLS, but the tunnel leg from the edge to localhost is plain TCP. Treat the tunnel as temporary unless you reserve a hostname on a paid plan.
Verification
- Open
http://127.0.0.1:4040and confirm the tunnel status is online. - Attempt a TCP connection without credentials, for example
nc PUBLIC_HOST PUBLIC_PORT. The edge should refuse or close the connection. - Attempt a connection with credentials. The method depends on your TCP client; some clients support passing
USERNAME:PASSWORDin the initial header, while others do not support basic auth at all. - Check your local service logs. Connections should appear only after the edge accepts the credentials.
If both authorized and unauthorized clients connect, Authtunnel is not active, the config was not loaded, or the syntax is invalid for your ngrok release.
Limits and common mistakes
Authentication is at the edge only
Authtunnel protects the public edge, not the local service. Traffic that passes the edge is forwarded as plain TCP inside the tunnel. If the tunnel or local network is untrusted, the local service still sees unauthenticated connections.
Ephemeral endpoints
Free tier URLs change when you restart ngrok and may be rate-limited or terminated after inactivity. For a stable address, reserve a hostname on a paid plan.
Not a replacement for service-level security
Do not expose production databases or sensitive internal services to the internet solely behind Authtunnel. Basic auth uses a single shared credential with no rotation, per-user access control, or detailed audit log.
Client compatibility
Many TCP clients cannot send basic-auth headers. Test your specific client before depending on the tunnel for access control.
Rollback
Stopping the tunnel removes the public endpoint. Press Ctrl+C in the ngrok terminal or kill the ngrok process. Remove the tunnel block from ngrok.yml if you want to prevent accidental restarts.
Practical check
After starting ngrok, watch the web UI for connection attempts. Confirm that unauthorized attempts are rejected and that only authorized clients reach the local service. If the local service receives connections from clients that did not present credentials, the edge rule is not working as intended.