> ## Documentation Index
> Fetch the complete documentation index at: https://ngrok.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get started with ngrok's API gateway

> Learn how to set up ngrok as an API gateway using a Cloud Endpoint that forwards traffic to internal Agent Endpoints with Traffic Policy.

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](/obs/traffic-inspection/#ngrok-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](https://dashboard.ngrok.com/domains) or with the [ngrok
  API](/api-reference/reserveddomains/create). Pay-as-you-go plans allow you to bring your own [custom branded
  domain](/gateway/custom-domains), like
  `https://api.example.com`.
  * This guide refers to this domain as `$YOUR_DOMAIN`.
* (optional) **An API key**: [Create an ngrok API
  key](https://dashboard.ngrok.com/api-keys/new) 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, use the
[ngrok demo API](https://github.com/ngrok-samples/api-demo), 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`.

```bash theme={null}
docker run -p 4000:4000 -e MESSAGE='Hello from service abc!' -d joelatngrok/api-demo
```

Start up a second container on port `5000`.

```bash theme={null}
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.

<Tabs>
  <Tab>
    First, log into the [ngrok dashboard](https://dashboard.ngrok.com). 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.

    ```yaml title="policy.yaml" mode=traffic-policy theme={null}
    on_http_request:
    - actions:
      - type: forward-internal
        config:
          url: https://abc.internal
    ```

    Select **Save** to apply your changes.
  </Tab>

  <Tab>
    The `ngrok` CLI provides a helpful wrapper around the [ngrok API](/api/index), which you can use to create a Cloud Endpoint and apply a file containing Traffic Policy rules.

    Create a new file named `policy.yaml` on your local workstation with the following YAML.

    ```yaml title="policy.yaml" mode=traffic-policy theme={null}
    on_http_request:
    - actions:
      - type: forward-internal
        config:
          url: https://abc.internal
    ```

    Create a Cloud Endpoint on `$YOUR_DOMAIN`, passing your `policy.yaml` file as an option.

    ```bash theme={null}
    ngrok api endpoints create \
    --bindings public \
    --url https://$YOUR_DOMAIN
    	--traffic-policy "$(cat policy.yaml)"
    ```

    You'll get a `201` response—save the value of `id`, as you'll need it again later to continue configuring the Traffic Policy applied to your Cloud Endpoint.
  </Tab>
</Tabs>

At this point, your API gateway is ready for traffic. Send the following request to test it out:

```bash theme={null}
curl -X GET https://$YOUR_DOMAIN
```

If you're using the demo API, you'll see a response like:

```json theme={null}
{
	"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.

<Tip>
  If you're using the demo API service, fire up another internal Agent Endpoint to route traffic to the second container on port `5000`.

  ```bash theme={null}
  ngrok http 5000 --url https://xyz.internal
  ```
</Tip>

Use the [Traffic Policy system](/traffic-policy), 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](/traffic-policy/how-it-works#phases) are the distinct points in the lifecycle of
  a request where you can filter and take action. For this use case, `on_http_request` is used,
  which activates when ngrok receives an HTTP request over an
  established connection.
* [Expressions](/traffic-policy/how-it-works#expressions) define when to run
  your actions. They're written in [Common Expression
  Language](https://github.com/google/cel-spec), 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](/traffic-policy/examples/route-requests), like subdomains and
headers.

<Tabs>
  <Tab>
    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.

    ```yaml mode=traffic-policy title="policy.yaml" theme={null}
    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.
  </Tab>

  <Tab>
    Update your existing `policy.yaml` file with the YAML below. 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.

    ```yaml mode=traffic-policy title="policy.yaml" theme={null}
    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
    ```

    Update your Cloud Endpoint.

    ```bash theme={null}
    ngrok api endpoints update <CLOUD_ENDPOINT_ID> \
    	--traffic-policy "$(cat policy.yaml)"
    ```
  </Tab>
</Tabs>

You can now `curl` different paths to see your requests routed to the
appropriate upstream API service.

```bash theme={null}
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](/traffic-policy/actions/jwt-validation) 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. The process with Auth0 is covered below.

* Log in to your [Auth0 tenant dashboard](https://manage.auth0.com/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, see the full [integration
guide](/integrations/jwt-validation/auth0) with more details.

```yaml mode="traffic-policy" title="policy.yaml" theme={null}
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

For example, one of your services (like `abc` on port `4000`, if you're following along with the demo service) may need additional protection from unintentional misuse and malicious attacks.

The [`rate-limit` Traffic Policy
action](/traffic-policy/actions/rate-limit) 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.

```yaml title="abc-policy.yaml" mode="file" theme={null}
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`.

```bash theme={null}
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.

```bash theme={null}
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:

1. Check out your [Traffic
   Inspector](https://dashboard.ngrok.com/observability/traffic-inspector)
   ([documentation](/obs/traffic-inspection#ngrok-traffic-inspector)) to
   observe, modify, and replay requests across your API gateway.
2. Explore other opportunities to manage and take action on API traffic in the
   [Traffic Policy documentation](/traffic-policy).
3. Learn [how to monitor your API traffic](/guides/api-gateway/monitor-ngrok), so you'll
   know how your service is performing at all times, and be alerted to errors.
