TLS Endpoints
Overview
TLS endpoints enable you to deliver any network service that runs over a TLS-based protocol. TLS endpoints make no assumptions about the wrapped protocol being transported.
TLS endpoints use the Server Name Information (SNI) data on incoming TLS connections to route connections to the appropriate endpoint.
Because the TLS protocol has limited application-level semantics, ngrok can only offer a limited set of modules to handle TLS traffic.
You may choose where to terminate TLS, including at your upstream service or at the ngrok agent to achieve end-to-end encryption (E2EE). We call this Zero Knowledge TLS. When your TLS endpoints operate in this mode, the ngrok edge can not see the payloads that transfer through your endpoints.
If you are delivering an HTTPS application, prefer to create an HTTP Endpoint.
Example Usage
Terminate at Edge
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok tls 80 --terminate-at edge --url your-name.ngrok.app
tunnels:
example:
proto: tls
terminate_at: edge
domain: your-name.ngrok.app
addr: 80
SSH does not support termination at the edge
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.TLSEndpoint(
config.WithDomain("your-name.ngrok.app"),
config.WithTLSTermination(
config.WithTLSTerminationAt(config.TLSAtEdge),
),
),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
const fs = require("fs");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
proto: "tls",
domain: "app.example.com",
crt: fs.readFileSync("/path/to/app-example-com-crt.pem", "utf8"),
key: fs.readFileSync("/path/to/app-example-com-key.pem", "utf8"),
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
-
https://ngrok.github.io/ngrok-javascript/interfaces/Config.html#domain
-
https://ngrok.github.io/ngrok-javascript/interfaces/Config.html#crt
-
https://ngrok.github.io/ngrok-javascript/interfaces/Config.html#key
-
https://ngrok.github.io/ngrok-javascript/classes/TlsListenerBuilder.html#domain
-
https://ngrok.github.io/ngrok-javascript/classes/TlsListenerBuilder.html#termination
import ngrok
def load_file(name):
with open(name, "r") as crt:
return bytearray(crt.read().encode())
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
proto="tls",
domain="app.example.com",
crt=load_file("/path/to/app-example-com-crt.pem"),
key=load_file("/path/to/app-example-com-key.pem"))
print(f"Ingress established at: {listener.url()}");
Python SDK Docs:
The Rust SDK does not support TLS termination at the ngrok edge
TLS endpoints are not supported by the ngrok Kubernetes Operator
Terminate at Upstream
See Zero-Knowledge TLS for additional details.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok tls 443 \
--terminate-at upstream \
--url app.example.com
tunnels:
example:
proto: tls
domain: app.example.com
addr: 443
terminate_at: upstream
ssh -R app.example.com:443:localhost:443 v2@connect.ngrok-agent.com tls
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.TLSEndpoint(
config.WithDomain("app.example.com"),
),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
proto: "tls",
domain: "app.example.com",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
proto="tls",
domain="app.example.com")
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
.tls_endpoint()
.domain("app.example.com")
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
TLS endpoints are not supported by the ngrok Kubernetes Operator
Terminate at Agent
See Zero-Knowledge TLS at the Agent for additional details.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok tls 80 \
--terminate-at agent \
--url app.example.com \
--crt /path/to/app-example-com-crt.pem \
--key /path/to/app-example-com-key.pem
tunnels:
example:
proto: tls
terminate_at: agent
domain: app.example.com
addr: 80
crt: /path/to/app-example-com-crt.pem
key: /path/to/app-example-com-key.pem
SSH does not support termination at the agent
The Go SDK does not support TLS termination at the SDK
The Javascript SDK does not support TLS termination at the SDK.
The Python SDK does not support TLS termination at the SDK.
The Rust SDK does not support TLS termination at the SDK.
TLS endpoints are not supported by the ngrok Kubernetes Operator
Re-encrypt to Upstream
If you terminate at the ngrok edge or ngrok agent, you may want to re-encrypt
the connection from the agent to your upstream service. The ngrok agent
supports this behavior by using the non-standard tls://
scheme syntax.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok tls tls://localhost:443 --terminate-at=edge
tunnels:
example:
proto: tls
addr: tls://localhost:443
terminate_at: edge
Re-encrypting the connection to your upstream service with TLS is not supported via SSH.
Re-encrypting the connection to your upstream service with TLS is not supported in the Go SDK.
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: "tls://localhost:443",
authtoken_from_env: true,
proto: "tls",
crt: "",
key: "",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
An empty certificate and key will default to the ngrok edge's automatically provisioned keypair. The upstream certificate of localhost:443
will be validated by a filepath specified in the SSL_CERT_FILE
environment variable (e.g. SSL_CERT_FILE=/path/to/ca.crt
), or falling back to the host OS installed trusted certificate authorities.
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("tls://localhost:443", authtoken_from_env=True,
proto="tls"
crt=bytearray(),
key=bytearray())
print(f"Ingress established at: {listener.url()}");
An empty certificate and key will default to the ngrok edge's automatically provisioned keypair. The upstream certificate of localhost:443
will be validated by a filepath specified in the SSL_CERT_FILE
environment variable (e.g. SSL_CERT_FILE=/path/to/ca.crt
), or falling back to the host OS installed trusted certificate authorities.
Python SDK Docs:
Re-encrypting the connection to your upstream service with TLS is not yet supported in the Rust SDK.
TLS endpoints are not supported by the ngrok Kubernetes Operator
PROXY Protocol
Add a PROXY protocol header on connection to your upstream service. This sends connection information like the original client IP address to your upstream service.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok tls 443 --proxy-proto=2
tunnels:
example:
proto: tls
addr: 443
proxy_proto: 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.TLSEndpoint(
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: "tls",
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="tls",
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
.tls_endpoint()
.proxy_proto(ProxyProto::V2)
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
TLS Endpoints are not supported via the ngrok Kubernetes Operator
Behavior
TLS endpoints allow you to deliver any application that uses TLS as its encryption transport. They provide you with complete flexibility to define where TLS termination occurs. You may ask ngrok to terminate TLS at the ngrok edge, the agent or at your upstream service. Consult the TLS Termination module documentation for additional detail.
It is very common to encounter certificate errors when working with TLS endpoints because the behavior changes depending on where you terminate TLS. The Certificates documentation contains details about what certificates are used under which circumstances.
TLS endpoints always use 443 as the port on their domain. TLS endpoints use the Server Name Information (SNI) data on incoming TLS connections to route connections to the appropriate endpoint.
Protocols that begin in plain text and upgrade to TLS via a mechanism like STARTTLS in SMTP, IMAP, etc are not supported.
Endpoints
When your TLS endpoint is online, it will be available as an Endpoint
resource. Endpoints have URLs, but there is no
standard scheme for TLS URLs so ngrok renders them as tls://
.
Compatible Clients
All modern TLS clients populate the SNI extension. Some older clients do not. These clients will not work properly with ngrok's TLS endpoints. The following list of clients do not support SNI and will not work with TLS endpoints:
- Microsoft Internet Explorer 6.0
- Microsoft Internet Explorer 7 & 8 on Windows XP or earlier
- Native browser on Android 2.X
- Java <=1.6
- Python 2.X, 3.0, 3.1 if required modules are not installed
A more complete list can be found on the Server Name Indication page on Wikipedia
Reference
Edges
Edges enable you to centrally manage your endpoints' Module configurations in the ngrok dashboard or API instead of defining them via an Agent or Agent SDK.
- A TLS Edge is attached to one or more Domains. For each Domain, it creates a TLS Endpoint that it listens for traffic on.
- When a Domain is associated with a TLS Edge, agents may no longer start endpoints on that Domain. You can always detach a Domain from your Edge if you want to create Endpoints on it from an Agent or Agent SDK.
- Modules on a TLS Edge are attached directly to the edge itself. There are no Routes.
- When you create a TLS Edge via the dashboard, it will automatically create a new Domain with a random name and assign it to your Edge.
- When you create an TLS Edge via the dashboard, it will automatically create a Tunnel Group Backend with a unique label.
Modules
Use modules to modify the behavior of traffic flowing through your endpoints.
Module | Description |
---|---|
Mutual TLS | Perform mutual TLS authentication when terminating TLS connections with a configured set of certificate authorities. |
TLS | Configure whether ngrok terminates TLS traffic at its edge or forwards the TLS traffic through unterminated. |
IP Restrictions | Allow or deny traffic based on the source IP of connections |
Observability
Use ngrok's events system to capture logs of TLS connections to your endpoints.
When TLS connections to your endpoints are closed, tcp_connection_closed.v0 events are published.
Errors
If the TLS handshake fails, a TLS abort code will be sent to the client.
In all other cases, if an error is encountered while handling TLS connections to your endpoints (e.g. no available backends or internal server error), the connection will simply be closed. The TLS protocol and its implementations are not sufficiently flexible enough to deliver additional rich error information when failures are encountered.
You can use the observability primitives to understand the error handling behavior of a connection.
Pricing
Current plans and price points can be found on our website.
TLS endpoints are available on the Pay-as-you-go, Pro, and Enterprise plans.
Zero-knowledge TLS is available on the Enterprise plan.