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

# CloudEndpoint

> Reference documentation for the CloudEndpoint Kubernetes custom resource for creating persistent, always-on Cloud Endpoints.

## CloudEndpoint custom resource

### **apiVersion:** `ngrok.k8s.ngrok.com/v1alpha1`

### **kind:** `CloudEndpoint`

The `CloudEndpoint` custom resource is used to create centrally managed endpoints in the cloud. Cloud Endpoints are persistent, always-on endpoints that live within the ngrok cloud.
They exist permanently until they are explicitly deleted. Cloud Endpoints do not forward their traffic to an agent by default and instead only use their attached Traffic Policy to handle connections.
Using the Traffic Policy configuration, you may configure your Cloud Endpoints to route to one or more other internal ngrok endpoints.

For more information about Cloud Endpoints in ngrok, refer to the [Cloud Endpoints page](/gateway/cloud-endpoints/)

## CloudEndpoint structure and types

The following outlines the high level structure and typings of a `CloudEndpoint`

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: CloudEndpoint
metadata:
  name: <string>
  namespace: <string>
spec:
  url: <string>               # required
  trafficPolicyName: <string> # optional
  trafficPolicy:              # optional
    policy:                   # required
      <Traffic Policy config>
  description: <string>       # optional, default: "Created by the ngrok-operator"
  metadata: <string>          # optional, default: "{"owned-by":"ngrok-operator"}"
  bindings: <[]string>        # optional
  poolingEnabled: <bool>      # optional, default: false
```

## CloudEndpoint fields

The following sections outline each field of the `CloudEndpoint` custom resource, whether they are required, what their default values are (if applicable), and a description of their purpose/constraints.

### `spec`

`spec` defines the desired state of the `CloudEndpoint`

**Type:** `Object`

**Required:** yes

**Default:** none

**Fields:**

| Field Name                                         | Type              | Required | Default                           | Description                                                                                                                              |
| -------------------------------------------------- | ----------------- | -------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| [`spec.url`](#specurl)                             | `string`          | yes      | none                              | The unique URL for this `CloudEndpoint` that defines how the endpoint is accessed                                                        |
| [`spec.trafficPolicyName`](#spectrafficpolicyname) | `string`          | no       | none                              | The name of an `NgrokTrafficPolicy` custom resource in the same namespace as the `CloudEndpoint` to use for Traffic Policy configuration |
| [`spec.trafficPolicy`](#spectrafficpolicy)         | `Object`          | no       | none                              | Allows for a Traffic Policy to be provided to the `CloudEndpoint` using inline configuration                                             |
| [`spec.description`](#specdescription)             | `string`          | no       | `"Created by the ngrok-operator"` | Human-readable description for this `CloudEndpoint` to help identify/describe it                                                         |
| [`spec.metadata`](#specmetadata)                   | `string`          | no       | `"{"owned-by":"ngrok-operator"}"` | String of arbitrary data associated with the object in the ngrok API/Dashboard                                                           |
| [`spec.bindings`](#specbindings)                   | `[]string` (enum) | no       | none                              | List of Binding IDs to associate with the endpoint                                                                                       |
| [`spec.poolingEnabled`](#specpoolingenabled)       | `bool`            | no       | `false`                           | Whether or not the `CloudEndpoint` should enable pooling with other endpoints sharing the same URL                                       |

### `spec.url`

The unique URL for this Cloud Endpoint. This URL defines how the endpoint is accessed.

**Type:** `string`

**Required:** yes

**Default:** none

The following formats are accepted:

* **Domain**
  * When using the domain format you are only defining the domain. The scheme and port will be inferred.
  * example: `example.org`
* **Origin**
  * When using the origin format you are defining the protocol, domain and port. HTTP endpoints accept ports `80` or `443` with respective protocol.
  * examples:
    * `https://example.ngrok.app`
    * `https://example.ngrok.app:443`
    * `tcp://1.tcp.ngrok.io:12345`
    * `tls://example.ngrok.app`
