# Configure reverse proxy

This guide shows you how to configure a reverse proxy for the Tenzir Platform. The proxy terminates TLS and routes traffic to these four entry points:

1. **Tenzir UI**: The URL your browser connects to, e.g., `app.platform.example`. This serves the web frontend where you interact with the platform.
2. **Tenzir Gateway**: The URL nodes connect to, e.g., `nodes.platform.example`. Tenzir Nodes connect to this URL to establish long-running WebSocket connections.
3. **Blob Storage**: The URL where the platform’s S3-compatible blob storage is accessible, e.g., `downloads.platform.example`. When you click the *Download* button, the platform generates download links under this URL. When you drag files into the explorer window, the platform stores them here so that Tenzir Nodes can access them.
4. **Platform API**: The URL the Tenzir Platform CLI connects to, e.g., `api.platform.example`.

The typical setup for the Tenzir Platform uses a reverse proxy to terminate TLS connections and forward incoming traffic to the correct services. The choice of technology varies with your deployment scenario and ranges from an additional [Traefik](https://doc.traefik.io/traefik/getting-started/install-traefik/) container within the Docker Compose stack, over an nginx instance running on the same host, to global load balancing services offered by a commercial cloud provider.

In our example scenarios, set the following environment variables to configure these four endpoints:

```sh
# The domain under which the platform frontend is reachable.
# Must include the `http://` or `https://` scheme.
TENZIR_PLATFORM_UI_ENDPOINT=https://app.platform.example


# The endpoint to which Tenzir nodes should connect.
# Must include the `ws://` or `wss://` scheme.
TENZIR_PLATFORM_NODES_ENDPOINT=wss://nodes.platform.example


# The URL at which the platform's S3-compatible blob storage is accessible.
TENZIR_PLATFORM_DOWNLOADS_ENDPOINT=https://downloads.platform.example


# The URL at which the platform API is accessible.
TENZIR_PLATFORM_API_ENDPOINT=https://api.platform.example
```

## Native TLS

A reverse proxy typically runs on the same host as other platform containers and terminates TLS. When you can’t guarantee that the reverse proxy runs on the same host as other platform containers, or when you deploy the containers to different machines, enable native TLS support for individual platform containers.

### Obtaining Certificates

Purchase the domain name you want for the platform and use one of the globally trusted certificate authorities (CAs) to obtain a valid certificate. This approach provides the most straightforward and recommended certificate acquisition method.

If you run the platform in a private or air-gapped network, use methods like the DNS challenge offered by [Let’s Encrypt](https://letsencrypt.org/) and other providers to generate a certificate and transfer it to the target machine.

When you can’t use a globally trusted CA, use a corporate root CA instead. Naturally, certificates from this CA will only be trusted inside your organization or your Tenzir Platform setup.

If you don’t possess a corporate root CA, create a private CA for yourself. Signing and provisioning root certificates is a complex task, so we recommend using a tool like `trustme` for this purpose.

We provide a [sample script](https://github.com/tenzir/platform/tree/main/examples/native-tls) that shows how to create the necessary certificates for all components.

Certificate Validation Idiosyncrasies

Some libraries ignore the system-wide CA certificate store and use alternative, more strictly curated bundles. For example, Mozilla’s NSS root store is a popular choice. Additionally, the operating system’s default certificate bundles shipped within our Docker containers won’t trust private CAs by default. Therefore, when you use a private CA, perform the same configuration for corporate root CAs from a publicly trusted CA or your self-created private CA.

### Self-signed Certificates

Instead of creating a private CA, create a self-signed certificate that combines certificate and CA in a single file.

This approach simplifies setup and management compared to a private CA, but reduces security guarantees. For example, it nullifies several TLS security guarantees and provides only protection against passive eavesdropping.

Below we assume you store valid TLS certificates in files named `ssl/app-cert.pem`, `ssl/platform-cert.pem`, etc., where each file contains both the TLS certificate and private key. If you store the certificate and private key in separate files, mount both into the containers and adjust the environment variables to point towards the correct file.

When you use a private CA, store the public key of that CA in the file `ssl/ca.pem`.

#### Tenzir UI

To have the Tenzir UI serve its traffic using TLS, add the following environment variables and volumes to your `docker-compose.yaml`:

```yaml
services:
  app:
    environment:
      - TLS_CERTFILE=/ssl/app-cert.pem
      - TLS_KEYFILE=/ssl/app-cert.pem


    volumes:
      - ./ssl/app-cert.pem:/ssl/app-cert.pem
```

When you use a private CA, add the following configuration:

```yaml
services:
  app:
    environment:
      - NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt


    volumes:
      - ./ssl/ca.pem:/etc/ssl/certs/ca-certificates.crt
```

#### Tenzir Gateway

To enable TLS serving for the gateway, mount the certificate into the container and set the `TLS_CERTFILE` and `TLS_KEYFILE` environment variables:

```yaml
services:
  websocket-gateway:
    environment:
      - TLS_CERTFILE=/ssl/gateway-cert.pem
      - TLS_KEYFILE=/ssl/gateway-cert.pem
    volumes:
      - ./ssl/gateway-cert.pem:/ssl/gateway-cert.pem
```

When you use a private CA, add the following configuration:

```yaml
services:
  websocket-gateway:
    environment:
      - TLS_CAFILE=/ssl/ca.pem
    volumes:
      - ./ssl/ca.pem:/ssl/ca.pem
```

Browser certificate trust for direct gateway connections

When the browser connects directly to the gateway (the default when `TENZIR_PLATFORM_USE_INTERNAL_WS_PROXY` is `false`) and the gateway uses a self-signed certificate, the browser must explicitly trust that certificate. Because users do not navigate to the gateway port directly, the browser never shows its usual untrusted-certificate warning page. The only visible symptom is a vague message such as “Unable to fetch pipelines.” The actual cause appears only in the browser developer console, where it shows a failed connection to the gateway URL.

To resolve this, open the gateway URL directly in your browser (for example, `https://nodes.platform.example`) and accept the security exception. After accepting the certificate, reload the platform UI.

Alternatively, set `TENZIR_PLATFORM_USE_INTERNAL_WS_PROXY=true` to route gateway traffic through the UI backend. The browser then only needs to trust the UI certificate, not the gateway certificate.

#### Platform API

To enable TLS serving for the Platform API, mount the certificate into the container and set the `TLS_CERTFILE` and `TLS_KEYFILE` environment variables. This follows the same process as for the `websocket-gateway` container:

```yaml
services:
  platform:
    environment:
      - TLS_CERTFILE=/ssl/platform-cert.pem
      - TLS_KEYFILE=/ssl/platform-cert.pem
    volumes:
      - ./ssl/platform-cert.pem:/ssl/platform-cert.pem
```

When you use a private CA, add the following configuration:

```yaml
services:
  platform:
    environment:
      # 'requests' uses a baked-in CA bundle, so point it to our CA explicitly.
      - REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
      - SSL_CERT_FILE=/ssl/ca.pem
    volumes:
      - ./ssl/ca.pem:/etc/ssl/certs/ca-certificates.crt
```

### Example

Refer to our [native TLS example](https://github.com/tenzir/platform/tree/main/examples/native-tls) for a complete configuration example, including the native TLS setup for the default bundled database, S3 storage and IdP services.

## Node TLS Settings

Nodes connect to the platform using the Tenzir Gateway via a TLS connection. When using a custom certificate for the gateway, provide it to the node to successfully establish a connection.

Set the following option to point to a CA certificate file in PEM format without password protection:

```sh
TENZIR_PLATFORM_CACERT=/path/to/ca-certificate.pem
```

When using a self-signed TLS certificate, additionally disable TLS certificate validation:

```sh
TENZIR_PLATFORM_SKIP_PEER_VERIFICATION=true
```

TLS: Platform vs. pipeline

These settings apply only to the connection that the node establishes with the platform, not to any TLS connections that pipelines may create within the node.