---
title: "Install Calico networking and network policy for on-premises deployments"
description: "Install Calico Open Source networking and network policy on a self-managed Kubernetes cluster running on-premises hardware."
product: "Calico Open Source"
version: "3.32 (latest)"
section: "Installing and upgrading"
canonical_url: "https://docs.tigera.io/calico/latest/getting-started/kubernetes/self-managed-onprem/onpremises"
---

# Install Calico networking and network policy for on-premises deployments

## Big picture

Install Calico to provide both networking and network policy for self-managed on-premises deployments.

## Value

**Calico networking** and **network policy** are a powerful choice for a CaaS implementation. If you have the networking infrastructure and resources to manage Kubernetes on-premises, installing the full Calico product provides the most customization and control.

## Concepts

### Recommended: Tigera Operator

Calico is installed by an operator which manages the installation, upgrade, and general lifecycle of a Calico cluster. The operator is installed directly on the cluster as a Deployment, and is configured through one or more custom Kubernetes API resources.

### Calico manifests

Calico can also be installed using raw manifests as an alternative to the operator. The manifests contain the necessary resources for installing Calico on each node in your Kubernetes cluster. Using manifests is not recommended as they cannot automatically manage the lifecycle of the Calico as the operator does. However, manifests may be useful for clusters that require highly specific modifications to the underlying Kubernetes resources.

## Before you begin...

