> For the complete documentation index, see [llms.txt](https://docs.catalyx.solutions/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.catalyx.solutions/catalyx-blockchain-manager/canton-network/version-2.0/installation-instructions-canton/platform-installation.md).

# Platform Installation

The `catalyx-canton` Helm chart installs three components — the operator, the API, and the console — plus the two custom resource definitions they depend on.

## Before you install

{% stepper %}
{% step %}
**Create the namespace**

By convention the platform runs in `catalyx-system`.

```bash
kubectl create namespace catalyx-system
```

{% endstep %}

{% step %}
**Create the identity provider secrets**

Two secrets are required. Both live in the release namespace.

```bash
# The operator's Keycloak admin client secret
kubectl create secret generic catalyx-operator-keycloak \
  --from-literal=admin-client-secret=<keycloak-admin-client-secret> \
  -n catalyx-system

# The API's Keycloak confidential client secret
kubectl create secret generic catalyx-api-credentials \
  --from-literal=client-secret=<catalyx-api-client-secret> \
  -n catalyx-system
```

{% hint style="danger" %}
`catalyx-api-credentials` is **not optional**. The API pod will not start without it — it fails with `CreateContainerConfigError`.
{% endhint %}
{% endstep %}

{% step %}
**Create the TLS secret**

The chart does not create a TLS certificate unless you enable cert-manager. The default name is `catalyx-app-tls`.

```bash
kubectl create secret tls catalyx-app-tls \
  --cert=<path-to-cert.pem> --key=<path-to-key.pem> \
  -n catalyx-system
```

{% hint style="warning" %}
This secret name is used by **every ingress route the operator creates for validators**, not just by the console and API. If it does not exist, validator UIs will fail to serve over HTTPS even if you never set `ingress.tls.secretName` yourself.
{% endhint %}
{% endstep %}

{% step %}
**Create the image pull secret**

```bash
kubectl create secret docker-registry intellecteu-jfrog-access \
  --docker-server=intellecteu-catbp-docker.jfrog.io \
  --docker-username=<username> --docker-password=<token> \
  -n catalyx-system
```

{% endstep %}
{% endstepper %}

***

## Install

```bash
helm install catalyx-canton catalyx/catalyx-canton \
  -n catalyx-system \
  --set image.tag=v2.0.0 \
  --set 'image.pullSecrets[0].name=intellecteu-jfrog-access' \
  --set operator.keycloak.serverUrl=https://keycloak.example.com \
  --set operator.keycloak.realm=my-realm \
  --set operator.keycloak.adminClientId=catalyx-operator-admin \
  --set operator.keycloak.adminClientSecretRef.name=catalyx-operator-keycloak \
  --set api.auth.jwksUri=https://keycloak.example.com/realms/my-realm/protocol/openid-connect/certs \
  --set ui.oidc.authority=https://keycloak.example.com/realms/my-realm \
  --set ui.oidc.redirectUri=https://validators.example.com \
  --set operatorRuntime.baseHostname=validators.example.com \
  --set ingress.host=validators.example.com \
  --set ingress.tls.secretName=catalyx-app-tls
```

Contact IntellectEU support for the Helm repository URL and credentials.

Verify the rollout:

```bash
kubectl -n catalyx-system get deploy
kubectl -n catalyx-system wait --for=condition=Available deployment \
  -l app.kubernetes.io/instance=catalyx-canton --timeout=180s
```

The console is then available at `https://<ingress.host>/`, and the API at `https://<ingress.host>/api`.

***

## Values you must set

These have defaults that are only suitable for local development. Every production install should override all of them.

<table><thead><tr><th width="330">Value</th><th>Purpose</th></tr></thead><tbody><tr><td><code>ingress.host</code></td><td>Hostname the console and API are served on. When empty, ingress routes match on path only, with no host clause.</td></tr><tr><td><code>ingress.tls.secretName</code></td><td>TLS secret for the console and API routes.</td></tr><tr><td><code>operatorRuntime.baseHostname</code></td><td>Base hostname for every per-validator hostname the operator generates, and for the identity provider redirect URIs it registers. Changing it later rewrites those redirect URIs on the next reconcile.</td></tr><tr><td><code>operatorRuntime.tlsSecretName</code></td><td>TLS secret used by every ingress route the operator creates. Default <code>catalyx-app-tls</code>.</td></tr><tr><td><code>api.auth.jwksUri</code></td><td>JWKS endpoint the API validates console tokens against.</td></tr><tr><td><code>ui.oidc.authority</code></td><td>OIDC issuer the console redirects browser logins to.</td></tr><tr><td><code>ui.oidc.clientId</code></td><td>Public OIDC client for the console. Default <code>catalyx-canton-ui</code>.</td></tr><tr><td><code>ui.oidc.redirectUri</code></td><td>Where the identity provider returns the browser after login. Must match a redirect URI registered on the client.</td></tr><tr><td><code>image.tag</code></td><td>Pin to a release tag. Default is <code>latest</code>.</td></tr><tr><td><code>image.pullSecrets</code></td><td>Pull secret for the IntellectEU registry.</td></tr></tbody></table>

## Managed authentication values

Required only if you intend to use `managedKeycloak: true` on any validator.

<table><thead><tr><th width="380">Value</th><th>Purpose</th></tr></thead><tbody><tr><td><code>operator.keycloak.serverUrl</code></td><td>Identity provider base URL.</td></tr><tr><td><code>operator.keycloak.realm</code></td><td>Realm the operator provisions into. Must already exist.</td></tr><tr><td><code>operator.keycloak.adminClientId</code></td><td>Admin client the operator authenticates as. Must exist <strong>in that realm</strong>.</td></tr><tr><td><code>operator.keycloak.adminClientSecretRef.name</code> / <code>.key</code></td><td>Secret holding the admin client secret. Key defaults to <code>admin-client-secret</code>.</td></tr><tr><td><code>operator.keycloak.apiClientId</code></td><td>The client that per-validator Ledger API scopes are attached to. Default <code>catalyx-api</code>.</td></tr></tbody></table>

## Component values

<table><thead><tr><th width="300">Value</th><th width="150">Default</th><th>Notes</th></tr></thead><tbody><tr><td><code>operator.replicaCount</code></td><td><code>1</code></td><td><strong>Must remain 1.</strong> The operator has no leader election; a second replica double-reconciles every resource.</td></tr><tr><td><code>api.replicaCount</code></td><td><code>1</code></td><td><strong>Must remain 1.</strong> Canton console sessions are held in process, so they do not survive being load-balanced across replicas.</td></tr><tr><td><code>ui.replicaCount</code></td><td><code>2</code></td><td>The console is stateless and runs highly available by default, with a pod disruption budget and topology spread.</td></tr><tr><td><code>api.namespace</code></td><td>release namespace</td><td>Namespace the API reads validators from. The API's RBAC is namespaced to the release namespace, so pointing this elsewhere produces authorisation errors.</td></tr><tr><td><code>operator.rbac.clusterAdmin</code></td><td><code>false</code></td><td>Leave <code>false</code>. When <code>true</code>, the operator service account is bound to <code>cluster-admin</code> instead of the chart's least-privilege role.</td></tr><tr><td><code>ui.grafana.baseUrl</code></td><td>—</td><td>Base URL for the Grafana deep links in the console. See <a href="/pages/3Yn0J5hyBIme6EGLfI4u">Grafana Links</a>.</td></tr><tr><td><code>monitoring.serviceMonitor.enabled</code></td><td><code>false</code></td><td>Set <code>true</code> to have Prometheus scrape validator component metrics. Requires the Prometheus Operator CRDs.</td></tr><tr><td><code>certManager.enabled</code></td><td><code>false</code></td><td>Set <code>true</code>, with <code>certManager.certificate.create</code> and <code>certManager.certificate.dnsNames</code>, to have cert-manager issue the platform certificate.</td></tr></tbody></table>

{% hint style="warning" %}
**Harden the OpenAPI endpoints before exposing the platform publicly.** The chart publishes `/swagger-ui` and `/v3/api-docs` on the same hostname as the API, and both are served without authentication. If that is not acceptable in your environment, restrict them with a Traefik middleware via `api.ingress.middlewares`, or block them at your edge.
{% endhint %}

***

## Upgrading

```bash
helm upgrade catalyx-canton catalyx/catalyx-canton -n catalyx-system -f my-values.yaml
```

{% hint style="danger" %}
**Helm does not upgrade CRDs.** `helm upgrade` never touches the chart's `crds/` directory. When a release changes the `Validator` or `Application` schema, apply the CRDs explicitly before upgrading:

```bash
kubectl apply -f <chart>/crds
```

{% endhint %}

Existing validators are re-reconciled after an upgrade. The operator applies rolling updates to component deployments, so a component with more than one replica is updated without downtime.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.catalyx.solutions/catalyx-blockchain-manager/canton-network/version-2.0/installation-instructions-canton/platform-installation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
