Documentation Index
Fetch the complete documentation index at: https://ngrok.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
TCP endpoints enable you to deliver any network service with a TCP-based
protocol. They are commonly used to create connectivity for:
- Remote access protocols like SSH, VNC and RDP
- Databases like MySQL, Postgres, MSSQL and SQLite
- IoT protocols like MQTT
- Gaming servers like Minecraft
If you are accepting TLS traffic, you may prefer to create a TLS Endpoint.
Quickstart
Agent Endpoints are the easiest way to get started with ngrok. An agent
endpoint is started by a
Secure Tunnels agent. The endpoint lives for the lifetime
of the process and forwards traffic to a port or URL of your choosing.
This example creates a TCP endpoint on a randomly assigned URL - for example,
tcp://1.tcp.ngrok.io:12345 and forwards its traffic to a local port.
Agent CLI
Agent Config
SSH -R
Go
Javascript
Python
Rust
Kubernetes Controller
ssh -R 0:localhost:22 v2@connect.ngrok-agent.com tcp
import (
"context"
"net"
"golang.ngrok.com/ngrok/v2"
)
func ngrokListener(ctx context.Context) (net.Listener, error) {
return ngrok.Listen(ctx,
ngrok.WithURL("tcp://"),
)
}
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
proto: "tcp",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docsimport ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
proto="tcp")
print(f"Ingress established at: {listener.url()}");
Python SDK Docs:use ngrok::prelude::*;
async fn listen_ngrok() -> anyhow::Result<impl Tunnel> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
let tun = sess
.tcp_endpoint()
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate DocsTCP Endpoints are not supported via the ngrok Kubernetes Operator
URLs
URLs are validated differently depending on their
binding. Consult the
following documentation for details on valid URLs for TCP endpoints:
There is no standard scheme for TCP URLs so ngrok renders them as tcp://.
Static URLs
If you would like a public TCP endpoint to have a static URL, you must first
create a TCP Address. When you create a TCP
address, a random hostname and port will be assigned to you, for example,
1.tcp.ngrok.io:12345.
A TCP address is only needed to make a public TCP endpoint have a static URL.
They are not needed for TCP endpoints on other bindings, like internal or
kubernetes.
After you have created a TCP Address, specify the address (for example,
1.tcp.eu.ngrok.io:12345) in the URL when you create the endpoint.
Agent CLI
Agent Config
SSH Reverse Tunnel
Go
Javascript
Python
Rust
Kubernetes Controller
ngrok tcp 3389 --url tcp://1.tcp.eu.ngrok.io:12345
ssh -R 1.tcp.eu.ngrok.io:12345:localhost:3389 connect.eu.ngrok-agent.com tcp
import (
"context"
"net"
"golang.ngrok.com/ngrok/v2"
)
func ngrokListener(ctx context.Context) (net.Listener, error) {
return ngrok.Listen(ctx,
ngrok.WithURL("tcp://1.tcp.ngrok.io:12345"),
)
}
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
proto: "tcp",
remote_addr: "1.tcp.eu.ngrok.io:12345",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
proto="tcp",
remote_addr="1.tcp.eu.ngrok.io:12345")
print(f"Ingress established at: {listener.url()}");
Python SDK Docs:use ngrok::prelude::*;
async fn listen_ngrok() -> anyhow::Result<impl Tunnel> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
let tun = sess
.tcp_endpoint()
.remote_addr("1.tcp.eu.ngrok.io:12345")
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:TCP Endpoints are not supported via the ngrok Kubernetes Operator
Custom domains
Public TCP endpoints are assigned randomly on an ngrok-controlled hostname with
a randomly assigned port. You may not choose the hostname and you may not
select the port.
You may, however, simulate a customized hostname by creating a CNAME record to
the hostname of your assigned TCP address. If you do so, be aware that all
ports on that hostname, even those provisioned to other accounts will then be
available on your domain.
For example if your TCP address is 5.tcp.ngrok.io:12345, you could create the
following CNAME record:
CNAME tcp.mydomain.com -> 5.tcp.ngrok.io
And then you can access that TCP endpoint with
telnet tcp.mydomain.com 12345
Traffic Policy
Attach Traffic Policy to endpoints to route, authenticate
and transform the traffic through the endpoint.
Authentication
When you create public TCP endpoints, you often want to secure them with
authentication. You can secure your TCP endpoints with the following Traffic
Policy actions. There is a limited set of actions available
to authenticate TCP traffic because the TCP protocol is low-level.
Agent forwarding
The ngrok agent and Agent
SDKs forward traffic that your endpoints receive
to upstream services. You specify a URL or port number to instruct the ngrok
agent where and how to forward traffic.
Forward to non-local service
Agents don’t just forward to ports on your localhost. You can forward traffic
to any address or URL reachable from the agent. For example, if you want to
forward traffic to a Postgres server running on your network at
192.168.1.2:5432:
Agent CLI
Agent Config
SSH Reverse Tunnel
Go
Javascript
Python
Rust
Kubernetes Controller
ngrok tcp 192.168.1.2:5432
ssh -R 0:192.168.1.2:5432 v2@connect.ngrok-agent.com tcp
import (
"context"
"golang.ngrok.com/ngrok/v2"
)
func ngrokForwarder(ctx context.Context) (ngrok.EndpointForwarder, error) {
return ngrok.Forward(ctx,
ngrok.WithUpstream("tcp://192.168.1.2:3306"),
ngrok.WithURL("tcp://"),
)
}
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: "192.168.1.2:5432",
authtoken_from_env: true,
proto: "tcp",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:import ngrok
listener = ngrok.forward("192.168.1.2:5432", authtoken_from_env=True,
proto="tcp")
print(f"Ingress established at: {listener.url()}");
Python SDK Docs:use ngrok::prelude::*;
use ngrok::tunnel;
use ngrok::forwarder::Forwarder;
use url::Url;
async fn forward_ngrok() -> Result<Forwarder<tunnel::TcpTunnel>, Error> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
sess
.tcp_endpoint()
.listen_and_forward(Url::parse("tcp://127.0.0.1:8090")?)
.await
.map_err(Into::into)
}
Rust Crate Docs:TCP Endpoints are not supported via the ngrok Kubernetes Operator
PROXY Protocol
When you forward traffic to an upstream TCP service, because traffic is coming
from the ngrok agent, it won’t know the client’s original IP address. You can
add the PROXY
protocol header
on connections to your upstream service to send connection information like the
original client IP address to your upstream service. You will need to configure
your upstream service to handle the PROXY protocol header.
Agent CLI
Agent Config
SSH Reverse Tunnel
Go
Javascript
Python
Rust
Kubernetes Controller
ngrok tcp 22 --upstream-proxy-protocol=2
version: 3
endpoints:
- name: example
url: tcp://1.tcp.ngrok.io:12345
upstream:
url: 22
proxy_protocol: 2
PROXY proto is not support via SSH.
import (
"context"
"net"
"golang.ngrok.com/ngrok/v2"
)
func ngrokListener(ctx context.Context) (net.Listener, error) {
return ngrok.Forward(ctx,
ngrok.WithUpstream("tcp://localhost:8080",
ngrok.WithUpstreamProxyProto(ngrok.ProxyProtoV2),
),
ngrok.WithURL("tcp://"),
)
}
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
proto: "tcp",
proxy_proto: "2",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
proto="tcp",
proxy_proto="2")
print(f"Ingress established at: {listener.url()}");
Python SDK Docs:use ngrok::prelude::*;
async fn listen_ngrok() -> anyhow::Result<impl Tunnel> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
let tun = sess
.tcp_endpoint()
.proxy_proto(ProxyProto::V2)
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:TCP Endpoints are not supported via the ngrok Kubernetes Operator
Observability
Traffic Inspector
Traffic Inspector does not support TCP endpoints.
Log exports
You can export logs of traffic to TCP endpoints with ngrok’s events
system. The following events are published for log exporting:
| Log | When |
|---|
| tcp_connection_closed.v0 | Published when a TCP connection to a TCP endpoint completes. |
Limits & timeouts
Contact Support if you need to configure limits and timeouts on
connections to TCP endpoints.
| Limit | Name | Notes |
|---|
| 5 minutes | Client Idle Timeout | Time since data was last transmitted by the upstream service |
| 5 minutes | Server Idle Timeout | Time since data was last transmitted by the upstream service |
| No limit | Data transmitted | Data transmitted by the client or upstream service |
Errors
If an error is encountered while handling connections to a TCP endpoint for any
reason (for example, Traffic Policy action error, internal server error), the
connection will be closed. Because of the low-level nature of the TCP protocol,
there is no mechanism used to transmit information about what error code was
encountered.
Use the observability features to understand connection
handling errors.
API
TCP Endpoints can be created programmatically. Consult the documentation on
Endpoint APIs.
Pricing
TCP endpoints are available on all plans. Consult the Endpoints
Pricing documentation for
billing details.
TCP endpoints are only available on a free plan after adding a valid payment
method to your account.
See TCP Addresses pricing for
details on pricing for fixed TCP Addresses.