You’ve developed a world-class API, and now you want to make it available online. Aside from the challenges involved in any API gateway deployment, you’re looking for a solution that allows you to:
  • Consistently apply security and traffic management policy in one place
  • Observe all your API requests and responses from a single dashboard with Traffic Inspector
  • Add ingress to your APIs in any environment with the same agent configuration and Traffic Policy rules

What you’ll learn

In this tutorial, you’ll learn how to implement ngrok as an API gateway with these broad steps:
  1. Set up the common pattern for ngrok’s API gateway.
  2. Create one or more internal agent endpoints for your upstream API services.
  3. Create a cloud endpoint to centralize your traffic management policies, including how to forward traffic to your internal agent endpoint.

What you’ll need

  • A domain: This can be your free dev domain, or if you’re on a paid plan, one that you choose in the ngrok dashboard or with the ngrok API. Pay-as-you-go plans allow you to bring your own custom branded domain, like https://api.example.com.
    • We’ll refer to this domain as $YOUR_DOMAIN.
  • (optional) An API key: Create an ngrok API key if you’d like to use the ngrok API to manage your cloud endpoints.

Deploy a demo API service (optional)

If you don’t yet have API services you’d like to bring online with an API gateway, or just want to quickly wire up a POC using ngrok, we recommend our ngrok demo API, which responds with details about the request. Assuming you have Docker installed on the systems where your API services run, you can deploy a container listening on port 4000.
docker run -p 4000:4000 -e MESSAGE='Hello from service abc!' -d joelatngrok/api-demo
Start up a second container on port 5000.
docker run -p 5000:4000 -e MESSAGE='Hello from service xyz!' -d joelatngrok/api-demo

1. Create an internal agent endpoint

Your upstream API service needs a way of receiving traffic from the ngrok network, which you can establish with an agent endpoint on an internal URL like https://abc.internal. Replace 4000 if you’ve brought your own API service.
ngrok http 4000 --url https://abc.internal
Your API service isn’t yet accessible on the public internet. To fix that, you need two things:
  1. A cloud endpoint for traffic routing and centralized policy management.
  2. A Traffic Policy rule that forwards traffic from your cloud endpoint to https://abc.internal.

2. Create a cloud endpoint

Cloud endpoints are persistent, always-on endpoints that you can manage with the ngrok dashboard or API. You centrally control your traffic management and security policy on your cloud endpoint, then forward traffic to your endpoint pool. That’s much easier than managing these policies for each service separately and trying to keep them in sync to ward off configuration drift.
First, log into the ngrok dashboard. Select Endpoints → + New.Leave the Binding value Public, then enter the domain name you reserved earlier. Select Create Cloud Endpoint.With your cloud endpoint created, you’ll see a default Traffic Policy in the dashboard. Paste in the YAML below to apply the rule.
policy.yaml
on_http_request:
	- actions:
			- type: forward-internal
				config:
					url: https://abc.internal
Select Save to apply your changes.
At this point, your API gateway is ready for traffic. Send the following request to test it out:
curl -X GET https://$YOUR_DOMAIN
If you’re using our demo API, you’ll see a response like:
{
	"message": "Hello from ngrok!",
	"host": "localhost:4000",
	"req_headers": {
		"host": "localhost:4000",
		"user-agent": "curl/8.5.0",
		"accept": "*/*"
	},
	"method": "GET",
	"url": "/",
	"time": "2025-02-06T21:44:23.116Z",
	"status": 200
}

3. Route traffic to multiple services with Traffic Policy

Your API gateway is ready, but chances are you need to handle ingress into more than a one API service.
If you’re using our demo API service, fire up another internal agent endpoint to route traffic to the second container on port 5000.
ngrok http 5000 --url https://xyz.internal
Enter our Traffic Policy system, which lets you filter traffic based on its properties and take action as it passes through ngrok’s global network. Two important concepts of Traffic Policy to note:
  • Phases are the distinct points in the lifecycle of a request where you can filter and take action. For this use case, we’re using on_http_request, which activates when ngrok receives an HTTP request over an established connection.
  • Expressions define when to run your actions. They’re written in Common Expression Language, and must evaluate to true to run the corresponding action.
The rules below:
  1. Filter for requests arriving on only https://$YOUR_DOMAIN/abc and forward them to your internal agent endpoint at https://abc.internal.
  2. Filter for requests arriving on only https://$YOUR_DOMAIN/xyz and forward them to your internal agent endpoint at https://xyz.internal.
You can also route by other properties, like subdomains and headers.
Copy and paste the rules below into your cloud endpoint’s Traffic Policy editor in the dashboard. If you’re bringing your own API services instead of using the demo API, you’ll need to change /abc and /xyz to match your services’ paths and the url for your internal agent endpoints.
policy.yaml
on_http_request:
	- expressions:
			- "req.url.path.startsWith('/abc')"
		actions:
			- type: forward-internal
				config:
					url: https://abc.internal
	- expressions:
			- "req.url.path.startsWith('/xyz')"
		actions:
			- type: forward-internal
				config:
					url: https://xyz.internal
Hit Save to lock in the new policy.
You can now curl different paths to see your requests routed to the appropriate upstream API service.
curl https://$YOUR_DOMAIN/abc
You should get a response like:
{"message":"Hello from service abc!","host":"$YOUR_DOMAIN","req_headers":{"host":"$YOUR_DOMAIN","user-agent":"curl/8.7.1","accept":"*/*","accept-encoding":"gzip"},"method":"GET","url":"/abc","time":"2025-03-04T01:10:25.812Z","status":200}
And when you run curl https://$YOUR_DOMAIN/xyz?
{"message":"Hello from service xyz!","host":"$YOUR_DOMAIN","req_headers":{"host":"$YOUR_DOMAIN","user-agent":"curl/8.7.1","accept":"*/*","accept-encoding":"gzip"},"method":"GET","url":"/xyz","time":"2025-03-04T01:10:25.812Z","status":200}