* **Scheme (shorthand)**
  * When using scheme you are defining the protocol and will receive back a randomly assigned ngrok address.
  * examples:
    * `https://`
    * `tcp://`
    * `tls://`
    * `http://`
* **Empty**
  When empty your endpoint will default to be https and receive back a randomly assigned ngrok address.
* **Internal**
  * When ending your URL with .internal, an internal endpoint will be created. Internal Endpoints cannot be accessed directly, but rather
    can only be accessed using the forward-internal Traffic Policy action.
  * example: `some.domain.internal`

### `spec.trafficPolicyName`

Reference to an `NgrokTrafficPolicy` custom resource in the same namespace as the `CloudEndpoint` to use for Traffic Policy configuration.
It is invalid to configure both `spec.trafficPolicyName` and `spec.trafficPolicy` at the same time.

The referenced `NgrokTrafficPolicy` **must** be in the same namespace as the `CloudEndpoint`.

**Type:** `string`

**Required:** no

**Default:** none

### `spec.trafficPolicy`

Reference to an `NgrokTrafficPolicy` custom resource in the same namespace as the `CloudEndpoint` to use for Traffic Policy configuration.
It is invalid to configure both `spec.trafficPolicyName` and `spec.trafficPolicy` at the same time.
For more information about writing ngrok Traffic Policies, refer to the [Traffic Policy section](/traffic-policy/).

**Type:** `Object`

**Required:** no

**Default:** none

**Fields:**

