# Requirements

Confirm every item on this page before you install Zuplo Self-Hosted. The
installation uses a single non-interactive `helm install` command.

This page assumes you already have a working Kubernetes cluster. Creating one is
out of scope.

## Cluster

| Requirement             | Detail                                                                                                   |
| ----------------------- | -------------------------------------------------------------------------------------------------------- |
| Kubernetes              | A conformant cluster. Managed offerings (EKS, AKS, GKE, LKE) and self-managed distributions both work.   |
| Dedicated cluster       | Recommended. To run Zuplo in a multi-tenant cluster, consult your Zuplo point of contact first.          |
| Cluster administrator   | The chart installs CRDs and cluster-scoped RBAC.                                                         |
| `LoadBalancer` Services | The chart creates exactly one, for the HAProxy ingress controller.                                       |
| Privileged pods         | Gateway images are built in-cluster by a Job that runs a privileged container.                           |
| Helm                    | Helm 3.8 or later. The chart is distributed as an OCI artifact.                                          |
| `kubectl`               | Within one minor version of the cluster.                                                                 |
| Nodes                   | Three or more. The chart requests three HAProxy replicas and a Prometheus stack, and builds run as Jobs. |

A default `StorageClass` is not required. The bundled Prometheus runs without
persistent volumes, so the install creates no `PersistentVolumeClaim`.

:::caution{title="Privileged builds"}

The builder Job sets `privileged: true` because it builds container images
inside the cluster. A cluster that enforces the `restricted` Pod Security
Standard on the `zuplo-system` namespace blocks builds. Label the namespace for
the `privileged` policy, or discuss alternatives with your Zuplo solutions
architect.

:::

## Container registry

Gateway images are built in your cluster and pushed to a registry you provide.
The chart does not create it.

- A registry your cluster can push to and pull from, such as Google Artifact
  Registry, Amazon ECR, Azure Container Registry, GitHub Container Registry, or
  a private Harbor.
- Credentials with both push and pull rights, supplied at install time. The
  builder Job and gateway pods use the same Secret. With read-only credentials,
  the build can finish, but the gateway rollout fails.
- Enough quota for a new image tag with every deployment. The chart doesn't
  remove old tags, so configure a retention policy in the registry.

## DNS names

Choose two hostnames. After you install the chart, point both to the external IP
of the `LoadBalancer` Service:

| Name                              | Example                   | Used by                              |
| --------------------------------- | ------------------------- | ------------------------------------ |
| Wildcard under a parent subdomain | `*.api.example.com`       | Your API consumers                   |
| A management API hostname         | `zuplo-admin.example.com` | The Zuplo CLI, your CI/CD, and Zuplo |

Each gateway environment gets a hostname under the parent subdomain when you
deploy it. Because these hostnames aren't known in advance, the wildcard record
routes them to your ingress.

Leave `cert-manager.enabled` at its default of `true`. cert-manager requests a
certificate for each hostname when you deploy it. The first request to a
deployment can fail while cert-manager issues its certificate.

:::tip{title="Send your management API hostname to Zuplo early"}

Zuplo registers your management API endpoint so that deployments from the Zuplo
portal reach your cluster. This registration requires only the hostname. Send it
to your Zuplo solutions architect after you choose it. Zuplo CLI deployments
don't require registration because you pass the endpoint to the CLI.

:::

:::caution{title="Forward HTTP-01 challenge requests"}

If a proxy or external load balancer sits in front of the ingress, keep port 80
publicly reachable. Forward requests to `/.well-known/acme-challenge/*` without
authentication, caching, or response modification. Both cert-manager's
self-check and the certificate authority must receive the response from the
temporary solver Ingress.

:::

## Network access

Allow the following connections:

| Path                                 | Port | Reached by                       | Fails silently? |
| ------------------------------------ | ---- | -------------------------------- | --------------- |
| `*.{parent subdomain}`               | 443  | Your API consumers               | No              |
| The management API hostname          | 443  | The Zuplo CLI and your CI/CD     | No              |
| Cluster DNS resolution of both names | 53   | cert-manager, inside the cluster | **Yes**         |

cert-manager checks the challenge URL from inside the cluster before asking the
certificate authority to validate it. If cluster DNS can't resolve both names,
challenges remain `pending`. To inspect a pending challenge, see
[Troubleshooting](./troubleshooting.md).

For HTTP-01 validation, the certificate authority must also reach the ingress on
port 80. If your cluster can't expose port 80 to the public internet, discuss an
alternative certificate configuration with your Zuplo solutions architect.

## Access to Zuplo services

The cluster needs outbound HTTPS to Zuplo services, both container registries,
and your certificate authority. The management API hostname is the only inbound
path.

:::note

Your Zuplo solutions architect provides the exact hostnames and ports for your
firewall rules during onboarding.

:::

## Observability

Zuplo components use the bundled Prometheus stack to autoscale gateway
deployments based on ingress request rate. It isn't intended as a general
observability service. Because it has no persistent storage, its history doesn't
survive a pod restart.

Plan to run your own logging and monitoring alongside it. Every component, and
every gateway, logs to standard output for collection by your log shipper.

## Check for conflicts

The chart bundles cert-manager, kube-prometheus-stack, and prometheus-adapter as
subcharts. On a cluster that already runs any of them, the install fails on CRD
ownership.

```bash
# Anything returned here is a conflict to resolve before installing.
kubectl get crd | grep -E 'cert-manager\.io|monitoring\.coreos\.com'
kubectl get ingressclass
kubectl get svc -A --field-selector spec.type=LoadBalancer
```

The quick start requires a cluster without an existing cert-manager or
Prometheus Operator installation. If either is present, use a dedicated cluster
or discuss an alternative configuration with your Zuplo solutions architect.

## Run the preflight checks

Run the following commands and compare their output with the comments:

```bash
# 1. The cluster is reachable and the version is what you expect.
kubectl version

# 2. Helm is 3.8 or later (OCI support).
helm version --short

# 3. Nodes are Ready.
kubectl get nodes

# 4. A LoadBalancer implementation exists. On a managed cloud this is the
#    cloud controller manager; on bare metal it is MetalLB or equivalent.
kubectl get pods -A | grep -Ei 'cloud-controller|metallb|cloud-provider'

# 5. No conflicting CRDs (see above). Empty output is success.
kubectl get crd | grep -E 'cert-manager\.io|monitoring\.coreos\.com'
```

## Gather installation values

Gather the following values before you install. You don't need a running cluster
to collect them.

### From the Zuplo portal

Create your account at [portal.zuplo.com](https://portal.zuplo.com), then
collect:

- Open **Account Settings → General**
  ([portal](https://portal.zuplo.com/+/account/settings/general)). This is the
  `account.name` value, so copy it exactly.

### From Zuplo

- Credentials for Zuplo's private registry. The same credential pulls the Helm
  chart and the component images.
- The chart version to pin.

### To Zuplo

- The management API hostname you chose, so Zuplo can register it as your
  account's deployment target.

Next, [install Zuplo Self-Hosted](./install.md).
