> ## Documentation Index
> Fetch the complete documentation index at: https://controlplanecorporation-kyle-cron-and-quotas.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Domain

> Domain configuration for workloads with TLS certificates, geo-routing, path-based routing, and DNS verification modes (CNAME and NS delegation).

## Domain Overview

[Workloads](/concepts/workload) managed by Control Plane can be configured to serve requests using domains that you own.

Domains are scoped to an [org](/reference/org) and are associated with **one** [GVC](/reference/gvc). The domain can then be configured to handle requests for one or more [workloads](/concepts/workload) within that [GVC](/reference/gvc).

Domains configured in Control Plane are automatically secured with TLS certificates, load balanced, and DNS geo-routed to the nearest healthy [location](/reference/location) assigned to the [GVC](/reference/gvc). Geo-routing behavior can be customized per location using [location routing options](/reference/gvc#location-routing-options) to configure priority-based failover and latency adjustments.

### Domain Name Validation

Domain names must conform to standard DNS naming rules and use a valid TLD. The domain name validation follows standard DNS domain name rules.

## Default Domain Names

If a domain is not associated with a [GVC](/reference/gvc), the following default endpoints are available to [workloads](/concepts/workload):

* Canonical endpoints (Global): `cpln.app`
* Individual location endpoints: `controlplane.us`

## Configure a Domain

See the [Configure a Domain](/guides/configure-domain) guide for setup instructions.

## Domain Configuration Example

The following example demonstrates a complete domain configuration:

```yaml theme={null}
kind: domain
name: my-domain
spec:
  dnsMode: cname # or "ns"
  certChallengeType: http01 # or "dns01"
  gvcLink: //gvc/my-gvc
  ports:
    - number: 443
      protocol: http2
      tls:
        minProtocolVersion: TLSV1_2
        cipherSuites:
          - ECDHE-ECDSA-AES256-GCM-SHA384
          - ECDHE-RSA-AES256-GCM-SHA384
        clientCertificate:
          secretLink: //secret/client-ca-cert
        serverCertificate:
          secretLink: //secret/server-cert
      cors:
        allowCredentials: true
        maxAge: 24h
        allowOrigins:
          - exact: https://example.com
          - regex: "https://.*\\.example\\.com"
        allowMethods:
          - GET
          - POST
          - PUT
          - DELETE
        allowHeaders:
          - Authorization
          - Content-Type
        exposeHeaders:
          - X-Custom-Header
      routes:
        - prefix: /api/
          replacePrefix: /v2/api/
          port: 443
          workloadLink: //gvc/my-gvc/workload/api-service
          headers:
            request:
              set:
                X-Custom-Header: "value"
                X-Client-IP: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
        - prefix: /web
          port: 3000
          workloadLink: //gvc/my-gvc/workload/web-service
          canaries:
            - workloadLink: //gvc/my-gvc/workload/web-service-v2
              weight: 20
        - prefix: /
          port: 8080
          workloadLink: //gvc/my-gvc/workload/default-service
          mirror:
            - workloadLink: //gvc/my-gvc/workload/mirror-service
              percent: 50
```

## Domain Verification

An apex domain, also known as a root domain, refers to a domain name that does not have any subdomain prefix (e.g., **example.com**).

If you want to use subdomains configured in NS mode, you must create and verify the apex domain in the org.
Even if the apex domain is not used by workloads, it must still be verified before subdomains can be created.

If multiple [orgs](/reference/org) create subdomains using the same apex domain, apex domain verification only needs to be performed in one of the orgs. Subdomains in orgs that do not have the apex domain require a TXT record to be added to DNS for verification.

The verification TXT record can be named `_cpln.<domain>` or `_verify.<domain>` and must have the value of the org name or org id.

<Note>When creating domains with the CLI, the operation fails if the required TXT and CNAME records are missing from your DNS. The error message prints the exact records that must be added; update your DNS with those values and rerun the command.</Note>

<Tip>As a best practice, create the apex domain in the org designated for your production environment.</Tip>

## Hostname Behavior

The `Host` header forwarded to the target workload depends on both the workload type and the domain used for the request.

For **serverless** workloads, even if the request was served using a custom domain, the `Host` header will be the canonical endpoint of the workload.

For **standard** or **stateful** workloads, the `Host` header will be the domain name used for the request.

Whenever the `Host` header is manipulated, the `X-Forwarded-Host` header will be appended with the original `Host` from the request.

## Routing Modes

Control Plane provides two routing modes for directing requests to your domain:

1. [Path-based routing](#path-based-routing)
2. [Subdomain-based routing](#subdomain-based-routing)

### Path-Based Routing

Path-based routing allows requests matching a specific path prefix to be routed to a specific workload. Multiple paths can be defined, but at least one path must be defined.

This is accomplished by adding a **CNAME** record to DNS and configuring the domain with `dnsMode: cname`.

Advantages of using path-based routing:

* You maintain full control of DNS for the domain.
* CDN / WAF compatible.

**Example URL endpoints:**

* If the domain `sub.example.com` is configured to point to the GVC that contains `workload_one` and `workload_two`, the path `workload_one` can route requests to `workload_one`, and the path `workload_two` can route requests to `workload_two`.
  * **[https://sub.example.com/workload\_one](https://sub.example.com/workload_one)**
  * **[https://sub.example.com/workload\_two](https://sub.example.com/workload_two)**

<Note>All path prefix values must be unique and there must be at least one path defined. Routes are automatically sorted by prefix length (longest first), then by host prefix length, then by trailing slash preference.</Note>

#### Path Prefix Replacement

The `replacePrefix` property allows a path prefix to be replaced when forwarding the request to the [workload](/concepts/workload).

**For example:** A request to the URL `https://sub.example.com/users/` can have the path prefix `/users/` replaced with the path prefix `/v2/users/`
when forwarding the request internally to the target [workload](/concepts/workload).

<Note>This does not work for regex-based paths.</Note>

#### Root Path Prefix

The `/` path will match any unmatched path prefixes for the subdomain.

#### Path Order

The order of the path prefix list is adjustable. When a request to the domain is received, the first match will be processed.

<Note>
  When combining the `/` path prefix with other path prefixes, the `/` path will automatically be placed last in the list because it matches
  all requests.
</Note>

#### Port Selection

The `port` property allows each route to forward traffic to a specific port exposed by the running workload.

For **serverless** workloads, assigning the port is optional since only one port can serve traffic.

For **standard** and **stateful** workloads that serve traffic on multiple ports, specific ports can be assigned on a route. If no port is assigned, external requests will be routed to the first port in the container's port list (in declaration order).

#### Replica Selection

The `replica` property allows **stateful** workloads with replicaDirect enabled to specify a replica number to route traffic directly to a specific replica. The replica number must be an integer greater than or equal to 0.

If no replica is specified, traffic will be routed to all replicas of the workload.

#### Header Operations

The `headers` property allows routes to modify HTTP headers for all requests processed by that route. Header operations allow you to set or override headers before forwarding requests to the workload.

**Supported Operations:**

* **`set`**: Sets or overrides headers for all HTTP requests processed by this route

**Header Value Wildcards:**
Header values support the following wildcards:

* `%REQUESTED_SERVER_NAME%`: The server name requested by the client
* `%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%`: The client IP address without port
* `%START_TIME%`: The request start time

**Example:**

```yaml theme={null}
headers:
  request:
    set:
      X-Custom-Header: "value"
      X-Client-IP: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
      X-Server-Name: "%REQUESTED_SERVER_NAME%"
```

<Note>
  When a domain is serving path-based requests, the [domain port protocol](#protocol) must be compatible with the selected protocol of the
  port configured on the container. For example, HTTP2 is compatible with HTTP2 and gRPC, HTTP is compatible with HTTP, and so on.
</Note>

#### Mirror Routing

The `mirror` property allows a route to be configured to mirror requests to another workload.

**For example:** A request to the URL `https://sub.example.com/` can be mirrored to the workload `api-service-v2` 50% of the time.
This is commonly used for testing new workload versions before promoting them to production traffic.

An optional `port` property can be added to the mirror configuration to specify which port the mirrored request should be sent to on the target workload.
If not specified, it defaults to the first listed port on the target workload.

**Example:**

```yaml theme={null}
routes:
  - prefix: /api
    workloadLink: //gvc/my-gvc/workload/api-service
    mirror:
      - workloadLink: //gvc/my-gvc/workload/api-service-v2
        percent: 50
      - workloadLink: //gvc/my-gvc/workload/api-service-v3
        percent: 25
        port: 8081
```

<Note>
  The mirrored workload must be in the same GVC as the main workload. If you need to mirror to a workload in a different GVC, contact support.
</Note>

#### Canary Routing

The `canaries` property splits traffic for a route across one or more additional workloads by weight. This is commonly used to gradually shift production traffic onto a new workload version, or to perform a blue/green cutover.

Each canary entry requires a `workloadLink` and a `weight` (an integer between 1 and 100). An optional `port` specifies which port the canary traffic is sent to on the target workload; if not specified, it defaults to the first configured port on that workload.

The combined weight of all canaries on a route must not exceed 100. The remaining weight is sent to the route's primary workload. A combined weight of 100 sends no traffic to the primary workload, which performs a full blue/green cutover.

**For example:** the route below sends 25% of traffic to `api-service-v2`, 10% to `api-service-v3`, and the remaining 65% to the primary workload `api-service`.

**Example:**

```yaml theme={null}
routes:
  - prefix: /api
    workloadLink: //gvc/my-gvc/workload/api-service
    canaries:
      - workloadLink: //gvc/my-gvc/workload/api-service-v2
        weight: 25
      - workloadLink: //gvc/my-gvc/workload/api-service-v3
        weight: 10
        port: 8081
```

If a canary's workload does not exist or is not deployed in a given [location](/reference/location), the canary is omitted in that location and its weight is returned to the primary workload.

<Note>
  Canary workloads must be in the same GVC as the route's primary workload. Canaries are supported only on `http` and `http2` ports, and are not supported when the route's primary workload or a canary workload is **serverless**.
</Note>

### Regex-Based Routing

Instead of specifying routes based on a path prefix, paths can be specified using [regex](https://github.com/google/re2/wiki/Syntax).

**For example:** A path regex can be specified as `/user/.*/profile` to match routes like `/user/bob/profile` or `/user/mary/profile`.

<Note>If at least one regex path is found, routes will not be sorted. You must specify either a prefix or regex for each route, but not both.</Note>

### Subdomain-Based Routing

Subdomain-based routing maps a domain to all workloads within a [GVC](/reference/gvc).

This works in either [DNS mode](#dns-modes). In **NS mode** (`dnsMode: ns`), add **NS** records that delegate DNS to Control Plane for this domain **only**, and Control Plane creates every subdomain record automatically. In **CNAME mode** (`dnsMode: cname` with a `gvcLink`), you create one **CNAME** record per workload — see [Subdomain-Based Routing in CNAME Mode](#cname-mode-dnsmode-cname).

Advantages of using subdomain-based routing:

* Best choice when a unique DNS subdomain is required for each workload.
* One-time configuration.
* Works for all current and future workloads in a GVC.

**Example URL endpoints:**

* If the domain `sub.example.com` is configured for the GVC that contains workloads named `workload_one` and `workload_two`, Control Plane will create
  the following subdomains and route requests to the respective workloads:
  * **[https://workload\_one.sub.example.com](https://workload_one.sub.example.com)**
  * **[https://workload\_two.sub.example.com](https://workload_two.sub.example.com)**

## DNS Modes

Control Plane supports two DNS modes for domain configuration:

### CNAME Mode (`dnsMode: cname`)

In CNAME mode, Control Plane will configure workloads to accept traffic for the domain but will not manage DNS records for the domain. Users configure CNAME records in their DNS provider that point to the canonical workload endpoint.

**Certificate Challenge Types:**

* `certChallengeType: http01`: Uses HTTP-01 challenge for certificate validation
* `certChallengeType: dns01`: Uses DNS-01 challenge for certificate validation

**Subdomain-Based Routing in CNAME Mode**

When a `gvcLink` is configured, each workload in the GVC is served at `<workload>.<domain>`. Create one **CNAME** record per workload pointing `<workload>.<domain>` to `<gvcAlias>.cpln.app`. The exact records to create are listed in the domain's [`status.dnsConfig`](#dns-configuration-records).

Certificate handling depends on `certChallengeType`:

* `dns01`: Control Plane issues a **wildcard** certificate covering all subdomains. Also create the `_acme-challenge` CNAME record shown in `status.dnsConfig` to delegate the challenge to Control Plane.
* `http01` (or unset): Control Plane does not issue a certificate for subdomain-based routing — configure a [custom server certificate](#custom-server-certificate) on every port that enables TLS.

**Constraints:**

* A CNAME domain cannot be created as a subdomain of a domain that is already configured in NS mode.

### NS Mode (`dnsMode: ns`)

In NS mode, Control Plane manages subdomains and automatically creates the required DNS records. End users configure an NS record to forward DNS requests to the Control Plane managed DNS servers.

<Note>HTTP-01 challenge type is not supported for NS mode domains.</Note>

## Certificate Challenge Type

The `certChallengeType` property controls both the certificate validation method and whether a wildcard certificate is generated:

* **`dns01`**: Uses DNS-01 challenge and generates a wildcard certificate
* **`http01`**: Uses HTTP-01 challenge and generates a standard certificate for just the domain name (not supported for NS mode)
* **unset**: Defaults to wildcard certificate for NS domains, standard certificate for CNAME domains

## Apex Domain Considerations

* An apex domain (e.g., **example.com**) can serve requests to workloads using
  either [path-based](#path-based-routing) or [subdomain-based](#subdomain-based-routing) routing.

* If subdomain-based routing is desired, set `certChallengeType: dns01` for a Control Plane-managed wildcard certificate, or configure a [custom server certificate](#custom-server-certificate) and use `http01`.

* If your DNS provider does not allow apex domains to point to a CNAME record, a service such as [CloudFront](https://docs.aws.amazon.com/cloudfront/index.html) or [Cloudflare](https://cloudflare.com) must be used to proxy the apex domain to Control Plane.

* Apex domains can only use CNAME mode (`dnsMode: cname`).

<Tip>
  These DNS providers **do not** allow apex domains to have a CNAME record:

  * GoDaddy
  * Route53
</Tip>

## Internal Domains

A domain whose name ends in `.internal` (for example, `example.internal`) is a private domain. Control Plane configures its workloads to accept and route traffic for the domain but does **not** manage or publish any public DNS for it — you are responsible for resolving the domain in your own environment.

**Resolution:** Point your own (private or split-horizon) DNS at the Control Plane endpoint with a CNAME record. On [BYOK](/byok) locations, the CNAME can resolve to a private address if you prefer to keep traffic off the public internet.

**Constraints:**

* Only CNAME mode is supported (`dnsMode: cname`, which is also the default).
* Subdomain-based routing (`gvcLink`) is not supported. Route to workloads using [path-based](#path-based-routing) or [regex-based](#regex-based-routing) routes.
* `certChallengeType` is not supported. Control Plane cannot issue a certificate for a private domain, so you must supply your own via `tls.serverCertificate.secretLink` on every port that enables TLS.
* An apex `.internal` domain and all of its subdomains can be used by only one Org.

**Example:**

```yaml YAML theme={null}
kind: domain
name: example.internal
description: example.internal
spec:
  dnsMode: cname
  ports:
    - number: 443
      tls:
        serverCertificate:
          secretLink: //secret/TLS_SECRET
      routes:
        - prefix: /
          workloadLink: //gvc/GVC_NAME/workload/WORKLOAD_NAME
```

## Port Configuration

In the Console UI, the port configuration section is available when editing a domain in `Advanced Mode`.

### External Port

The `number` property specifies the external port number. Typically, TLS requests to a configured domain are served on the standard TLS port 443.

**Default Configuration:**

* Port number: `443` (default)
* Protocol: `http2` (default)

See the [dedicated load balancer](#dedicated-load-balancer-options) section for the external ports that can be used when dedicated load balancing is enabled.

### Protocol

The `protocol` property specifies the protocol used for the port. The following protocols are supported:

1. **`http2`** (default)
2. **`http`**
3. **`tcp`** (when using a [dedicated load balancer](#dedicated-load-balancer-options))

### TLS Settings

The default TLS protocol version is **`minProtocolVersion: TLSV1_2`**. The minimum TLS protocol version is **`TLSV1_0`**.

The minimum TLS version should be configured as high as compatibility requirements allow, with a maximum supported value of **`TLSV1_3`**. All modern browsers support the default of **`TLSV1_2`**.

Supported TLS protocol versions:

* **`TLSV1_3`** (TLS 1.3)
* **`TLSV1_2`** (TLS 1.2) - Default
* **`TLSV1_1`** (TLS 1.1)
* **`TLSV1_0`** (TLS 1.0)

#### Cipher Suites

The `cipherSuites` property configures the allowed cipher suites for TLS connections. The following cipher suites are added by default and can be removed or re-added:

1. ECDHE-ECDSA-AES256-GCM-SHA384
2. ECDHE-ECDSA-CHACHA20-POLY1305
3. ECDHE-ECDSA-AES128-GCM-SHA256
4. ECDHE-RSA-AES256-GCM-SHA384
5. ECDHE-RSA-CHACHA20-POLY1305
6. ECDHE-RSA-AES128-GCM-SHA256
7. AES256-GCM-SHA384
8. AES128-GCM-SHA256

Additional ciphers that can be added:

1. DES-CBC3-SHA
2. ECDHE-RSA-AES128-SHA
3. ECDHE-RSA-AES256-SHA
4. AES128-SHA
5. AES256-SHA

If you need additional cipher suites, contact support on Slack or email [support@controlplane.com](mailto:support@controlplane.com).

<Tip>
  If there is an attempt to disable the TLS settings on a domain, it will always revert to the default configuration unless the domain is using a non-standard port and a non-HTTP protocol (e.g., using TCP with a [dedicated load balancer](#dedicated-load-balancer-options)).
</Tip>

#### Client Certificate Forwarding

The `clientCertificate` property configures client certificate forwarding for TLS connections. Client certificates included in a request to a domain can be configured to be forwarded to the destination [workload](/concepts/workload).

The `x-forwarded-client-cert` (XFCC) HTTP header will contain the client certificate details.

The certificate authority PEM, stored as a [secret](/reference/secret) of type `keypair`, can be associated with the domain through the `secretLink` property and used to verify the authority of the client certificate. The secret must contain a client certificate authority certificate in PEM format used to verify requests that include client certificates. The key subject must match the domain and the key usage properties must be configured for client certificate authorization.

If a certificate authority PEM is not associated with a domain, no verification is performed.

By default, supplying a client certificate is optional — a request without one is still served, and any certificate presented is forwarded in the XFCC header. To **require** a valid client certificate, set the [`cpln/clientCertificateValidation`](#special-tags) tag to `enabled` on the domain. Control Plane then verifies each client certificate against the certificate authority configured in `clientCertificate.secretLink` and rejects any connection that does not present a valid, trusted certificate. A `clientCertificate.secretLink` must be configured for this to take effect.

CRL lists are not verified, but they can be checked by the [workload](/concepts/workload) by keeping a list of allowed or revoked client certificate hashes. When a request is received by the [workload](/concepts/workload), the hash field in the XFCC header can be checked against the allowed or revoked list and an allow or deny decision can be made.

To generate the certificate hash, execute the following command:

```bash theme={null}
openssl x509 -noout -fingerprint -sha256 -inform pem -in MyClientCert.pem | awk -F= '{print $2}' | tr -d ':' | tr '[:upper:]' '[:lower:]'`
```

<Tip>
  Verify that the CA certificate includes the correct x509 key usage fields (critical, digitalSignature, keyEncipherment) + extendedKeyUsage = serverAuth and that the CN of the client certificate matches the domain name selected.
</Tip>

#### Custom Server Certificate

The `serverCertificate` property configures a custom server certificate for the domain. A custom server certificate can be assigned to a domain by selecting an existing [secret](/reference/secret) of type `keypair` through the `secretLink` property.

This certificate is used when configuring:

1. An apex domain that is configured with [subdomain-based routing](#subdomain-based-routing).
2. A domain that is fronted by a proxy (such as Cloudflare).
3. A domain that prefers not to use a certificate generated by Control Plane.

The secret must contain PEM-encoded content and be of type `keypair`. When the port number is 443 and this is not supplied, a certificate is provisioned automatically.

<Tip>
  If a custom server certificate is configured on a domain, it is the responsibility of the user to ensure that the certificate is valid and not expired.
</Tip>

### CORS Settings

**CORS** stands for **Cross-Origin Resource Sharing**. It is a mechanism that allows web browsers to securely make requests to a different domain or origin than the one from which the web page was served.

By default, web browsers enforce a policy called the Same-Origin Policy, which restricts JavaScript code running in a web page from making requests to a different domain. CORS provides a way to relax this policy and enable cross-origin requests, but in a controlled and secure manner.

When a web page makes a cross-origin request, the server needs to include specific CORS headers in its response to indicate which origins are allowed to access its resources. These headers include information such as the allowed methods, allowed headers, and whether credentials (such as cookies or HTTP authentication) can be included in the request.

CORS helps to prevent malicious scripts from performing unauthorized actions on behalf of a user, while still allowing legitimate cross-origin requests between trusted domains. It plays a crucial role in enabling modern web applications to interact with APIs and services hosted on different domains.

The domain can enforce CORS settings, though the application being served can also configure these settings.

The following CORS properties can be configured:

* **`allowCredentials`**
  * Determines whether the client-side code (typically running in a web browser) is allowed to include credentials (such as cookies, HTTP authentication, or client-side SSL certificates) in cross-origin requests.
* **`maxAge`**
  * Maximum amount of time that a preflight request result can be cached by the client browser. Must match the regex pattern: `^[\d\.]+[wdhm]+$` (e.g., "24h", "1d", "3600s")
* **`allowOrigins`**
  * Determines which origins are allowed to access a particular resource on a server from a web browser.
    * Each origin can be specified as either:
      * `exact`: A specific origin string (e.g., `https://example.com`)
      * `regex`: A regex pattern to match origins
    * Examples:
      * Wildcard Origin: `*`
      * Specific Origin: `https://example.com`
* **`allowMethods`**
  * Specifies the HTTP methods (such as GET, POST, PUT, DELETE, etc.) that are allowed for a cross-origin request to a specific resource.
* **`allowHeaders`**
  * Specifies the custom HTTP headers that are allowed in a cross-origin request to a specific resource. Header names are automatically converted to lowercase.
* **`exposeHeaders`**
  * Specifies which response headers are exposed to the client-side code (typically running in a web browser) in a cross-origin request. Header names are automatically converted to lowercase.

## Dedicated Load Balancer Options

When a GVC has the dedicated load balancer option enabled, additional settings are available for any domains using it.

See the [GVC dedicated load balancer](/reference/gvc#dedicated-load-balancer) reference page for more information.

### NumTrustedProxies

The `numTrustedProxies` property gives control over the number of trusted proxies that are configured in front of Control Plane.

Changing this value controls the source IP address used for request logging, firewall settings, and for the X-Envoy-External-Address header passed to workloads.

If set to 1, then the last address in an existing X-Forwarded-For header will be used in place of the source client IP address.

If set to 2, then the second-to-last address in an existing X-Forwarded-For header will be used in place of the source client IP address.

When set to 2, any request where the XFF header does not have at least two addresses or does not exist uses the source client IP address instead.

### Custom Ports

Any custom port number can be used with the exception of the following excluded ports:

* 8012
* 8022
* 9090
* 9091
* 15000
* 15001
* 15006
* 15020
* 15021
* 15090
* 41000

Contact support on Slack or email [support@controlplane.com](mailto:support@controlplane.com) if you need to use a port that is not listed here.

### Dedicated Load Balancer Configuration Options

When a dedicated load balancer is enabled on a GVC, domains that serve workloads within that GVC can use the following options:

1. [`acceptAllHosts`](#acceptallhosts)
2. [`acceptAllSubdomains`](#acceptallsubdomains)
3. [`hostPrefix`](#hostprefix)
4. [`hostRegex`](#hostregex)

#### acceptAllHosts

The `acceptAllHosts` property configures the domain to allow all traffic (i.e. wildcard support) to the configured workloads, regardless of the Host header or SNI in the request. At most one domain should be configured with this setting for a single GVC. If there are multiple, requests will only route for one of the domains.

#### acceptAllSubdomains

The `acceptAllSubdomains` property configures the domain to allow all traffic to `*.${domain}` for the domain. No other domains in the same GVC should be configured for any subdomains of this domain because their routing rules will be ignored.

#### hostPrefix

For domains using [path-based routing](#path-based-routing), the `hostPrefix` property will be enabled and can be used for each path when the domain has the `acceptAllHosts` or `acceptAllSubdomains` property enabled.

This option allows forwarding traffic for different host header prefixes to specific workloads.

The host prefix must match the regex pattern: `^[0-9a-zA-Z-\._]*$`

<Note>You cannot use both `hostPrefix` and `hostRegex` on the same route.</Note>

#### hostRegex

For domains using [path-based routing](#path-based-routing), the `hostRegex` property will be enabled and can be used for each path when the domain has the `acceptAllHosts` or `acceptAllSubdomains` property enabled.

This option allows forwarding traffic for different host headers to specific workloads by regular expression.

<Note>You cannot use both `hostPrefix` and `hostRegex` on the same route.</Note>

## Replica Direct Routing

Domains can be configured, in conjunction with a `stateful` workload, for replica-direct endpoints.
These endpoints route traffic directly to a specific workload replica.

<Note>Control Plane also provides built-in per-replica endpoints under `controlplane.us` when `spec.loadBalancer.replicaDirect` is enabled on the workload — no custom domain required. See [Replica-Direct Endpoints](/reference/workload/general#replica-direct-endpoints) in the workload reference.</Note>

### Configuration

To configure a domain for replica-direct routing, you need to set the `workloadLink` property on the domain to the link of the workload.
The domain must also use `dnsMode: cname` with the `dns01` certificate challenge type.
The domain must define at least one port, and each port must contain exactly one route.

**Validation Rules:**

* When `workloadLink` is configured, `certChallengeType` cannot be `http01`
* Every port must have exactly one route
* All routes must reference the same workload as the domain's `workloadLink`
* The domain cannot have both `gvcLink` and `workloadLink` configured

#### Example

```yaml theme={null}
kind: domain
name: my-domain
spec:
  certChallengeType: dns01
  dnsMode: cname
  workloadLink: //gvc/my-gvc/workload/my-workload
  ports:
    - number: 443
      protocol: http2
      routes:
        - port: 8080
          prefix: /
          workloadLink: //gvc/my-gvc/workload/my-workload # must match the top-level workloadLink
```

### DNS names

When a domain is configured for replica-direct routing, the DNS names for each replica will be:

`<workload-name>-<replica>-<location>.<domain>`

#### Example

`my-workload-0-aws-us-west-2.example.com`

## DNS records

Replica direct domains require specific DNS records in order to work correctly.

1. One **CNAME** record to redirect the `dns01` certificate challenge to Control Plane
   | Host             | TTL | Type  | Value                     |
   | :--------------- | :-- | :---- | :------------------------ |
   | \_acme-challenge | 300 | CNAME | \_acme-challenge.cpln.app |
2. A **CNAME** record for each replica of the workload to redirect traffic to Control Plane
   | Host                        | TTL | Type  | Value                                                   |
   | :-------------------------- | :-- | :---- | :------------------------------------------------------ |
   | my-workload-0-aws-us-west-2 | 300 | CNAME | my-workload-\<gvcAlias>-0.aws-us-west-2.controlplane.us |
   | my-workload-1-aws-us-west-2 | 300 | CNAME | my-workload-\<gvcAlias>-1.aws-us-west-2.controlplane.us |
   | my-workload-2-aws-us-west-2 | 300 | CNAME | my-workload-\<gvcAlias>-2.aws-us-west-2.controlplane.us |

## Permissions

The permissions below are used to define [policies](/reference/policy) together with one or more of the four [principal types](/concepts/access-control):

| Permission | Description                                        | Implies                                 |
| :--------- | :------------------------------------------------- | :-------------------------------------- |
| create     | Create new domain                                  |                                         |
| delete     | Delete a domain                                    |                                         |
| edit       | Modify existing domains (only tags can be changed) | view, use                               |
| manage     | Full access                                        | create, delete, edit, manage, use, view |
| use        | Allow a principal to use this domain               | view                                    |
| view       | Read-only access                                   |                                         |

## Access Report

Displays the permissions granted to principals for the domain.

## Domain Status

The domain status field indicates the current state of the domain configuration and deployment.

**Supported Status Values:**

* `initializing`: Domain is being set up
* `ready`: Domain is fully configured
* `pendingDnsConfig`: Waiting for DNS configuration to be verified, this may happen if DNS is updated but has not yet propagated
* `pendingCertificate`: Waiting for certificate provisioning
* `usedByGvc`: Domain is being used by a GVC with legacy configuration
* `warning`: Domain has configuration warnings
* `errored`: Domain configuration has errors

**Status Fields:**

* `endpoints`: Array of endpoint URLs and their associated workload links
* `warning`: Warning message describing any issues
* `locations`: Array of location-specific certificate status information
* `fingerprint`: Unique identifier for the domain configuration
* `dnsConfig`: Array of DNS configuration records required for the domain

### DNS Configuration Records

The `dnsConfig` field contains the DNS records that must be configured for the domain to function properly.

**DNS Record Structure:**

* `type`: DNS record type (e.g., "CNAME", "NS", "TXT")
* `ttl`: Time-to-live value (positive integer)
* `host`: Hostname for the DNS record
* `value`: DNS record value

**Example DNS Configuration:**

```json theme={null}
{
  "dnsConfig": [
    {
      "type": "CNAME",
      "ttl": 300,
      "host": "sub.example.com",
      "value": "cpln.app"
    },
    {
      "type": "TXT",
      "ttl": 300,
      "host": "_acme-challenge.sub.example.com",
      "value": "challenge-token-value"
    }
  ]
}
```

## Special Tags

Control Plane supports special tags prefixed with `cpln/` that modify domain behavior.

| Tag                                | Value     | Description                                                                                                                                                                                                                                                                                                        |
| :--------------------------------- | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cpln/skipDNSCheck`                | `true`    | Skip DNS validation checks during domain configuration. Useful when DNS propagation is delayed or when using external DNS management.                                                                                                                                                                              |
| `cpln/wildcard`                    | `true`    | Enable wildcard certificate for custom ingress domains. Only applicable for domains with custom ingress enabled.                                                                                                                                                                                                   |
| `cpln/clientCertificateValidation` | `enabled` | Require a valid client certificate (mTLS) on the domain. Connections must present a certificate that is verified against the CA in `tls.clientCertificate.secretLink`; requests without a valid, trusted certificate are rejected. When unset, client certificates are optional and accepted without verification. |

## CLI

To view the CLI documentation for domains, see the [Domain CLI reference](/cli-reference/commands/domain).

## Domain Certificate Management

Control Plane automatically handles the creation and renewal of TLS certificates for domains.
This ensures that your domains remain secured with up-to-date certificates without requiring manual intervention.
The certificates issued are valid for 90 days and refresh every 60 days.

### Certificate Creation and Renewal Process

Control Plane uses the Let's Encrypt [ACME](https://letsencrypt.org/docs/acme-protocol-updates/) protocol to automatically create and renew certificates for domains.
Any certificates issued by Let's Encrypt are published to the [Certificate Transparency](https://www.certificate-transparency.org/) logs and discoverable by the public.
If you prefer to use a different certificate authority, you can configure a [custom server certificate](#custom-server-certificate) on the domain.

* **NS domains**: Control Plane uses the Let's Encrypt [DNS-01](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) verification process.
  This involves creating a DNS TXT record at `_acme-challenge.${domain}` to prove domain ownership, allowing Let's Encrypt to issue a certificate.
  Control Plane manages the creation of the DNS record, and the certificate is issued by Let's Encrypt.
  See [Certificate Challenge Type](#certificate-challenge-type) for details on wildcard vs standard certificate behavior.

* **CNAME domains**: Control Plane uses the Let's Encrypt [HTTP-01](https://letsencrypt.org/docs/challenge-types/#http-01-challenge) verification process.
  This involves serving a specific HTTP resource to prove domain ownership at `http://${domain}/.well-known/acme-challenge/`, allowing Let's Encrypt to issue a certificate.
  Control Plane configures the domain with a redirect to our HTTP-01 solver, and then the certificate is issued by Let's Encrypt.
  Wildcard certificates cannot be created using the HTTP-01 verification process. To attach a CNAME domain to a GVC for [subdomain-based routing](#subdomain-based-routing) (`gvcLink`) with a Control Plane-managed certificate, set `certChallengeType: dns01` so a wildcard certificate is issued via [DNS-01](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) — this requires adding the `_acme-challenge` CNAME record shown in `status.dnsConfig`. Otherwise, configure a custom server certificate.

<Note>
  If you choose to use a custom server certificate, ensure you monitor its expiration and renew it as necessary to avoid service
  disruptions.
</Note>

## Domain Validation Rules

The following validation rules apply to domain configuration:

### Route Limits

* Maximum of 150 routes per domain
* Routes must be unique (no duplicate prefix/regex and host combinations)
* All routes must reference workloads within the same GVC

### Port Configuration Limits

* Maximum of 10 ports per domain
* Each port can have a maximum of 150 routes

### DNS Mode Constraints

* Apex domains can only use CNAME mode (`dnsMode: cname`)
* NS mode requires DNS-01 certificate challenge type
* CNAME mode with subdomain routing requires custom server certificate

### Workload Link Constraints

* Cannot configure both `gvcLink` and `workloadLink` on the same domain
* When `workloadLink` is configured:
  * Cannot use HTTP-01 certificate challenge type
  * Every port must have exactly one route
  * All routes must reference the same workload

### Wildcard Support Constraints

* Cannot enable both `acceptAllHosts` and `acceptAllSubdomains` simultaneously
* `hostPrefix` and `hostRegex` can only be used when `acceptAllHosts` or `acceptAllSubdomains` is enabled

## Domain Configuration Errors

During the domain configuration process, several errors might occur.
These errors are viewable in the UI/API as a result of the domain status being modified and are also available in Grafana as the `domain_warning` metric.
A default alert is also created to notify the default contact when any domain is in a warning state.
Below are some common issues and their implications:

### Common Errors

* **Certificate Renewal Blocked**: The domain's certificate renewal is blocked.
  This can occur if the domain is using a CNAME DNS mode and the renewal is blocked due to firewall or external CDN/WAF configurations.
  To test if the request from Let's Encrypt is being blocked, you can use the following curl command:

  ```bash theme={null}
  curl -v https://${domain}/.well-known/acme-challenge/
  ```

If the request is blocked, you will see an error message in the response, the request will hang, or the `location:` in the response will not be targeted to `http01-solver.cpln.io`.

Example of an **invalid** redirect to HTTPS:

```bash theme={null}
< HTTP/1.1 301 Moved Permanently
< location: https://${domain}/.well-known/acme-challenge/test
```

Example of a **valid** redirect to the Control Plane solver:

```bash theme={null}
< HTTP/1.1 301 Moved Permanently
< location: http://http01-solver.cpln.io/.well-known/acme-challenge/test
```

As another test, you can run the following curl which includes the `-L` flag to follow the redirect:

```bash theme={null}
curl -L https://${domain}/.well-known/acme-challenge/
```

The response should be an error message like the following, indicating that the request made it to our certificate solver:

```bash theme={null}
{"message":"error downloading file: NoSuchKey: The specified key does not exist.\n\tstatus code: 404, request id: REDACTED, host id: REDACTED"}
```

Any other response indicates that the request was blocked.

* **Domain Used by GVC**: This domain is currently in use by a GVC using the legacy configuration of the GVC `spec.domain` property.
  The domain configuration will be ignored until no GVC is using it.
  This results in a `usedByGvc` status with a warning message indicating the domain's current usage.

* **Invalid GVC**: At least one of the configured routes does not map to a valid GVC.
  Check the routes and verify that the GVC and workloads targeted by the domain or routes exist.

* **No Valid Routes Configured**: No valid routes are configured for the domain.
  Routes need to be added or updated for the domain to be usable.

* **Disallowed Port or Protocol**: A port other than 443 or 80 is used, or the protocol is set to TCP and the GVC assigned is not configured with a [dedicated load balancer](#dedicated-load-balancer-options).
  If you need to use a port other than 443 or 80, you can enable [dedicated load balancer](#dedicated-load-balancer-options) on the GVC.

* **Invalid Workload**: A route is not mapped to a valid workload and will not be included in the configuration.
  This requires updating the route to map to a valid workload or removing the route that is no longer needed.

* **HostPrefix Ignored**: If the GVC does not have [dedicated load balancer](#dedicated-load-balancer-options) enabled and the domain is not configured for wildcard support, any hostPrefix for a route is ignored.

### Logging and Monitoring

Errors and warnings are exposed through domain status fields and displayed in the UI.
A Grafana metric of `domain_warning` is updated for each domain.
An alarm is configured to notify the default contact using this metric when any domain is in a warning state.