- Ensure that your Kubernetes cluster meets [requirements](https://docs.tigera.io/calico/latest/getting-started/kubernetes/requirements.md). If you do not have a cluster, see [Installing kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/).

## How to

- [Install Calico](#install-calico)

### Install Calico

<!-- tabs -->

**Tab: Operator**

1. Install the Tigera Operator and custom resource definitions.

   ```text
   kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/v1_crd_projectcalico_org.yaml
   kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/tigera-operator.yaml
   ```

2. Download the custom resources necessary to configure Calico.

   :::tip Automatic data plane deployment You can select either eBPF or iptables to be deployed automatically. :::

   - eBPF
   - iptables

   ```shell
   curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/custom-resources-bpf.yaml
   ```

   ```shell
   curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/custom-resources.yaml
   ```

   If you wish to customize the Calico install, customize the downloaded custom-resources.yaml manifest locally.

3. Create the manifest to install Calico.

   - eBPF
   - iptables

   ```shell
   kubectl create -f custom-resources-bpf.yaml
   ```

   ```shell
   kubectl create -f custom-resources.yaml
   ```

4. Monitor the deployment by running the following command:

   ```shell
   watch kubectl get tigerastatus
   ```

   After a few minutes, all the Calico components display `True` in the `AVAILABLE` column.

   - eBPF
   - iptables

   Expected output

   ```bash
   NAME                            AVAILABLE   PROGRESSING   DEGRADED   SINCE
   apiserver                       True        False         False      4m9s
   calico                          True        False         False      3m29s
   goldmane                        True        False         False      3m39s
   ippools                         True        False         False      6m4s
   kubeproxy-monitor               True        False         False      6m15s
   whisker                         True        False         False      3m19s
   ```

   Expected output

   ```bash
   NAME                            AVAILABLE   PROGRESSING   DEGRADED   SINCE
   apiserver                       True        False         False      4m9s
   calico                          True        False         False      3m29s
   goldmane                        True        False         False      3m39s
   ippools                         True        False         False      6m4s
   whisker                         True        False         False      3m19s
   ```

| Policy | IPAM   | CNI    | Overlay | Routing | Datastore  |
| ------ | ------ | ------ | ------- | ------- | ---------- |
| Calico | Calico | Calico | IPIP    | BGP     | Kubernetes |

?

**Tab: Manifest (v3 CRDs)**

```shell
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/custom-resources-bpf.yaml
```

**Tab: Migrate to v3 CRDs**

```shell
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/custom-resources.yaml
```

**Tab: Manifest**

```shell
kubectl create -f custom-resources-bpf.yaml
```

**Tab: Tab 5**

```shell
kubectl create -f custom-resources.yaml
```

**Tab: Tab 6**

Expected output

```bash
NAME                            AVAILABLE   PROGRESSING   DEGRADED   SINCE
apiserver                       True        False         False      4m9s
calico                          True        False         False      3m29s
goldmane                        True        False         False      3m39s
ippools                         True        False         False      6m4s
kubeproxy-monitor               True        False         False      6m15s
whisker                         True        False         False      3m19s
```

**Tab: Tab 7**

Expected output

```bash
NAME                            AVAILABLE   PROGRESSING   DEGRADED   SINCE
apiserver                       True        False         False      4m9s
calico                          True        False         False      3m29s
goldmane                        True        False         False      3m39s
ippools                         True        False         False      6m4s
whisker                         True        False         False      3m19s
```

**Tab: Tab 8**

> **SECONDARY:** This feature is tech preview. Tech preview features may be subject to significant changes before they become GA.

This manifest installs Calico using the native `projectcalico.org/v3` CRD API group. The v3 API group supports tiered policy, admission webhooks, and other features that aren't available with the legacy `crd.projectcalico.org/v1` API group.

> **SECONDARY:** If you're setting up a new cluster and don't need to customize the underlying Kubernetes resources, we recommend using the operator instead. The operator automatically manages the lifecycle of Calico components, including upgrades and scaling.

Native `projectcalico.org/v3` CRDs rely on MutatingAdmissionPolicies for defaulting, which require the beta `admissionregistration.k8s.io/v1beta1` API. That API is available in **Kubernetes 1.34 and later**; on Kubernetes 1.33 and earlier, MutatingAdmissionPolicy is only available as an alpha API and is not supported. On Kubernetes 1.34 and 1.35, enable the `MutatingAdmissionPolicy` [feature gate](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) on the Kubernetes API server before installing, as it is not enabled by default. On Kubernetes 1.36 and later, the feature is GA and enabled by default.

1. Download the Calico v3 CRD manifest.

   ```bash
   curl https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/calico-v3-crds.yaml -O
   ```

2. If you are using pod CIDR `192.168.0.0/16`, skip to the next step. If you are using a different pod CIDR with kubeadm, no changes are required - Calico will automatically detect the CIDR based on the running configuration. For other platforms, make sure you uncomment the CALICO\_IPV4POOL\_CIDR variable in the manifest and set it to the same value as your chosen pod CIDR.

3. Customize the manifest as necessary.

4. Apply the manifest.

   ```bash
   kubectl apply -f calico-v3-crds.yaml
   ```

5. Generate TLS certificates for the admission webhook.

   The manifest applied above includes a `calico-webhooks` Deployment that serves a `ValidatingWebhookConfiguration` for tiered RBAC enforcement on `projectcalico.org/v3` policy resources, but no TLS material is provisioned by default. Until the certificates are in place, write operations on `projectcalico.org/v3` policy resources will fail closed.

   The following commands create a self-signed CA and a server certificate valid for `calico-webhooks.kube-system.svc`. If you already manage TLS via cert-manager or an internal PKI, use that instead and skip ahead.

   ```bash
   # Self-signed CA.
   openssl genrsa -out ca.key 2048
   openssl req -x509 -new -nodes -key ca.key -days 3650 \
       -subj "/CN=calico-webhooks-ca" -out ca.crt

   # Server cert with SANs for the webhook service.
   openssl genrsa -out tls.key 2048
   cat > csr.conf <<'EOF'
   [req]
   distinguished_name = req_distinguished_name
   req_extensions = v3_req
   prompt = no
   [req_distinguished_name]
   CN = calico-webhooks.kube-system.svc
   [v3_req]
   keyUsage = digitalSignature, keyEncipherment
   extendedKeyUsage = serverAuth
   subjectAltName = @alt_names
   [alt_names]
   DNS.1 = calico-webhooks.kube-system.svc
   DNS.2 = calico-webhooks.kube-system.svc.cluster.local
   EOF
   openssl req -new -key tls.key -out tls.csr -config csr.conf
   openssl x509 -req -in tls.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
       -days 365 -extensions v3_req -extfile csr.conf -out tls.crt
   ```

6. Create the webhook TLS secret in the `kube-system` namespace.

   ```bash
   kubectl -n kube-system create secret tls calico-webhooks-tls \
       --cert=tls.crt --key=tls.key
   ```

7. Patch the `ValidatingWebhookConfiguration` with the CA bundle so the API server trusts the webhook.

   ```bash
   kubectl patch validatingwebhookconfiguration calico-webhooks \
       --type='json' \
       -p="[{\"op\":\"replace\",\"path\":\"/webhooks/0/clientConfig/caBundle\",\"value\":\"$(base64 -w0 < ca.crt)\"}]"
   ```

| Policy | IPAM   | CNI    | Overlay | Routing | Datastore  |
| ------ | ------ | ------ | ------- | ------- | ---------- |
| Calico | Calico | Calico | IPIP    | BGP     | Kubernetes |

?

**Tab: Tab 9**

> **SECONDARY:** This feature is tech preview. Tech preview features may be subject to significant changes before they become GA.

If you have an existing manifest-based Calico install using the legacy `crd.projectcalico.org/v1` CRDs, you can migrate to the native `projectcalico.org/v3` CRDs. This enables tiered policy, admission webhooks, and other v3-only features.

#### Prerequisites

- Calico installed via `calico.yaml` manifest (not operator)
- `kubectl` access to the cluster
- A recent Calico version that includes the migration controller
- **Kubernetes 1.34 or later.** Native `projectcalico.org/v3` CRDs rely on MutatingAdmissionPolicies for defaulting, which require the beta `admissionregistration.k8s.io/v1beta1` API. That API is not available on Kubernetes 1.33 and earlier, where MutatingAdmissionPolicy is alpha only. On Kubernetes 1.34 and 1.35, the `MutatingAdmissionPolicy` [feature gate](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) must be enabled on the Kubernetes API server before starting the migration, as it is not enabled by default. On Kubernetes 1.36 and later, the feature is GA and enabled by default.

#### Migration steps

1. Install the v3 CRDs alongside the existing v1 CRDs.

   ```bash
   kubectl apply --server-side --force-conflicts -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/v3_projectcalico_org.yaml
   ```

2. Install the DatastoreMigration CRD.

   ```bash
   kubectl apply --server-side -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/kube-controllers/pkg/controllers/migration/crd/migration.projectcalico.org_datastoremigrations.yaml
   ```

3. Create a DatastoreMigration resource to start the migration. The migration controller copies all Calico resources from v1 CRDs to v3 CRDs.

   ```bash
   kubectl apply -f - <<EOF
   apiVersion: migration.projectcalico.org/v1beta1
   kind: DatastoreMigration
   metadata:
     name: v1-to-v3
   spec:
     type: APIServerToCRDs
   EOF
   ```

4. Monitor the migration progress.

   ```bash
   kubectl get datastoremigration v1-to-v3 -w
   ```

   The migration transitions through `Pending` → `Migrating` → `Converged`. Once it reaches `Converged`, all resources have been copied to v3 CRDs.

5. When the migration reaches `Converged`, configure calico-node (and calico-typha if present) to use the v3 API group.

   ```bash
   kubectl set env -n kube-system daemonset/calico-node CALICO_API_GROUP=projectcalico.org/v3
   ```

   If you're running calico-typha, update it as well:

   ```bash
   kubectl set env -n kube-system deployment/calico-typha CALICO_API_GROUP=projectcalico.org/v3
   ```

6. The migration controller monitors the rollout and transitions to `Complete` once all pods are running with the v3 API group. kube-controllers restarts automatically to pick up the new API group.

   ```bash
   kubectl get datastoremigration v1-to-v3 -w
   ```

7. Once the migration is `Complete`, delete the DatastoreMigration resource to clean up the old v1 CRDs.

   ```bash
   kubectl delete datastoremigration v1-to-v3
   ```

   The finalizer on the resource deletes all `crd.projectcalico.org` CRDs before removing the resource.

8. Install the admission webhook resources. The Deployment, Service, RBAC, `MutatingAdmissionPolicy` resources, and `ValidatingWebhookConfiguration` are bundled into `calico-v3-crds.yaml` alongside the CRDs and core Calico components. Extract just the webhook resources with [`yq`](https://github.com/mikefarah/yq) and apply them, so the existing `calico-node` DaemonSet, `kube-controllers` Deployment, and `calico-typha` Deployment in your cluster (including the `CALICO_API_GROUP` env you set above) are not overwritten.

   ```bash
   curl https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/calico-v3-crds.yaml -O
   yq 'select(.metadata.name == "calico-webhooks" or .kind == "MutatingAdmissionPolicy" or .kind == "MutatingAdmissionPolicyBinding")' \
       calico-v3-crds.yaml | kubectl apply -f -
   ```

9. Generate TLS certificates for the admission webhook.

   The `calico-webhooks` Deployment serves a `ValidatingWebhookConfiguration` for tiered RBAC enforcement on `projectcalico.org/v3` policy resources, but no TLS material is provisioned by default. Until the certificates are in place, write operations on `projectcalico.org/v3` policy resources will fail closed.

   The following commands create a self-signed CA and a server certificate valid for `calico-webhooks.kube-system.svc`. If you already manage TLS via cert-manager or an internal PKI, use that instead and skip ahead.

   ```bash
   # Self-signed CA.
   openssl genrsa -out ca.key 2048
   openssl req -x509 -new -nodes -key ca.key -days 3650 \
       -subj "/CN=calico-webhooks-ca" -out ca.crt

   # Server cert with SANs for the webhook service.
   openssl genrsa -out tls.key 2048
   cat > csr.conf <<'EOF'
   [req]
   distinguished_name = req_distinguished_name
   req_extensions = v3_req
   prompt = no
   [req_distinguished_name]
   CN = calico-webhooks.kube-system.svc
   [v3_req]
   keyUsage = digitalSignature, keyEncipherment
   extendedKeyUsage = serverAuth
   subjectAltName = @alt_names
   [alt_names]
   DNS.1 = calico-webhooks.kube-system.svc
   DNS.2 = calico-webhooks.kube-system.svc.cluster.local
   EOF
   openssl req -new -key tls.key -out tls.csr -config csr.conf
   openssl x509 -req -in tls.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
       -days 365 -extensions v3_req -extfile csr.conf -out tls.crt
   ```

10. Create the webhook TLS secret in the `kube-system` namespace.

    ```bash
    kubectl -n kube-system create secret tls calico-webhooks-tls \
        --cert=tls.crt --key=tls.key
    ```

11. Patch the `ValidatingWebhookConfiguration` with the CA bundle so the API server trusts the webhook.

    ```bash
    kubectl patch validatingwebhookconfiguration calico-webhooks \
        --type='json' \
        -p="[{\"op\":\"replace\",\"path\":\"/webhooks/0/clientConfig/caBundle\",\"value\":\"$(base64 -w0 < ca.crt)\"}]"
    ```

**Tab: Tab 10**

Based on your datastore and number of nodes, select a link below to install Calico.

> **SECONDARY:** The option, **Kubernetes API datastore, more than 50 nodes** provides scaling using [Typha daemon](https://docs.tigera.io/calico/latest/reference/typha.md). Typha is not included for etcd because etcd already handles many clients so using Typha is redundant and not recommended.

- [Install Calico with Kubernetes API datastore, 50 nodes or less](#install-calico-with-kubernetes-api-datastore-50-nodes-or-less)
- [Install Calico with Kubernetes API datastore, more than 50 nodes](#install-calico-with-kubernetes-api-datastore-more-than-50-nodes)
- [Install Calico with etcd datastore](#install-calico-with-etcd-datastore)

#### Install Calico with Kubernetes API datastore, 50 nodes or less

> **SECONDARY:** This option is maintained for upgrade compatibility, but we recommend that new clusters use the operator, which will automatically configure Calico correctly for your cluster size (including deploying the Typha scale-out proxy and securing it when necessary).

1. Download the Calico networking manifest for the Kubernetes API datastore.

   ```bash
   curl https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/calico.yaml -O
   ```

2. If you are using pod CIDR `192.168.0.0/16`, skip to the next step. If you are using a different pod CIDR with kubeadm, no changes are required — Calico will automatically detect the CIDR based on the running configuration. For other platforms, make sure you uncomment the CALICO\_IPV4POOL\_CIDR variable in the manifest and set it to the same value as your chosen pod CIDR.

3. Customize the manifest as necessary.

4. Apply the manifest using the following command.

   ```bash
   kubectl apply -f calico.yaml
   ```

The geeky details of what you get:

| Policy | IPAM   | CNI    | Overlay | Routing | Datastore  |
| ------ | ------ | ------ | ------- | ------- | ---------- |
| Calico | Calico | Calico | IPIP    | BGP     | Kubernetes |

?

#### Install Calico with Kubernetes API datastore, more than 50 nodes

> **SECONDARY:** This option is maintained for upgrade compatibility but we recommend that new clusters use the operator to deploy Typha (the extra scale-out component included in this manifest) instead of using this method. The operator deploys Typha, autoscales it, and auto-configures mTLS between the per-host agent and Typha for maximum security. This manifest option leaves scaling up to you and, by default, it does not secure Typha's port.

1. Download the Calico networking manifest for the Kubernetes API datastore.

   ```bash
   curl https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/calico-typha.yaml -o calico.yaml
   ```

2. If you are using pod CIDR `192.168.0.0/16`, skip to the next step. If you are using a different pod CIDR with kubeadm, no changes are required — Calico will automatically detect the CIDR based on the running configuration. For other platforms, make sure you uncomment the CALICO\_IPV4POOL\_CIDR variable in the manifest and set it to the same value as your chosen pod CIDR.

3. Modify the replica count to the desired number in the `Deployment` named, `calico-typha`.

   ```yaml
   apiVersion: apps/v1beta1
   kind: Deployment
   metadata:
     name: calico-typha
     ...
   spec:
     ...
     replicas: <number of replicas>
   ```

   We recommend at least one replica for every 200 nodes, and no more than 20 replicas. In production, we recommend a minimum of three replicas to reduce the impact of rolling upgrades and failures. The number of replicas should always be less than the number of nodes, otherwise rolling upgrades will stall. In addition, Typha only helps with scale if there are fewer Typha instances than there are nodes.

   > **SECONDARY:** If you set `typha_service_name` and set the Typha deployment replica count to 0, Felix will not start.

4. Customize the manifest if desired.

5. Apply the manifest.

   ```bash
   kubectl apply -f calico.yaml
   ```

The geeky details of what you get:

| Policy | IPAM   | CNI    | Overlay | Routing | Datastore  |
| ------ | ------ | ------ | ------- | ------- | ---------- |
| Calico | Calico | Calico | IPIP    | BGP     | Kubernetes |

?

#### Install Calico with etcd datastore

> **SECONDARY:** The etcd datastore is not recommended for new Kubernetes installs:
>
> - etcd is another component to manage and maintain.
> - Some newer Kubernetes-targeted features (such as service matches in policy) are not supported with the etcd datastore.
> - eBPF data plane mode is not supported with the etcd datastore. It relies on watching services to implement some features, which is not supported with the etcd datastore.
> - The Cloud/Enterprise versions of Calico do not support etcd mode at all so using this manifest prevents you from upgrading.
>
> However, it is the only option that supports running both OpenStack and Kubernetes nodes in the same cluster.

1. Download the Calico networking manifest for etcd.

   ```bash
   curl https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/calico-etcd.yaml -o calico.yaml
   ```

2. If you are using pod CIDR `192.168.0.0/16`, skip to the next step. If you are using a different pod CIDR with kubeadm, no changes are required — Calico will automatically detect the CIDR based on the running configuration. For other platforms, make sure you uncomment the CALICO\_IPV4POOL\_CIDR variable in the manifest and set it to the same value as your chosen pod CIDR.

3. In the `ConfigMap` named, `calico-config`, set the value of `etcd_endpoints` to the IP address and port of your etcd server.

   > **SECONDARY:** You can specify more than one `etcd_endpoint` using commas as delimiters.

4. Customize the manifest if desired.

5. Apply the manifest using the following command.

   ```bash
   kubectl apply -f calico.yaml
   ```

The geeky details of what you get:

| Policy | IPAM   | CNI    | Overlay | Routing | Datastore |
| ------ | ------ | ------ | ------- | ------- | --------- |
| Calico | Calico | Calico | IPIP    | BGP     | etcd      |

?

<!-- /tabs -->

## Next steps

**Required**

- [Install and configure calicoctl](https://docs.tigera.io/calico/latest/operations/calicoctl/install.md)

**Recommended - Networking**

- If you are using the default BGP networking with full-mesh node-to-node peering with no encapsulation, go to [Configure BGP peering](https://docs.tigera.io/calico/latest/networking/configuring/bgp.md) to get traffic flowing between pods.
- If you are unsure about networking options, or want to implement encapsulation (overlay networking), see [Determine best networking option](https://docs.tigera.io/calico/latest/networking/determine-best-networking.md).

**Recommended - Security**

- [Secure Calico component communications](https://docs.tigera.io/calico/latest/network-policy/comms/crypto-auth.md)
- [Secure hosts by installing Calico on hosts](https://docs.tigera.io/calico/latest/getting-started/bare-metal/about.md)
- [Secure pods with Calico network policy](https://docs.tigera.io/calico/latest/network-policy/get-started/calico-policy/calico-network-policy.md)
- If you are using Calico with Istio service mesh, get started here: [Enable application layer policy](https://docs.tigera.io/calico/latest/network-policy/istio/app-layer-policy.md)
