
Introducing ngrok-go: Ingress to Your Go Apps as a net.Listener
Today, we're excited to announce ngrok-go, our idiomatic open-source Go package for embedding secure ingress directly into your Go applications. If you’ve used ngrok before, you can think of ngrok-go as the ngrok agent packaged as a Go library.
ngrok-go lets developers serve Go apps on the internet in a single line of code without setting up low-level network primitives like IPs, certificates, load balancers and even ports! Applications using ngrok-go listen on ngrok’s global ingress network but they receive the same interface any Go app would expect (net.Listener
) as if it listened on a local port by calling net.Listen()
. This makes it effortless to integrate ngrok-go into any application that uses Go's net
or net/http
packages.
- Quickstart guide: A step-by-step guide on how to use ngrok-go
- Go package documentation: The package documentation including functions, variables and examples
- Repo on GitHub: ngrok-go is open source on GitHub. Star the repo to follow along!
Check out how easy it is to run the classic Go hello world web app with ngrok-go:
package main
import (
"context"
"fmt"
"log"
"net/http"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)
func main() {
ctx := context.Background()
l, err := ngrok.Listen(ctx,
config.HTTPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
if err != nil {
log.Fatal(err)
}
fmt.Println("ngrok ingress url: ", l.Addr())
http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello from your ngrok-delivered Go app!")
}))
}
Add your ngrok authtoken to your environment as NGROK_AUTHTOKEN
and run the above code. Your app is on the internet and ready to receive requests with a simple ngrok.Listen()
!
It is that simple. There is no additional configuration or code required. In this example, we didn’t request a specific domain, so your app is assigned a URL (e.g. https://myapp.ngrok.io) which is available as l.Addr()
.
The example app above doesn’t listen on any ports, how is that possible? When you call ngrok.Listen()
, ngrok-go initiates a secure and persistent outbound TLS connection to ngrok’s ingress-as-a-service platform and transmits your configuration requirements — i.e. URL, authentication, webhook verification, and IP restrictions. The ngrok service sets up your configuration across all of our global points of presence in seconds and returns a URL for your application.

After your ingress is set up, ngrok receives HTTP requests at the closest region to the requester and enforces the middleware policies defined by your application. Unauthorized requests are blocked at the edge and only valid requests reach your ngrok-go app via the persistent TLS connection.

Creating ingress today is a frustrating exercise of wrangling a slew of disparate low level networking primitives. Developers must manage a number of technologies at different layers of the network stack like DNS, TLS Certificates, network-level CIDR policies, IP and subnet routing, load balancing, VPNs and NATs, just to name a few. In short, developers are being forced to work with the assembly language of networking.
We built ngrok-go to empower application developers to declare ingress policies at a high layer of abstraction without sacrificing security and control. As an example, here’s how ngrok-go allows developers to specify ingress with declarative options by removing the burden of working with low-level details:
l, err := ngrok.Listen(ctx, config.HTTPEndpoint(
config.WithDomain("app.my-domain.com"),
config.WithAllowCIDRString("200.2.0.0/16"),
config.WithCircuitBreaker(0.8),
config.WithCompression(),
config.WithOAuth("google", config.WithAllowOAuthDomain("example.com")),
),
ngrok.WithAuthtokenFromEnv(),
)
A complete list of supported middleware configurations can be found in the ngrok-go API reference.
Traditionally, ingress is tightly coupled to the environment where your app is deployed. For example, the same app deployed to your own datacenter, an EC2 instance, or a Kubernetes cluster requires wildly different networking setups. Running your app in those three different environments means you need to manage ingress in three different ways.
ngrok-go decouples your app’s ingress from the environment where it runs.
When your application uses ngrok-go, you can run it anywhere and it will receive traffic the same way. From an ingress standpoint, your application becomes portable: it does not matter whether it runs on bare metal, VMs, AWS, Azure, in Kubernetes, serverless platforms like Heroku or Render, a racked data-center server, a Raspberry Pi, or on your laptop.
Developers often distribute the ngrok agent alongside their own applications to create ingress for their IoT devices, SaaS offerings, and CI/CD pipelines. It can be challenging to bundle and manage the ngrok agent as a sidecar process. ngrok-go eliminates the agent, simplifying distribution and management as well as enabling developers to easily deliver private label experiences.
ngrok-go was designed with developer ergonomics top of mind and to seamlessly fit into the Go ecosystem:
- Compatible with any code that accepts a net.Listener: ngrok-go returns the standard library’s
net.Listener
interface. Developers can easily integrate ngrok-go into existing Go network code likehttp.Server
without changes. - Works in one line: ngrok-go can give you ingress with a simple
ngrok.Listen(ctx, config.HTTPEndpoint())
call. - Idiomatic functional options: ngrok-go enables developers to declare behaviors like authentication in a simple way, e.g.
config.WithOAuth("google")
. - Batteries included: ngrok-go includes logging adapters for the most common Go libraries like
zap
andlogrus
.
We validated ngrok-go’s design by dogfooding it in the ngrok agent and our soon-to-be-released Kubernetes ingress controller. We also worked with fellow gophers and customers like Airplane and Kubefirst for additional feedback on the design.
Absolutely! We’re actively building libraries for other programming languages. Rust (ngrok-rs) and JavaScript (ngrok-js) are in active development and you can follow along on GitHub. Expect other languages like Java, C#, Python and Ruby to follow. We’re eager for your feedback on which language to prioritize next.
To get started and stay up to date with ngrok-go, try the following resources:
- Quickstart guide: A step-by-step guide on how to use ngrok-go
- Go package documentation: The package documentation including functions, variables and examples
- Repo on GitHub: ngrok-go is open source on GitHub. Star the repo to follow along!