TLS Termination
ngrok automatically handles TLS (SSL) termination and certificate management for you. There is typically nothing to setup, configure or manage.
Overview
ngrok's TLS termination behavior is determined by an endpoint's protocol and traffic policy. You may customize each endpoint to choose where TLS is terminated, how it is terminated and even whether it is terminated at all. When ngrok's cloud service terminates TLS, it:
- Uses latest and most secure version of TLS
- Uses the TLS Certificate attached to the Domain which matches the Endpoint URL's hostname
- Accelerates your traffic by using the global load balancer to terminate at its closest point of presence
ngrok supports end-to-end encryption where the ngrok cloud service does not terminate TLS connections and only sees enciphered traffic. When configured this way, you are responsible for configuring TLS termination in your upstream service or at the ngrok agent.
Termination Location
TLS connections to your ngrok endpoints are terminated at one of three locations.
- ngrok's cloud service: This is the easiest and most common. All HTTPS endpoints terminate TLS at ngrok's cloud service. When connections are terminated by ngrok's cloud service, they are re-encrypted before they are transmitted over a Secure Tunnel to an agent.
- ngrok agent: This is a form of end-to-end encryption where the ngrok cloud service does not terminate TLS and you instead configure the ngrok agent to terminate TLS connections for you.
- your upstream service: This is another form of end-to-end encryption where neither the cloud service nor an agent terminates TLS connections. Instead, your upstream application service is responsible for TLS termination.
An endpoint's protocol determines the ngrok cloud service's default TLS termination behavior.
Endpoint Protocol | TLS Termination |
---|---|
HTTP | None |
HTTPS | Always at ngrok's cloud service. |
TLS | Default no termination, configurable with terminate-tls |
TCP | Default no termination, configurable with terminate-tls |
Examples
Cloud Service
- 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 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
Terminate at Upstream
- 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-tls
The terminate-tls
Traffic Policy
Action enables you to terminate TLS
connections at ngrok's cloud service for TCP and TLS endpoints.
You may also use this action on HTTPS endpoints to customize how TLS is
terminated. When you use the terminate-tls
action on an HTTPS endpoint, ngrok
will skip the default TLS termination step that it runs for all HTTPS endpoints
so as not to terminate TLS twice.
Acceleration
The ngrok cloud service improves the performance of your endpoints by accelerating TLS termination using ngrok's global points of presence.
TLS connection set up requires multiple network round-trips. When round-trip times (RTTs) are long, TLS connection establishment slows down. ngrok reduces the latency of these round-trip times between the client and your endpoint by terminating connections at the closest point of presence via its global load balancer.
Certificates
When the ngrok cloud service terminates TLS connections, it does so with the TLS Certificate attached to the Domain which matches the Endpoint URL's hostname. See the documentation on TLS Certificates for more details on how they are selected, managed, provisioned and renewed.
You may customize which TLS certificate is chosen for termination with the
terminate-tls
traffic policy action.
Handshake
TLS Version
ngrok uses TLS 1.3 (the latest version) by default. If a client does not support TLS 1.3, ngrok will use the highest possible version that the client supports, down to TLS 1.1.
You may customize the minimum and maximum supported versions of TLS with the
terminate-tls
traffic policy action.
ALPN
https
endpoints negotiate the next protocol via ALPN with the following
default list in order of preference:
['h2', 'http/1.1']
SNI
ngrok endpoints do not support legacy clients which do not set the SNI extension. For example, the following clients (and others) will fail to work with ngrok 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
FIPS Compliance
ngrok does not use a FIPS-compliant TLS implementation by default, but one can be enabled for your endpoints.
Contact us if you require a FIPS-compliant TLS implementation.
End-to-end encryption
You may choose to terminate TLS at your upstream service or at the ngrok agent to achieve end-to-end encryption (E2EE). When your endpoints operate in this mode, the ngrok cloud service can not see the payloads that transfer through your endpoints.
Creating an endpoint with end-to-end encryption is simple:
- Create a TLS or TCP endpoint
- Do not add a
terminate-tls
action to its traffic policy.
That's it! If you'd like to configure the agent to terminate TLS for you, the configuration depends on which kind you are using.
Agent | Documentation |
---|---|
Agent Config File | agent_tls_termination |
Go SDK | WithTLSTerminationKeyPair |
Other SDKs | not supported |
Kubernetes Operator | not supported |