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

# Public endpoints

> Give a service inside a sandbox a public address, with platform TLS or TLS passthrough.

This page describes how public endpoints work, how to declare one when you create a sandbox, and how to connect to it.

A public endpoint gives a service running inside a sandbox an address that clients can reach from the internet. You request one when you create the sandbox, and the platform provisions the routing, DNS, and network access for it. The address belongs to the sandbox for as long as the sandbox runs.

Endpoints come in two kinds, which differ in where TLS terminates:

* **HTTPS**: The platform terminates TLS at its edge with a certificate it provisions and renews, then forwards the request to your port as cleartext HTTP.
* **TLS passthrough**: The platform routes the connection to your port by [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) without decrypting it. Your workload terminates TLS and owns its own certificates.

Choose TLS passthrough when the workload must hold the private key itself: mutual TLS, a client that pins a certificate, or a protocol that isn't HTTP.

<Note>
  CoreWeave sandboxes are in public preview. For access, contact your CoreWeave account team, [CoreWeave Support](https://cloud.coreweave.com/contact), or email [support@coreweave.com](mailto:support@coreweave.com).
</Note>

## Compare the two kinds

|                       | HTTPS                                                      | TLS passthrough       |
| --------------------- | ---------------------------------------------------------- | --------------------- |
| Terminates TLS        | Platform edge                                              | Your workload         |
| Owns certificates     | Platform                                                   | You                   |
| Carries               | HTTP, WebSockets over HTTP Upgrade, and Server-Sent Events | Any protocol over TLS |
| `endpoint.kind`       | `HTTPS`                                                    | `TLS_PASSTHROUGH`     |
| `endpoint.auth`       | `OPEN` (required)                                          | Omit                  |
| Read the address from | `service_urls`                                             | `service_addresses`   |

<Warning>
  Both kinds are open to the internet. The platform does not authenticate callers, so the service behind the endpoint is responsible for its own access control.
</Warning>

## Declare an endpoint

Declare endpoints in the `services` list when you create the sandbox. Ports are fixed for the sandbox's lifetime, and no call exposes a port on a sandbox that is already running.

To give a service an endpoint, set `visibility=PUBLIC` and an `endpoint` value on it. A service without an `endpoint` value listens on its port inside the sandbox but gets no public address.

For an HTTPS endpoint, set `kind=EndpointKind.HTTPS` and `auth=EndpointAuth.OPEN`:

```python theme={"system"}
from cwsandbox import (
    Endpoint,
    EndpointAuth,
    EndpointKind,
    Sandbox,
    Service,
    ServiceVisibility,
)

sandbox = Sandbox.run(
    "python3", "-m", "http.server", "8080",
    container_image="python:3.11",
    services=[
        Service(
            port=8080,
            name="web",
            visibility=ServiceVisibility.PUBLIC,
            endpoint=Endpoint(kind=EndpointKind.HTTPS, auth=EndpointAuth.OPEN),
        ),
    ],
)
```

For a TLS passthrough endpoint, set `kind=EndpointKind.TLS_PASSTHROUGH` and leave `auth` unset. The command you run must terminate TLS on the port itself, because the platform forwards the connection without decrypting it:

```python theme={"system"}
from cwsandbox import (
    Endpoint,
    EndpointKind,
    Sandbox,
    Service,
    ServiceVisibility,
)

sandbox = Sandbox.run(
    "python3", "/srv/serve_tls.py",
    container_image="python:3.11",
    services=[
        Service(
            port=8443,
            name="tls",
            visibility=ServiceVisibility.PUBLIC,
            endpoint=Endpoint(kind=EndpointKind.TLS_PASSTHROUGH),
        ),
    ],
)
```

One sandbox can mix both kinds. The following rules apply to every `services` entry:

* **Ports must be unique**, and any name you set must be unique. Names map to Kubernetes container port names, which require uniqueness.
* **`visibility` must be `PUBLIC`** when `endpoint` is set, and must be left unset when it isn't. Visibility on its own doesn't create an endpoint or an address.
* **`protocol` must be `TCP` or unset.** The platform rejects `UDP` and `SCTP` endpoints.
* **Omit `auth` and `request_timeout_seconds` for TLS passthrough.** Pass `None` rather than `0`. A `0` counts as a set value, and the platform rejects the create call.
* **A platform limit caps how many services one sandbox declares.** Operators set the cap, and deployments commonly set it to five.

## Read the assigned address

The platform assigns the address. You can't choose the hostname or supply your own domain. Read it back from the sandbox rather than constructing it, because the DNS zone differs per cluster and isn't part of the API contract.

TLS passthrough addresses arrive on `service_addresses` as `host:port`, and HTTPS URLs arrive on `service_urls`. The two lists stay separate: A TLS endpoint never appears in `service_urls`.

```python theme={"system"}
for endpoint in sandbox.service_addresses:
    print(endpoint.port, endpoint.name, endpoint.address)
```

You should see output similar to the following:

```text theme={"system"}
8443 tls 8443-2f8d41b6-9c3e-4a17-b5d2-7e0a13c64f89.a1b2c3d4.ep2.cwsandbox.com:443
```

The advertised port is the platform's TLS listener port, not the port your process binds inside the sandbox. In this example, the workload listens on `8443` and clients connect to `443`.

The two kinds become readable at different points in the sandbox's startup:

* **A TLS passthrough address is assigned when the sandbox is created**, so it is on the create response and stays available while the sandbox is creating or running.
* **An HTTPS URL is empty until the sandbox reaches `RUNNING`** and its route has a hostname. Call `get_status()` in a loop until the URL appears or your own deadline passes.
* **Neither one means the application is serving.** The platform doesn't wait for your process to bind the port before reporting the sandbox as running, so retry your first connection.

The platform reports endpoints while a sandbox is creating or running, and clears them in every other state. A paused or completed sandbox has no reachable endpoint.

## Connect to a TLS passthrough endpoint

Because the platform doesn't decrypt the connection, the certificate a client receives is the one your workload presents. Two things follow for the client:

* **Send the endpoint host as the SNI server name.** The platform routes on SNI alone, so a connection that omits it, or sends a different name, doesn't reach your sandbox.
* **Trust the workload's certificate.** The endpoint hostname is platform-assigned, so a certificate you issue yourself doesn't match it unless you issue it for that hostname. Configure the client to trust your own certificate authority, or pin the certificate.

The following client sends the endpoint host as SNI while connecting to the advertised address. Replace `[ENDPOINT-ADDRESS]` with the address you read from `service_addresses`, and `[PATH-TO-CA-CERT]` with the path to the certificate authority that signed your workload's certificate:

```python theme={"system"}
import socket
import ssl

address = "[ENDPOINT-ADDRESS]"  # host:port from service_addresses
host, port = address.rsplit(":", 1)

context = ssl.create_default_context(cafile="[PATH-TO-CA-CERT]")

with socket.create_connection((host, int(port))) as sock:
    with context.wrap_socket(sock, server_hostname=host) as tls:
        print(tls.version(), tls.getpeercert()["subject"])
```

## Endpoint lifetime

An endpoint lives as long as the sandbox that owns it:

* **It's keyed to the sandbox, not to a Pod.** If the underlying Pod restarts, the address stays the same.
* **Deleting the sandbox removes the endpoint.** The address doesn't move to another sandbox, and a new sandbox gets a new address.
* **Nothing is reserved between sandboxes.** You can't hold a hostname for reuse.

## Troubleshoot create failures

If no runner in your fleet supports the endpoint kind you requested, the create call fails rather than starting a sandbox with the endpoint silently dropped.

| Reason                                              | Meaning                                                                                                                                                          |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CWSANDBOX_TLS_PASSTHROUGH_ENDPOINTS_NOT_SUPPORTED` | No runner you can reach is configured for TLS passthrough. Ask your administrator to enable it on a runner.                                                      |
| `CWSANDBOX_NO_SUITABLE_RUNNER`                      | The sandbox declared both endpoint kinds, and no runner supports both. The response's `unsupported_endpoint_kinds` metadata names the kinds that are missing.    |
| `CWSANDBOX_INVALID_REQUEST`                         | A `services` entry breaks one of the rules in [Declare an endpoint](#declare-an-endpoint), such as a duplicate port or `auth` set on a TLS passthrough endpoint. |
| `CWSANDBOX_NOT_IMPLEMENTED`                         | The request used a feature that isn't implemented, such as `auth=TOKEN`.                                                                                         |

## Related pages

* [Sandbox configuration](/products/sandboxes/client/guides/sandbox-configuration): resources, ports, secrets, and timeouts.
* [Sandbox architecture](/products/sandboxes/architecture): how runners, profiles, and the control plane interact.
* [Sandbox lifecycle](/products/sandboxes/client/guides/sandbox-lifecycle): the states a sandbox moves through.
