HTTP Endpoints
Overview
ngrok's HTTP endpoints enable you to serve APIs, web services, websocket servers, websites and more.
Serving a web application is as simple as ngrok http 80
. You can also layer
on additional capabilities like auth, observability, load balancing and more.
Example Usage
Basic usage
Create an HTTPS endpoint on a randomly assigned ngrok domain.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http 8080
tunnels:
example:
proto: http
addr: 8080
ssh -R 443:localhost:80 v2@connect.ngrok-agent.com http
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.HTTPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True)
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
.http_endpoint()
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: example.ngrok.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Static domain
Create an HTTPS endpoint on example.ngrok.app
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http 80 --url example.ngrok.app
tunnels:
example:
proto: http
addr: 8080
domain: example.ngrok.app
ssh -R example.ngrok.app:443:localhost:80 v2@connect.ngrok-agent.com http
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.HTTPEndpoint(
config.WithDomain("example.ngrok.app"),
),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
domain: "example.ngrok.app",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
domain="example.ngrok.app")
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
.http_endpoint()
.domain("example.ngrok.app")
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: example.ngrok.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Bring your own domain
Create an HTTPS endpoint on app.example.com
.
You will need to create a CNAME DNS record to bring your own domain. Create a Domain record on your ngrok dashboard and follow the instructions.
Consult the documentation about setting up branded domains for additional details.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http 80 --url app.example.com
tunnels:
example:
proto: http
addr: 8080
domain: app.example.com
ssh -R app.example.com:443:localhost:80 v2@connect.ngrok-agent.com http
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.HTTPEndpoint(
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,
domain: "example.ngrok.app",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
domain="example.ngrok.app")
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
.http_endpoint()
.domain("example.ngrok.app")
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Basic auth
Adds a username and password with the Basic Auth Module.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http 80 --basic-auth "username1:password1" --basic-auth "username2:password2"
tunnels:
example:
proto: http
addr: 80
basic_auth:
- username1:password1
- username2:password2
ssh -R 443:localhost:80 v2@connect.ngrok-agent.com http \
--basic-auth "username1:password1" \
--basic-auth "username2:password2"
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.HTTPEndpoint(
config.WithBasicAuth("username1", "password1"),
config.WithBasicAuth("username2", "password2"),
),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
basic_auth: ["username1:password1", "username2:password2"],
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
basic_auth=["username1:password1", "username2:password2"])
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
.http_endpoint()
.basic_auth("username1", "password1")
.basic_auth("username2", "password2")
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
This module is not supported by the Kubernetes Ingress Controller.
Auth with Google
Enforce a browser-based OAuth flow in front of your HTTP endpoints to an identity provider like Google with the OAuth Module.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http 80 --oauth google
tunnels:
example:
proto: http
addr: 80
oauth:
provider: "google"
ssh -R 443:localhost:80 v2@connect.ngrok-agent.com http --oauth=google
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.HTTPEndpoint(
config.WithOAuth("google"),
),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
oauth_provider: "google",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
oauth_provider="google")
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
.http_endpoint()
.oauth(OauthOptions::new("google"))
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
---
kind: NgrokModuleSet
apiVersion: ingress.k8s.ngrok.com/v1alpha1
metadata:
name: ngrok-module-set
modules:
oauth:
google:
optionsPassthrough: false
inactivityTimeout: 4h
maximumDuration: 24h
authCheckInterval: 1h
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: your-domain.ngrok.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Forward to HTTPS
Use a URL with an https:// scheme to make ngrok speak HTTPS to your upstream service.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http https://localhost:8443
tunnels:
example:
proto: http
addr: https://localhost:8443
Forwarding to an upstream HTTPS service is not supported via SSH.
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("https://localhost:8443")
if err != nil {
return nil, err
}
return ngrok.ListenAndForward(ctx,
backendUrl,
config.HTTPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
}
For HTTP/2 Use: config.HTTPEndpoint(config.WithAppProtocol("http2"))
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: "https://localhost:8443",
authtoken_from_env: true,
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("https://localhost:8443", authtoken_from_env=True)
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::HttpTunnel>, Error> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
sess
.http_endpoint()
.listen_and_forward(Url::parse("https://localhost:8443")?)
.await
.map_err(Into::into)
}
Rust Crate Docs:
Add the k8s.ngrok.com/app-protocols
label to the Service definition
targeted by your ingress backend to instruct the Ingress Controller to use
https
when forwarding connections.
apiVersion: v1
kind: Service
metadata:
name: example-service
annotations:
k8s.ngrok.com/app-protocols: '{"example-https-port":"HTTPS"}'
spec:
ports:
- name: example-https-port
port: 443
protocol: TCP
targetPort: 8443
selector:
app-name: some-example-app-label
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 443
Rewrite Host header
Rewrite the Host
header to the value localhost
using the Request Headers
module. Adding the Host
header is a special
case that replaces the existing Host
header instead of appending a second value.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http 8080 --request-header-add='host: localhost'
ngrok http 9090 --request-header-add='host: example.com'
tunnels:
example:
proto: http
addr: 8080
request_header:
add: ["host: localhost"]
ssh -R 443:localhost:80 v2@connect.ngrok-agent.com http \
--request-header-add='host: localhost'
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.HTTPEndpoint(
config.WithRequestHeader("host", "localhost"),
),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
request_header_add: "host:localhost",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
request_header_add="host:localhost")
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
.http_endpoint()
.request_header("host", "localhost")
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
kind: NgrokModuleSet
apiVersion: ingress.k8s.ngrok.com/v1alpha1
metadata:
name: ngrok-module-set
modules:
headers:
request:
add:
host: "localhost"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: your-domain.ngrok.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Forward to non-local
Forward traffic to a HTTP server running on your network at 192.168.1.2:80
.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http 192.168.1.2:80
tunnels:
example:
proto: http
addr: 192.168.1.2:80
ssh -R 0:192.168.1.2:80 v2@connect.ngrok-agent.com http
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("http://192.168.1.2:80")
if err != nil {
return nil, err
}
return ngrok.ListenAndForward(ctx,
backendUrl,
config.HTTPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: "192.168.1.2:80",
authtoken_from_env: true,
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("192.168.1.2:80", authtoken_from_env=True)
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::HttpTunnel>, Error> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
sess
.http_endpoint()
.listen_and_forward(Url::parse("http://192.168.1.2:80")?)
.await
.map_err(Into::into)
}
Rust Crate Docs:
The Kubernetes Ingress controller always forwards its traffic. All of our other
examples show the most common forwarding case: a Service
object that defines
a label selector of matching pods to forward traffic to.
But you can also forward to an explicit set of IP
addresses
on the same network using Service
and EndpointSlice
objects.
apiVersion: v1
kind: Service
metadata:
name: example-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: example-service-1
labels:
kubernetes.io/service-name: example-service
addressType: IPv4
ports:
- name: "http"
appProtocol: http
protocol: TCP
port: 80
endpoints:
- addresses:
- "192.168.1.2"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Wildcard domain
Create an endpoint on the wildcard domain, *.example.com
. It will receive
traffic for foo.example.com
and bar.example.com
. Read more about using
wildcard domains.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http 80 --url *.example.com
tunnels:
example:
proto: http
addr: 80
domain: *.example.com
ssh -R '*.example.com:443:localhost:80' v2@connect.ngrok-agent.com http
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.HTTPEndpoint(
config.WithDomain("*.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,
domain: "*.example.com",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
domain="*.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
.http_endpoint()
.domain("*.example.com")
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: *.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Serve directory files
Serve the files in a directory on an ngrok endpoint. It works
just like python3 -m http.server
but built directly into the ngrok agent.
Serve files in /var/log
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http file://`pwd`
tunnels:
example:
proto: http
addr: "file:///var/log"
Serving directory files is not supported via SSH.
import (
"context"
"net"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)
func serveFiles(ctx context.Context) error {
l, _ := ngrok.Listen(ctx,
config.HTTPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
http.Serve(l, http.FileServer(http.Dir("/var/log")))
}
Serving directory files is not supported in the Javascript SDK.
Serving directory files is not supported in the Python SDK.
Serving directory files is not supported in the Rust SDK.
Serving directory files is not supported in the Kubernetes Ingress Controller.
Serve files on Windows
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http "file://C:\Users\alan\Directory Name"
tunnels:
example:
proto: http
addr: "C:\Users\alan\Directory Name"
Serving directory files is not supported via SSH.
import (
"context"
"net"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)
func serveFiles(ctx context.Context) error {
l, _ := ngrok.Listen(ctx,
config.HTTPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
http.Serve(l, http.FileServer(http.Dir("C:\Users\alan\Directory Name")))
}
Serving directory files is not supported in the Javascript SDK.
Serving directory files is not supported in the Python SDK.
Serving directory files is not supported in the Rust SDK.
Serving directory files is not supported in the Kubernetes Ingress Controller.
Serve files in your current working directory
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http "file:///var/log"
Serving the current working directory is not supported via the agent configuration file.
Serving directory files is not supported via SSH.
import (
"context"
"net"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)
func serveFiles(ctx context.Context) error {
l, _ := ngrok.Listen(ctx,
config.HTTPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
http.Serve(l, http.FileServer(http.Dir(".")))
}
Serving directory files is not supported in the Javascript SDK.
Serving directory files is not supported in the Python SDK.
Serving directory files is not supported in the Rust SDK.
Serving directory files is not supported in the Kubernetes Ingress Controller.
Serve HTTP and HTTPS
By default, ngrok creates an HTTPS endpoint but not an HTTP one. You can configure this behavior to create an HTTP endpoint as well.
- Agent CLI
- Agent Config
- SSH
- Go
- Javascript
- Python
- Rust
- Kubernetes Controller
ngrok http 80 --scheme http,https
tunnels:
example:
proto: http
addr: 80
schemes: ["http", "https"]
When using ngrok via SSH, you can start an endpoint with either the http
or
https
scheme, but not both.
ssh -R 80:localhost:80 v2@connect.ngrok-agent.com http --schemes http
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.HTTPEndpoint(
config.WithSchemes("http", "https"),
),
ngrok.WithAuthtokenFromEnv(),
)
}
Go Package Docs:
const ngrok = require("@ngrok/ngrok");
(async function () {
const listener = await ngrok.forward({
addr: 8080,
authtoken_from_env: true,
schemes: "http",
});
console.log(`Ingress established at: ${listener.url()}`);
})();
Javascript SDK Docs:
import ngrok
listener = ngrok.forward("localhost:8080", authtoken_from_env=True,
schemes="http")
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
.http_endpoint()
.scheme("http")
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Rust Crate Docs:
Creating HTTP endpoints is not supported in The Kubernetes Ingress Controller.
Behavior
ngrok is a compliant HTTP reverse proxy.
Upstream Headers
ngrok adds headers to each HTTP request with information about the client IP and original protocol. These headers can be removed with the Request Headers module.
Header | Description |
---|---|
X-Forwarded-For | The IP address of the client who initiated the request to your endpoint. |
X-Forwarded-Host | The header from the client's request if it existed, otherwise is set to the request's Host . |
X-Forwarded-Proto | Either http or https , indicating the protocol the request used to access your endpoint. |
Since ngrok is proxying requests, the X-Forwarded-For
and X-Forwarded-Proto
headers
will be appended to if they already exist in the client's request. To utilize the
values that ngrok is adding, make sure the last value for the header is being used,
using whatever mechanism your server framework provides.
Auth
Anyone can access your ngrok endpoints unless you secure them with authentication. ngrok supports many different forms of authentication. The easiest to get started with are Basic Auth and OAuth. Basic Auth lets you set a username and password for your endpoint. With OAuth, you can restrict access to a specific email address with a Google, Microsoft or GitHub account.
Examples
There are many other forms of auth for more advanced use cases as well:
Domains
The Domains documentation contains details about how ngrok chooses domains, what managed based domains ngrok operates, how to set up branded domains, how wildcard domains work and more.
Static Domains
ngrok will randomly assign a domain when you create HTTP endpoints unless you specify one. This is okay for one-off uses, but usually you'll want to use a static domain that doesn't change.
You can ask ngrok to always use the same name with the --url
option in the
agent or an equivalent option with other connectivity choices.
Example: Static Domains
Bring your own Domain
If you want to bring your own domain, you can do that as well, but you'll need to create a Domain record and set up a DNS CNAME record. Once you've set one up, you can use the following example.
Example: Bring your own Domain
Wildcard Domains
You can ask ngrok to create an endpoint which will receive traffic for all of
the subdomains matching a given wildcard domain like *.example.com
. Read the
wildcard domains documentation to understand the matching
rules.
Example: Wildcard Domain
Forwarding
The ngrok agent forwards traffic that your endpoints receive to your upstream services. You specify a URL or port number to instruct the ngrok agent how and where to forward traffic.
Upstream HTTPS servers
By default, ngrok assumes that the upstream service it is forwarding to is
listening for unencrypted HTTP traffic. You can specify a URL with an
https://
scheme to make ngrok speak HTTPS to your upstream service.
As a special case, ngrok assumes that if you forward to port 443 on any host
that it should send HTTPS traffic and will act as if you specified an
https://
URL.
ngrok assumes that the network you run the agent on is private and it does not verify the TLS certificate presented by the upstream service.
Example: Forward to HTTPS
Rewriting the Host header
Some application servers expect the Host
header to match a specific value
when they receive requests and others use the Host
header to determine which
of many sites to display. ngrok can rewrite the Host
header of incoming
requests so that your upstream service behaves correctly.
When you rewrite the Host header, ngrok also rewrites the Location
header of
HTTP responses automatically to match the hostname of your Endpoint URL.
Example: Rewrite Host header
The ngrok agent has a shortcut which rewrites the Host
header to match the
hostname portion of the forwarding address. The following command will rewrite
the host header to foo.local
.
ngrok http foo.local:80 --host-header=rewrite
It is equivalent to:
ngrok http foo.local:80 --request-header-add='foo.local'
File Serving
The ngrok agent supports the file://
scheme in a forwarding URL. When you
used the file://
scheme, the ngrok agent serves local file system directories
by using its own built-in file server, no separate server needed.
All paths must be specified as absolute paths, the file://
URL scheme does
not understand relative paths.
Example: Serving directory files
Certificates
ngrok automatically manages all of your TLS certificates. There is nothing to setup, configure or manage.
Regardless of whether your domain is a subdomain of ngrok's managed base
domains (like ngrok.app
) or you brought your own domain, ngrok will
automatically provision and renew TLS certificates for you. You can optionally
bring your own certificates if you'd like though.
Read the TLS Certificates documentation for additional details of how ngrok automatically provisions certificates for your domains as well as how you can bring your own certificates.
Routes
When you use Edges to manage your endpoints, you can apply different
modules on a per-path basis. For example, you could apply auth to /dashboard
and compression to /static
.
We call this primitive a Route. Each Route is defined using a path selector, which will match a path on the request to that endpoint. This can be useful for adding OAuth to specific areas of your website, or stitching multiple services together into a single website. Routes can share the same backend, or you can use a different backend for each route.
HTTP vs HTTPS
By default, ngrok only creates HTTPS endpoints for your services. You can configure ngrok to create both HTTP and HTTPS endpoints or even just HTTP only. If you are using Edges, only HTTPS endpoints are supported.
Example: Serve HTTP and HTTPS
Websockets
Websocket connections are supported. No changes or configuration is required.
Hop by hop Headers
ngrok does not forward any hop-by-hop headers to the upstream service.
As an exception to this rule, Connection: upgrade
requests are forwarded to
support websockets.
For information on headers added automatically by ngrok, see Upstream Headers.
HTTP/1.1 Keep-Alive
When a request is transmitted over HTTP/1.1, the ngrok edge may choose to use keep-alive connections to improve the performance of future requests. This behavior is not configurable.
HTTP/2
Client to ngrok edge
ngrok's HTTP endpoints will automatically use HTTP/2 for all connections if the client supports it. HTTP/2 is used even if your upstream service does not support HTTP/2.
ngrok edge to upstream service
Requests to upstream services can be configured to continue using HTTP/2 with either the agent CLI flags or the agent SDKs.
All requests to your upstream service will be transmitted over HTTP/2 Cleartext since TLS was already terminated at the ngrok edge. We cannot use TLS-ALPN at this time. We rely on HTTP/2 with Prior Knowledge currently.
HTTP/3
HTTP/3 is not yet supported.
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.
- An HTTPS Edge is attached to one or more Domains. For each Domain, it creates an HTTPS Endpoint that it listens for traffic on.
- When a Domain is associated with an HTTPS 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.
- An HTTPS Edge has one or more Routes. Routes have selectors which enable you
to process traffic for paths like
/app
or/static
differently. - Each Route can apply different Modules. Routes can also even send traffic to different Backends.
- HTTPS Edges do not create a corresponding HTTP endpoint. Instead, all HTTP traffic to domains associated with your HTTPS edges is automatically redirected to HTTPS.
- When you create an HTTPS Edge via the dashboard, it will automatically create a new Domain with a random name and assign it to your Edge. If you are on the free plan and have created your free domain, it will adopt that domain.
- When you create an HTTPS Edge via the dashboard, it will automatically create a Failover Backend with two entries. First, a tunnel group backend with a unique label and second an HTTP Response backend which renders an error if there are no tunnels online in the tunnel group.
Modules
Use modules to modify the behavior of traffic flowing through your endpoints.
Module | Description |
---|---|
Basic Auth | Require a username and password with HTTP Basic Auth. |
Circuit Breaker | Protect upstream services by rejecting traffic when they become overwhelmed. |
Compression | Accelerate upstream services by compressing HTTP response bodies with gzip or deflate. |
IP Restrictions | Allow or deny traffic based on the source IP of connections. |
Mutual TLS | Enforce mutual TLS auth with a configured set of CAs. |
OAuth | Enforce an OAuth flow to well-known IdPs like Google, optionally authorizing users by domain or email address. |
OpenID Connect | Enforce an OpenID Connect flow to a federated IdP. |
Request Headers | Add or remove headers from HTTP requests before they are sent to your upstream service. |
Response Headers | Add or remove headers from HTTP responses before they are returned to the client. |
SAML | Enforce a SAML flow to a federated IdP, optionally authorizing users by group. |
TLS Termination | Customize TLS termination behavior, like the minimum supported version of TLS. |
Traffic Policy | Influence and control traffic to and from your upstream service by configuring a powerful policy engine. |
User Agent Filter | Block bots or browsers with rules that allow or deny HTTP requests based on User-Agent header. |
Webhook Verification | Restrict access by verifying HTTP requests are signed by a webhook provider like Slack or GitHub. |
Websocket TCP Converter | Convert binary websocket connections to backend TCP connections. |
Observability
ngrok's events system can capture logs of HTTP requests to your endpoints. ngrok publishes both Layer 4 (connection-level) and Layer 7 (request-level) events for HTTP traffic.
When HTTP requests to your endpoints are completed, http_request_complete.v0 events are published.
When TCP connections to your HTTP endpoints are completed, tcp_connection_closed.v0 events are published.
Errors
If ngrok fails to handle an HTTP request it will set the ngrok-error-code
header in the HTTP response with a unique ngrok Error Code
describing the failure.
ngrok guarantees that the upstream service may never set the ngrok-error-code
HTTP response header so you know reliably that it was set by ngrok.
ngrok may return an error under the following conditions:
- A configured module rejected the request
- Your upstream service timed out or rejected the connection
- Your upstream service returned a response that was not valid HTTP
- ngrok encountered an internal error
Pricing
HTTP endpoints are available on all plans.
Branded domains are available on the Pro and Enterprise plans.