| Field Name                                              | Type              | Required | Default | Description                                                                 |
| ------------------------------------------------------- | ----------------- | -------- | ------- | --------------------------------------------------------------------------- |
| [`spec.trafficPolicy.policy`](#spectrafficpolicypolicy) | `json.RawMessage` | yes      | none    | The inline Traffic Policy configuration to be used for this `CloudEndpoint` |

### `spec.trafficPolicy.policy`

Allows you to supply a Traffic Policy for this `AgentEndpoint` with inline configuration. An example has been included below.
For more information about writing ngrok Traffic Policies, refer to the [Traffic Policy section](/traffic-policy/).

**Type:** `json.RawMessage`

**Required:** yes

**Default:** none

### `spec.description`

Human-readable description of this Cloud Endpoint that can be used to help identify/describe it.

**Type:** `string`

**Required:** no

**Default:** `"Created by the ngrok-operator"`

### `spec.metadata`

String of arbitrary data associated with the object in the ngrok API/Dashboard.

**Type:** `string`

**Required:** no

**Default:** `"{"owned-by":"ngrok-operator"}"`

### `spec.bindings`

List of Binding IDs to associate with the endpoint

**Type:** `string` (enum)

**Required:** no

**Default:** none

**Accepted Values:** `"public"`, `"internal"`, or `"kubernetes"`

* A binding of `"internal"` will create an internal `AgentEndpoint` that is only accessible from other endpoints using the `forward-internal` Traffic Policy action.
  * Aside from setting `bindings: ["internal"]`, the `spec.url` of the `AgentEndpoint` must end in `.internal`
  * Setting `bindings: ["public"]` will not work for internal endpoints (endpoints that have a `spec.url` ending in `.internal`)
* A binding of `"public"` will create a standard `AgentEndpoint` with its `spec.url` accessible to the public internet
  * Setting `bindings: ["internal"]` will not work for public endpoints
* A binding of `"kubernetes"` will create a Kubernetes bound endpoint. This causes the endpoint to not be publicly accessible to the public internet
  and will be projected into one or more of your Kubernetes clusters that are running the ngrok Operator (depending on their endpoint selector configuration) as `Services`.
  * With a `"kubernetes"` binding, the `spec.url` becomes the `name.namespace` of the projected Service.
  * For example, with a `spec.url` of `http://my-service.my-namespace` then a Service with name `my-service` in the `my-namespace` namespace will be created by the ngrok Operator.
    Other services within the Kubernetes cluster can make requests to this endpoint. This enables many different use-cases such as being able to project a service in one Kubernetes cluster
    to another Kubernetes cluster so that services running in the other cluster can make requests to it. This has the benefit of not needing to expose the endpoint to the public internet behind a publicly accessible URL.

### `spec.poolingEnabled`

Configures whether [pooling](/gateway/endpoint-pooling) is always enabled for this `CloudEndpoint`.

When pooling is enabled, if two different endpoints share the same `spec.url` then requests will be balanced between them.
This is not limited to endpoints within the same cluster, or endpoints of the same type. For example, a `CloudEndpoint` can be pooled with an Agent Endpoint created using the ngrok CLI if they both enable pooling and share the same URL.

It is recommended to include a prefix/suffix in the URL to prevent unintended pooling. For example, if you are running a service `foo` in the namespace `bar` in two different
Kubernetes clusters, you may want to give each one a slightly different `spec.url` that includes something such as a cluster identifier to prevent requests from being balanced between them.

You will receive an error back from the ngrok server if you attempt to create two different endpoints using the same URL if they do not both enable pooling.
In this scenario, the older endpoint wins and the newer one will fail to be created.

**Type:** `bool`

**Required:** no

**Default:** `false`

## Status fields

The `CloudEndpoint` resource includes status information that reflects the current state of the Cloud Endpoint in the ngrok system.

### `status.id`

The ngrok API ID for this Cloud Endpoint.

**Type:** `string`

**Example:** `ep_34iZT0muBP3kpcAXxGjM4uFlgDK`

### `status.domain`

**(Deprecated)** Domain information for the endpoint. This field is deprecated; use `status.domainRef` instead.

**Type:** `Object`

### `status.domainRef`

Reference to the Domain resource associated with this Cloud Endpoint.

**Type:** `Object`

**Fields:**

* `name` - Name of the Domain resource
* `namespace` - Namespace of the Domain resource

**Example:**

```yaml theme={null}
domainRef:
  name: example-domain-ngrok-app
  namespace: default
```

### `status.conditions`

Standard Kubernetes conditions that indicate the state of the Cloud Endpoint.

**Type:** `[]Condition`

Each condition includes:

* `type` - The condition type
* `status` - `True`, `False`, or `Unknown`
* `reason` - A programmatic identifier for the condition state
* `message` - A human-readable description
* `lastTransitionTime` - When the condition last changed
* `observedGeneration` - The resource generation this condition applies to

#### Condition types

##### `Ready`

Indicates whether the Cloud Endpoint is fully operational and ready to use.

**Status Values:**

* `True` - Cloud endpoint is active and ready
* `False` - Cloud endpoint is not ready (see reason for details)

**Reasons:**

| Reason                        | Status  | Meaning                                                              |
| ----------------------------- | ------- | -------------------------------------------------------------------- |
| `CloudEndpointActive`         | `True`  | Cloud endpoint is successfully created and active                    |
| `CloudEndpointCreationFailed` | `False` | Failed to create the Cloud Endpoint in ngrok                         |
| `Pending`                     | `False` | Cloud endpoint creation is pending (for example, waiting for domain) |
| `Unknown`                     | `False` | Cloud endpoint state is unknown                                      |
| `DomainNotReady`              | `False` | Associated domain is not ready                                       |

Additionally, the `Ready` condition may reflect reasons from the associated Domain resource when domain issues prevent endpoint creation.

**Example:**

```yaml theme={null}
conditions:
- type: Ready
  status: "True"
  reason: CloudEndpointActive
  message: "Cloud endpoint is active"
  lastTransitionTime: "2025-10-29T00:39:16Z"
  observedGeneration: 1
```

**Example (Pooling Error):**

```yaml theme={null}
conditions:
- type: Ready
  status: "False"
  reason: CloudEndpointCreationFailed
  message: |
    Failed to create Cloud Endpoint: HTTP 400: The provided Cloud Endpoint was invalid because pooling was set to disabled when another endpoint exists for this url. [ERR_NGROK_18017]
    
    Operation ID: op_34ic9T376GyGAXQ4sIRn7F0xUYP
  lastTransitionTime: "2025-10-29T00:39:15Z"
  observedGeneration: 2
```

##### `CloudEndpointCreated`

Indicates whether the Cloud Endpoint was successfully created in the ngrok API.

**Status Values:**

* `True` - Cloud endpoint was successfully created
* `False` - Failed to create Cloud Endpoint

**Reasons:**

| Reason                        | Status  | Meaning                                  |
| ----------------------------- | ------- | ---------------------------------------- |
| `CloudEndpointCreated`        | `True`  | Cloud endpoint successfully created      |
| `CloudEndpointCreationFailed` | `False` | API call to create Cloud Endpoint failed |

**Example:**

```yaml theme={null}
conditions:
- type: CloudEndpointCreated
  status: "True"
  reason: CloudEndpointCreated
  message: "Cloud endpoint successfully created"
  lastTransitionTime: "2025-10-29T00:39:16Z"
  observedGeneration: 1
```

##### `DomainReady`

Indicates whether the associated domain is ready for use. This condition propagates the state from the referenced Domain resource.

**Status Values:**

* `True` - Domain is ready
* `False` - Domain is not ready

**Reasons:**

This condition propagates reasons from the Domain resource's `Ready` condition, including:

* `DomainActive` - Domain is successfully reserved and ready
* `ProvisioningError` - Domain has DNS or certificate provisioning errors
* `DomainCreationFailed` - Domain failed to be created
* `DomainInvalid` - Domain format or configuration is invalid

**Example:**

```yaml theme={null}
conditions:
- type: DomainReady
  status: "True"
  reason: DomainActive
  message: "Domain ready for use"
  lastTransitionTime: "2025-10-29T00:39:25Z"
  observedGeneration: 1
```

**Example (Domain DNS Error):**

```yaml theme={null}
conditions:
- type: DomainReady
  status: "False"
  reason: ProvisioningError
  message: 'DNS_ERROR Reserved domain "example.com" NS DNS records are not pointing at the ngrok infrastructure'
  lastTransitionTime: "2025-10-29T00:39:24Z"
  observedGeneration: 1
```

## Status examples

### Successfully created Cloud Endpoint

```yaml theme={null}
status:
  id: ep_34iZT0muBP3kpcAXxGjM4uFlgDK
  domainRef:
    name: example-domain-ngrok-app
    namespace: default
  conditions:
  - type: DomainReady
    status: "True"
    reason: DomainActive
    message: "Domain ready for use"
    lastTransitionTime: "2025-10-29T00:39:25Z"
    observedGeneration: 1
  - type: CloudEndpointCreated
    status: "True"
    reason: CloudEndpointCreated
    message: "Cloud endpoint successfully created"
    lastTransitionTime: "2025-10-29T00:39:16Z"
    observedGeneration: 1
  - type: Ready
    status: "True"
    reason: CloudEndpointActive
    message: "Cloud endpoint is active"
    lastTransitionTime: "2025-10-29T00:39:16Z"
    observedGeneration: 1
```

### Cloud Endpoint with pooling error

```yaml theme={null}
status:
  domainRef:
    name: example-domain-ngrok-app
    namespace: default
  conditions:
  - type: DomainReady
    status: "True"
    reason: DomainActive
    message: "Domain ready for use"
    lastTransitionTime: "2025-10-29T00:39:25Z"
    observedGeneration: 2
  - type: CloudEndpointCreated
    status: "False"
    reason: CloudEndpointCreationFailed
    message: |
      Failed to create Cloud Endpoint: HTTP 400: The provided Cloud Endpoint was invalid because pooling was set to disabled when another endpoint exists for this url. [ERR_NGROK_18017]
      
      Operation ID: op_34ic9T376GyGAXQ4sIRn7F0xUYP
    lastTransitionTime: "2025-10-29T00:39:25Z"
    observedGeneration: 2
  - type: Ready
    status: "False"
    reason: CloudEndpointCreationFailed
    message: |
      Failed to create Cloud Endpoint: HTTP 400: The provided Cloud Endpoint was invalid because pooling was set to disabled when another endpoint exists for this url. [ERR_NGROK_18017]
      
      Operation ID: op_34ic9T376GyGAXQ4sIRn7F0xUYP
    lastTransitionTime: "2025-10-29T00:39:15Z"
    observedGeneration: 2
```

### Cloud Endpoint with domain not ready

```yaml theme={null}
status:
  domainRef:
    name: custom-domain-com
    namespace: default
  conditions:
  - type: DomainReady
    status: "False"
    reason: ProvisioningError
    message: 'DNS_ERROR Reserved domain "example.com" NS DNS records are not pointing at the ngrok infrastructure'
    lastTransitionTime: "2025-10-29T00:39:24Z"
    observedGeneration: 1
  - type: CloudEndpointCreated
    status: "False"
    reason: Pending
    message: "Waiting for domain to be ready"
    lastTransitionTime: "2025-10-29T00:39:24Z"
    observedGeneration: 1
  - type: Ready
    status: "False"
    reason: DomainNotReady
    message: "Cloud endpoint cannot be created because domain is not ready"
    lastTransitionTime: "2025-10-29T00:39:24Z"
    observedGeneration: 1
```

## Checking Cloud Endpoint status

You can check the status of a Cloud Endpoint using kubectl:

```bash theme={null}
# Check if Cloud Endpoint is ready
kubectl get cloudendpoint example-cloud-endpoint -o jsonpath='{.status.conditions[?(@.type=="Ready")]}'

# Watch for Cloud Endpoint to become ready
kubectl wait --for=condition=Ready cloudendpoint/example-cloud-endpoint --timeout=60s

# Get all Cloud Endpoints with their ready status
kubectl get cloudendpoints -A -o custom-columns=\
NAME:.metadata.name,\
NAMESPACE:.metadata.namespace,\
DOMAIN:.status.domainRef.name,\
READY:.status.conditions[?(@.type==\'Ready\')].status,\
REASON:.status.conditions[?(@.type==\'Ready\')].reason

# Check domain readiness for a Cloud Endpoint
kubectl get cloudendpoint example-cloud-endpoint -o jsonpath='{.status.conditions[?(@.type=="DomainReady")]}'
```

## Example CloudEndpoints

### CloudEndpoint with inline Traffic Policy

The following `CloudEndpoint`:

* Accepts traffic on the URL `https://example-cloud-endpoint.ngrok.io`
* Adds an inline Traffic Policy that sends back a custom response

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: CloudEndpoint
metadata:
  name: example-cloud-endpoint
spec:
  url: https://example-cloud-endpoint.ngrok.io
  trafficPolicy:
    policy:
      on_http_request:
      - name: example-rule
        actions:
        - type: custom-response
          config:
            body: Example response from Traffic Policy
            headers:
              content-type: text/plain
            status_code: 200
```

### CloudEndpoint with referenced Traffic Policy

The following `CloudEndpoint`:

* Accepts traffic on the URL `https://example-cloud-endpoint.ngrok.io`
* Adds a reference to a Traffic Policy that sends back a custom response

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: NgrokTrafficPolicy
metadata:
  name: static-response
  namespace: default
spec:
  policy:
    on_http_request:
    - name: example-rule
      actions:
      - type: custom-response
        config:
          body: Example response from Traffic Policy
          headers:
            content-type: text/plain
          status_code: 200
---
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: CloudEndpoint
metadata:
  name: example-cloud-endpoint
spec:
  url: https://example-cloud-endpoint.ngrok.io
  trafficPolicyName: static-response
```
