> ## 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.

# Path-based Routing and Policy Decentralization with Cloud Endpoints

> Learn how to use Cloud Endpoints to route traffic by path and apply different Traffic Policies to each of your endpoints.

This guide provides an example on how to forward traffic to internal endpoints based on path using ngrok Cloud Endpoints. The Cloud Endpoint will have a Traffic Policy to route traffic to one of two internal endpoints depending on the path, but each internal endpoint will also have its own Traffic Policy to independently handle incoming traffic.

## Core concepts

* [Cloud endpoints](/gateway/cloud-endpoints) are centrally managed endpoints in the cloud that can be used to route traffic to Agent Endpoints.
* [Internal endpoints](/gateway/internal-endpoints) are endpoints that are not publicly accessible and are only reachable from within your network by Cloud Endpoints via the forward action.
* **Path-Based Routing** involves directing incoming traffic to different destinations based on the path component of a URL

## Prerequisites

To follow this guide, you will need a local computer with `ngrok` installed [by following the installation guides](https://download.ngrok.com).

If you are going to be following along using **ngrok CLI**, you will need:

* An [ngrok API key](https://dashboard.ngrok.com/api) configured on your [ngrok agent](/agent/#api).

If you are going to be following along using **CURL**, you will need:

* An [ngrok API key](https://dashboard.ngrok.com/api) as an environment variable named `NGROK_API_KEY`.

## 1. Create an internal endpoint for the homepage

Start by creating an internal endpoint for the homepage endpoint, which will handle all non-API traffic.

```bash theme={null}
ngrok http 80 \
    --url https://homepage.internal
```

After running, you should see the endpoint with an "online" status at your domain. It will route traffic to the app running at your local port 80, which you can setup to have any HTTP server running.

## 2. Create an internal endpoint for the API

Next, create another internal endpoint, this one for all traffic to the `/api/` path.

Use a Traffic Policy to simulate accessing an API endpoint.

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - expressions:
        - "!(hasReqHeader('Api-Key'))"
      actions:
        - type: deny
          config:
            status_code: 404
    - actions:
        - type: custom-response
          config:
            status_code: 200
            body: "<html><body><h1>Hello world</h1><p>The quick brown fox jumps over the lazy dog.</p></body></html>"
            headers:
              content-type: text/html
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "expressions": [
          "!(hasReqHeader('Api-Key'))"
        ],
        "actions": [
          {
            "type": "deny",
            "config": {
              "status_code": 404
            }
          }
        ]
      },
      {
        "actions": [
          {
            "type": "custom-response",
            "config": {
              "status_code": 200,
              "body": "<html><body><h1>Hello world</h1><p>The quick brown fox jumps over the lazy dog.</p></body></html>",
              "headers": {
                "content-type": "text/html"
              }
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

The above Traffic Policy will deny all requests that do not have an `API-Key` header, and return a 200 status code with a custom response for all other requests.

Save the Traffic Policy as a file locally in your directory. Now, create an internal endpoint based on this Traffic Policy.

```bash theme={null}
ngrok http 3001 \
    --url https://api.internal \
    --traffic-policy-file {PATH_TO_TRAFFIC_POLICY}
```

After running, you should see the endpoint with an "online" status for your endpoint.

## 3. Create a domain for the Cloud Endpoint

Next, create the domain or TCP address that the Cloud Endpoint will reside on.
For the purpose of this guide, create an ngrok HTTP domain.

<Tabs>
  <Tab title="ngrok CLI">
    ```bash theme={null}
    ngrok api reserved-domains create \
        --url ${NGROK_SUBDOMAIN}.ngrok.app
    ```

    * Replace `NGROK_SUBDOMAIN` with the subdomain you'd like to use for this guide.

    After running, you should see the following:

    ```json skip-validation theme={null}
    200 OK
    {
       "id":"rd_2MT5Bqt0UzU0mFQ0zr8m1UQWCfm",
       ...
    }
    ```
  </Tab>

  <Tab title="CURL">
    ```bash theme={null}
    curl \
        -X POST https://api.ngrok.com/reserved_domains \
        -H "Authorization: Bearer ${NGROK_API_KEY}" \
        -H "Content-Type: application/json" \
        -H "Ngrok-Version: 2" \
        -d @- <<BODY
        {
            "name":"${NGROK_SUBDOMAIN}.ngrok.app",
        }
    BODY
    ```

    * Replace `NGROK_API_KEY` with your ngrok API key.
    * Replace `NGROK_SUBDOMAIN` with the subdomain you'd like to use for this guide.

    After running, you should see the following:

    ```json skip-validation theme={null}
    200 OK
    {
       "id":"rd_2MT5Bqt0UzU0mFQ0zr8m1UQWCfm",
       ...
    }
    ```
  </Tab>

  <Tab title="ngrok Dashboard">
    You can reserve a subdomain via [ngrok dashboard](https://dashboard.ngrok.com/domains/new).
    After successfully reserving a domain, you should see it listed in the domains table.
  </Tab>
</Tabs>

When you have completed this step, you can move on to the next step.

## 4. Create a Traffic Policy for your Cloud Endpoint

Now, create a Traffic Policy for the Cloud Endpoint.
All incoming traffic will be preprocessed by this Traffic Policy, before
being forwarded to the internal endpoints which may or may not have their
own independent Traffic Policies. This separation allows for granularity and
full control over how traffic is handled.

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
  - expressions:
    - req.url.path.startsWith('/api/')
    actions:
    - type: forward-internal
      config:
        url: https://api.internal
        binding: internal
  - actions:
    - type: forward-internal
      config:
        url: https://homepage.internal
        binding: internal
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "expressions": [
          "req.url.path.startsWith('/api/')"
        ],
        "actions": [
          {
            "type": "forward-internal",
            "config": {
              "url": "https://api.internal",
              "binding": "internal"
            }
          }
        ]
      },
      {
        "actions": [
          {
            "type": "forward-internal",
            "config": {
              "url": "https://homepage.internal",
              "binding": "internal"
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

The Traffic Policy simply forwards traffic to one of the two internal endpoints based on the path.
More complex traffic handling can be created at your discretion.

## 5. Create an ngrok Cloud Endpoint

Now create an ngrok Cloud Endpoint that points to the
newly created internal endpoint. Cloud Endpoints can be created
via the API or ngrok dashboard.

<Tabs>
  <Tab title="API">
    We use the URL from Step 2 as the `url` value in the Traffic Policy, and the Traffic Policy from Step 3 as the `traffic-policy` value.
    The binding is set to public so anyone can access our Cloud Endpoint.

    Due to the shell's difficulty in parsing a more complex string that includes both `'` and `"`, we will use Postman to
    send a POST request to the ngrok API instead of using the `ngrok api` command.

    1. Open Postman and create a POST request to `https://api.ngrok.com/endpoints`.
    2. In the Authorization tab, select "API Key".
       * Set Key as `Authorization`
       * Set Value as `Bearer NGROK_API_KEY`
       * Set Add to as `Header`
    3. In the Headers tab, add a new header:
       * Create a header with the key `Content-Type` and value `application/json`
       * Create a header with the key `Ngrok-Version` and value `2`
    4. In the Body tab, create a raw JSON:

    ```json theme={null}
    {
    	"bindings": ["public"],
    	"description": "sample Cloud Endpoint",
    	"metadata": "{\"environment\": \"prod\"}",
    	"type": "cloud",
    	"traffic_policy": "{\"on_http_request\": [{\"expressions\": [\"req.url.path.startsWith('/api/')\"],\"actions\": [{\"type\": \"forward-internal\",\"config\": {\"url\": \"https://api.internal\",\"binding\": \"internal\"}}]},{\"actions\": [{\"type\": \"forward-internal\",\"config\": {\"url\": \"https://homepage.internal\",\"binding\": \"internal\"}}]}]}",
    	"url": "https://{NGROK_SUBDOMAIN}.ngrok.app"
    }
    ```

    * Replace `YOUR_NGROK_API_KEY` with your ngrok API key.
    * Replace `NGROK_SUBDOMAIN` with the value used in Step 3.

    For more details on using the API to create a Cloud Endpoint, see the \[API documentation for endpoints]\(/api-reference/endpoints/list.
  </Tab>

  <Tab title="ngrok Dashboard">
    Coming soon!
  </Tab>
</Tabs>

## Conclusion

You've successfully created a Cloud Endpoint that can be accessed from the URL you reserved: `${NGROK_SUBDOMAIN}.ngrok.app`

On most paths, the Cloud Endpoint will refer to its Traffic Policy and forward traffic to the homepage internal endpoint, which exposes the app running on local port 80.

For /api/ paths, the Cloud Endpoint will forward traffic to the API internal endpoint. It requires an `Api-Key` header to access, and denies for all other requests.
You won't be able to access the API normally from the browser, but you can use CURL or Postman to test it.

```bash theme={null}
curl --header "Api-Key: AnythingHere" https://${NGROK_SUBDOMAIN}.ngrok.app/api/
```