4. Add traffic management policies

Your API gateway routes traffic, but doesn’t yet do essential work of an API gateway: offload all the non-functional requirements away from your services. One great feature of ngrok’s building blocks of endpoints and Traffic Policy rules is that they’re composable—you can reuse them, chain them, and apply them at multiple stages in the lifecycle of an API request. With the shape you’ve already created, you can centrally manage certain policies, like authentication, on your cloud endpoint, then compose additional rules onto specific services.

Validate JWTs on all APIs and requests

API authentication is too important not to apply consistently across all your APIs and requests. That’s where the always-on, front door to all your routes quality of a cloud endpoint comes in handy—you can apply the jwt-validation action once for dependable AuthN no matter how many services you end up deploying behind your multicloud API gateway. ngrok’s JWT validation action helps you:
  • Give your end users many ways to access your APIs.
  • Ensure only requests containing the correct access token, specified by an Authorization: Bearer ... header, can access any of your APIs.
  • Add claims to tokens for authorization and fine-grained access control where a specific token may only have access to a certain API (service_access: abc) or apply RBAC (features: read).
  • Use a single credential for end users who need to access multiple upstream services.
  • Offload all this logic from your API services and run it in ngrok’s network.
You can use any OAuth provider for JWT validation, but let’s quickly cover the process with Auth0.
  • Log in to your Auth0 tenant dashboard.
  • Select Applications > APIs, then + Create API.
  • Name your API whatever you’d like.
  • Replace the value of the Identifier field with $YOUR_DOMAIN.
  • Leave the default values for JSON Web Token (JWT) Profile and JSON Web Token Signing Algorithm.
  • Select Create.
  • Navigate to your application and select the Test tab, where you can find a signed, fully functional JWT and examples of how to programmatically generate more.
The rule below builds on top of the previous cloud endpoint policy to:
  1. Reject requests missing a token with a 401 Unauthorized error.
  2. Reject requests with an invalid token with a 403 Forbidden error.
  3. Forward requests with a valid token to one of your internal agent endpoints based on the pathname.
You’ll need to change the variables accordingly—if you’re not sure where to find this information, we have a full integration guide with more details.
policy.yaml
on_http_request:
  - actions:
      - type: jwt-validation
        config:
          issuer:
            allow_list:
              - value: "https://<YOUR_AUTH0_TENANT_ID>.<YOUR_AUTH0_REGION>.auth0.com/"
          audience:
            allow_list:
              - value: "https://$YOUR_DOMAIN"
          http:
            tokens:
              - type: "jwt"
                method: "header"
                name: "Authorization"
                prefix: "Bearer "
          jws:
            allowed_algorithms:
              - "RS256"
            keys:
              sources:
                additional_jkus:
                  - "https://<YOUR_AUTH0_TENANT_ID>.<YOUR_AUTH0_REGION>.auth0.com/.well-known/jwks.json"
  - expressions:
      - "req.url.path.startsWith('/abc')"
    actions:
      - type: forward-internal
        config:
          url: https://abc.internal
  - expressions:
      - "req.url.path.startsWith('/xyz')"
    actions:
      - type: forward-internal
        config:
          url: https://xyz.internal
Apply in either the dashboard or ngrok API.

5. Rate limit specific API services

Let’s say one of your services (like abc on port 4000, if you’re following along with the demo service), needs additional protection from unintentional misuse and malicious attacks. The rate-limit Traffic Policy action allows you to reject requests with a 429 error code once a user or group have exceeded your customizable threshold. Create a new file named abc-policy.yaml on the system where you’re running your API services and ngrok agent and paste in the YAML below. The rule below creates new policy at your agent to:
  1. Allow up to 10 requests per IP in a 60s window.
  2. Reject requests that exceed the rate limiting capacity with a 429 error response.
abc-policy.yaml
on_http_request:
	- actions:
			- type: rate-limit
				config:
					name: Only allow 10 requests per minute
					algorithm: sliding_window
					capacity: 10
					rate: 60s
					bucket_key:
						- conn.client_ip
Restart the ngrok agent to enable abc-policy.yaml.
ngrok http 4000 --url https://abc.internal --traffic-policy-file /path/to/abc-policy.yaml
Ready to test your rate limit in action? Run the below command after replacing $YOUR_DOMAIN and the path, if relevant.
for i in `seq 1 50`; do curl -X GET -w '%{http_code}' https://$YOUR_DOMAIN/abc ; done
You’ll see a few normal responses until you hit the rate limit, and then you’ll see 429 errors. Run the same command on the /xyz path and you won’t see the same errors, since you’ve applied this policy only to the https://abc.internal agent endpoint. If you want all your APIs to have a consistent rate limiting strategy, you can move the rule to your cloud endpoint above the jwt-validation action.

What’s next?

You’ve now brought your APIs online with ngrok’s API gateway, which also automatically gives you features like DDoS protection and global load balancing. Plus, you’ve added global AuthN with JWTs and explored composing Traffic Policy rules on multiple endpoints. That said, your journey into deploying and securing services with ngrok’s API gateway is just beginning. Next up, we recommend you:
  1. Check out your Traffic Inspector (documentation) to observe, modify, and replay requests across your API gateway.
  2. Explore other opportunities to manage and take action on API traffic in our Traffic Policy documentation.
  3. Learn how to monitor your API traffic, so you’ll know how your service is performing at all times, and be alerted to errors.