TCP Endpoints
Overview
TCP endpoints enable you to deliver any network service with a TCP-based protocol. It is commonly used 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.
TCP endpoints are only available on a free plan after adding a valid payment method to your account.
Quickstart
Agent Endpoint
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 - e.g.
tcp://1.tcp.ngrok.io:12345
and forwards its traffic to a local port.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok tcp 22
tunnels:
example:
proto: tcp
addr: 22
ssh -R 0:localhost:22 v2@connect.ngrok-agent.com tcp
import (
"context"
"net"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)
func ngrokListener(ctx context.Context) (net.Listener, error) {
return ngrok.Listen(ctx,
config.TCPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
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 Docs
import 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 Docs
TCP Endpoints are not supported via the ngrok Kubernetes Operator
Cloud Endpoint
Cloud endpoints are created via the ngrok Dashboard or API. They are persistent and live until they are deleted. Traffic Policy controls how a cloud endpoint handles traffic.
Create a TCP cloud endpoint which forwards traffic to another internal TCP endpoint.
- Agent CLI
- curl
ngrok api endpoints create \
--url tcp://1.tcp.ngrok.io:12345 \
--traffic-policy "$(<traffic-policy.yml)"
traffic-policy.yml
on_tcp_connect:
- actions:
- type: forward-internal
config:
url: tcp://example.internal:12345
TODO
URLs
Because there is no standard scheme for TCP URLs, ngrok renders them as
tcp://
.
Static TCP Addresses
If you would like your TCP endpoints to be fixed, you must first provision a
TCP Address. TCP Addresses include a
hostname and port component and look like 1.tcp.ngrok.io:12345
. When you
provision a TCP address, a random address will be assigned to you. If you
delete a TCP address, there is no way to provision the same one again. TCP
addresses may be managed via the dashboard and via API.
Listen on the TCP Address 1.tcp.eu.ngrok.io:12345
. You must create this TCP
address ahead of time, see TCP Addresses.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok tcp 3389 --remote-addr 1.tcp.eu.ngrok.io:12345
tunnels:
example:
proto: tcp
addr: 3389
remote_addr: 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"
"golang.ngrok.com/ngrok/config"
)
func ngrokListener(ctx context.Context) (net.Listener, error) {
return ngrok.Listen(ctx,
config.TCPEndpoint(
config.WithRemoteAddr("1.tcp.ngrok.io:12345"),
),
ngrok.WithRegion("eu"),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
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
Bring your own domain
TCP Addresses 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.
Public TCP Endpoints are assigned randomly on ngrok-controlled domains with a randomly-chosen port. You may not choose the hostname or port of your Public TCP Addresses.
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
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok tcp 192.168.1.2:5432
tunnels:
example:
proto: tcp
addr: 192.168.1.2:5432
ssh -R 0:192.168.1.2:5432 v2@connect.ngrok-agent.com tcp
import (
"context"
"net/url"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)
func ngrokForwarder(ctx context.Context) (ngrok.Forwarder, error) {
backendUrl, err := url.Parse("tcp://192.168.1.2:80")
if err != nil {
return nil, err
}
return ngrok.ListenAndForward(ctx,
backendUrl,
config.TCPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
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, becuase 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
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok tcp 22 --upstream-proxy-protocol=2
tunnels:
example:
proto: tcp
addr: 22
proxy_protocol: 2
PROXY proto is not support via SSH.
import (
"context"
"net"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)
func ngrokListener(ctx context.Context) (net.Listener, error) {
return ngrok.Listen(ctx,
config.TCPEndpoint(
config.WithProxyProto(2),
),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
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 Export Events
You can export logs of traffic to TCP endpoints with ngrok's events system. The following events are published for log exporting:
Event | When |
---|---|
tcp_connection_closed.v0 | Published when a TCP connection to a TCP endpoint completes. |
Errors
If an error is encountered while handling connections to a TCP endpoint for any reason (e.g. 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 programatically. 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.