{"slug":"customize-the-kubernetes-operator-and-resources-it-manages","title":"Customize the Kubernetes operator and resources it manages","tags":["tailscale","containers"],"agent_summary":"Last validated: Jan 5, 2026","trigger_phrases":[],"runnable":false,"markdown":"\r\n# Customize the Kubernetes operator and resources it manages\r\n\r\nLast validated: Jan 5, 2026\r\n\r\n## [Cluster resource customization using `ProxyClass`](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#cluster-resource-customization-using-proxyclass)\r\n\r\nTailscale operator v1.60 and later provides the ability to customize the configuration of cluster resources created by the operator using `ProxyClass` [Custom Resource Definition](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources).\r\n\r\nYou can specify cluster resource configuration for custom labels and resource requests using a `ProxyClass` Custom Resource.\r\n\r\nYou can then:\r\n\r\n- Apply configuration from a particular `ProxyClass` to cluster resources created for a Tailscale Ingress or Service by using a `tailscale.com/proxy-class=<proxy-class-name>` annotation on the Ingress or Service.\r\n\r\n- Apply configuration from a particular `ProxyClass` to cluster resources created for a [`Connector`](https://tailscale.com/docs/features/kubernetes-operator/how-to/connector) using `connector.spec.proxyClass` field.\r\n\r\n\r\nThe following example shows how to use a `ProxyClass` that specifies custom labels and node selectors. These are applied to Pods for a [Tailscale Ingress](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress), a [cluster egress proxy](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress), a [`Connector`](https://tailscale.com/docs/features/kubernetes-operator/how-to/connector), and a [`ProxyGroup`](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress#configure-an-egress-service-using-proxygroup):\r\n\r\n1. Create a `ProxyClass` resource:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\n     name: prod\r\nspec:\r\n     statefulSet:\r\n       pod:\r\n         labels:\r\n           team: eng\r\n           environment: prod\r\n         nodeSelector:\r\n           beta.kubernetes.io/os: \"linux\"\r\n```\r\n\r\n2. Create a Tailscale Ingress with `tailscale.com/proxy-class=prod` annotation:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: networking.k8s.io/v1\r\nkind: Ingress\r\nmetadata:\r\n     name: my-app\r\n     annotations:\r\n       tailscale.com/proxy-class: \"prod\"\r\nspec:\r\n     rules:\r\n     ...\r\n     ingressClassName: tailscale\r\n```\r\n\r\n3. Create a [cluster egress](https://tailscale.com/docs/features/kubernetes-operator/how-to/cloud-services) Service with a `tailscale.com/proxy-class=prod` annotation:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n     annotations:\r\n       tailscale.com/tailnet-ip: <tailnet-ip>\r\n       tailscale.com/proxy-class: \"prod\"\r\n     name: my-tailnet-service\r\nspec:\r\n```\r\n\r\n4. Create a `Connector` that refers to the 'prod' `ProxyClass`:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: Connector\r\nmetadata:\r\n     name: prod\r\nspec:\r\n     proxyClass: prod\r\n     ...\r\n```\r\n\r\n5. Create a `ProxyGroup` that refers to the 'prod' `ProxyClass`:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: ProxyGroup\r\nmetadata:\r\n     name: egress\r\nspec:\r\n     proxyClass: prod\r\n     ...\r\n```\r\n\r\n\r\nYou can find [all available `ProxyClass` configuration options on GitHub →](https://github.com/tailscale/tailscale/blob/main/k8s-operator/api.md#proxyclass)\r\n\r\n### [Default `ProxyClass`](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#default-proxyclass)\r\n\r\nTailscale v1.74 and later lets you specify a default `ProxyClass`. Configuration from a default `ProxyClass` is applied\r\nto [cluster ingress](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress), [cluster egress](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress) and\r\n[`ProxyGroup`](https://tailscale.com/docs/features/kubernetes-operator#proxy-group) proxies that don't have a `ProxyClass` explicitly set.\r\nYou can set a default `ProxyClass` for the cluster by using the `proxyConfig.defaultProxyClass` Helm value if [installing\\\\\r\nusing Helm](https://tailscale.com/docs/features/kubernetes-operator#helm) or by using the `PROXY_DEFAULT_CLASS` environment variable if [installing using static\\\\\r\nmanifests](https://tailscale.com/docs/features/kubernetes-operator#static-manifests).\r\n\r\n## [Proxy configuration](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#proxy-configuration)\r\n\r\nYou can specify a `ProxyClass` for [`Connector`](https://tailscale.com/docs/features/kubernetes-operator/how-to/connector) resources, and [egress](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress) and [ingress](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress) proxies.\r\n\r\nThe [API server proxy](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy) currently runs as part of the same process as the Kubernetes operator. You can use [the available operator configuration options](https://tailscale.com/docs/features/kubernetes-operator#installation) to configure the API server proxy parameters.\r\n\r\n### [Customizing tags](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#customizing-tags)\r\n\r\nAll the proxies that the operator creates are [Tailscale devices](https://tailscale.com/docs/features/access-control/device-management) tagged by one or more [tags](https://tailscale.com/docs/features/tags).\r\n\r\nThe Tailscale operator must be a [tag owner](https://tailscale.com/docs/features/tags#define-tag-owners) of all the proxy tags: if you want to tag a proxy device with `tag:prod,tag:emea`, the [`tagOwners` section of the tailnet policy file](https://tailscale.com/docs/reference/syntax/policy-file#tag-owners) must list `tag:k8s-operator` as one of the owners of both `tag:prod` and `tag:emea`.\r\n\r\nCurrently, tags can not be modified after a proxy has been created.\r\n\r\n#### [Default tags](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#default-tags)\r\n\r\nBy default, a proxy device joins your tailnet tagged with the [tag](https://tailscale.com/docs/features/tags)`tag:k8s`. You can modify the default tag or tags when installing the operator.\r\n\r\nIf you install the operator [with Helm](https://tailscale.com/docs/features/kubernetes-operator#helm), you can use `.proxyConfig.defaultTags` in the Helm values file.\r\n\r\nIf you install the operator [with static manifests](https://tailscale.com/docs/features/kubernetes-operator#static-manifests), you can set the `PROXY_TAGS` environment variable in the deployment manifest.\r\n\r\nMultiple tags must be passed as a comma separated string, that is, `tag:prod,tag:emea`.\r\n\r\n#### [Tags for individual proxies](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#tags-for-individual-proxies)\r\n\r\nTo override the default tags for an individual proxy created for a Tailscale Service or Ingress, you can set the `tailscale.com/tags` annotation on the Service or Ingress resource to a comma separated list of the desired tags.\r\nFor example, setting `tailscale.com/tags: \"tag:prod,tag:emea\"` annotation will result in the proxy device having the tags `tag:prod` and `tag:emea`.\r\n\r\nTo override the default tags for the proxy created for a [`Connector`](https://tailscale.com/docs/features/kubernetes-operator/how-to/connector) custom resource, you can set tags by using the `spec.tags` field.\r\n\r\nRefer to [Common patterns for tag names](https://tailscale.com/docs/features/tags#common-patterns-for-tag-names) for best practices around tag names.\r\n\r\n### [Static endpoints](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#static-endpoints)\r\n\r\nThis functionality is available in Tailscale v1.86 and later, and is only available to proxies within [`ProxyGroups`](https://tailscale.com/docs/features/kubernetes-operator#proxy-group).\r\n\r\nTailscale uses various [NAT traversal techniques](https://tailscale.com/blog/how-nat-traversal-works) to securely connect to other Tailscale nodes without manual intervention. Most of the time, you do not need to open any [firewall ports](https://tailscale.com/docs/integrations/firewalls) for Tailscale. However, in some scenarios where NAT Traversal is unsuccessful, Tailscale proxies deployed by the operator may have to rely on a [relayed connection](https://tailscale.com/blog/how-tailscale-works#encrypted-tcp-relays-derp), resulting in lower throughput and performance compared to direct connections. For example, when using AWS NAT Gateways, which are [hard NATs](https://tailscale.com/docs/reference/device-connectivity#hard-nat)).\r\n\r\nIn these scenarios, `ProxyClass` provides the configuration that lets users leverage [Kubernetes NodePort Services](https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport) as extra endpoints to facilitate direct connections to `ProxyGroups`.\r\n\r\nOnce configured, these endpoints will only work for tailnet devices on the same network as that Kubernetes Node. If the Kubernetes Node has a public IP address, the configured static endpoint will be reachable by all Tailscale devices.\r\n\r\n#### [Configure firewall rules](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#configure-firewall-rules)\r\n\r\nA maximum of two static endpoints are now allowed per `ProxyGroup`. To specify which nodes the operator uses for NodePort Services, configure the `spec.staticEndpoints.selector` field in the [ProxyClass resource](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#configuring-static-endpoints).\r\n\r\nTo leverage static endpoints, firewall rules will likely need to be configured to allow inbound traffic to be sent to each relevant Node's IP address.\r\n\r\nGiven the horizontally scalable nature of ProxyGroups, we recommend configuring a suitable number of ports on the firewall to reduce the chance of running out of ports when scaling the number of ProxyGroup replicas.\r\n\r\n#### [Configure static endpoints](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#configure-static-endpoints)\r\n\r\n1. Create a ProxyClass.\r\nThe configuration for static endpoints is exposed as part of the [ProxyClass](https://github.com/tailscale/tailscale/blob/main/k8s-operator/api.md#proxyclass) custom resource, under `spec.staticEndpoints`:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\n       name: prod\r\nspec:\r\n       staticEndpoints:\r\n       nodePort:\r\n           ports:\r\n        - \"31667-31680\"\r\n        selector:\r\n        kubernetes.io/os: linux\r\n```\r\n\r\nIn this example, `ProxyClass` is configured to use [Kubernetes NodePort services](https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport) for the static endpoints. Inside the `nodePortConfig`, a list of `ports` can be configured. It's also important to ensure that the specified ranges have the necessary firewall rules configured so that the endpoints are reachable from other tailnet devices. The `selector` field can also be used to select which Kubernetes node's `ExternalIP`s should be used for the static endpoints.\r\n\r\nOnce created, this ProxyClass can be referenced on a ProxyGroup to configure static endpoints for all its replicas:\r\n\r\n2. Create a ProxyGroup.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: ProxyGroup\r\nmetadata:\r\n       name: ingress\r\nspec:\r\n       type: ingress\r\n       proxyClass: prod\r\n       replicas: 3\r\n```\r\n\r\n\r\n\r\nThe example above (once applied) will create three proxy replicas, but given the configuration in the ProxyClass will also create three Kubernetes NodePort services to facilitate connections to the ProxyGroup from other tailnet devices:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```bash\r\nNAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)           AGE\r\nprod-0-nodeport        NodePort    172.20.123.3     <none>        22918:31669/UDP   84m\r\nprod-1-nodeport        NodePort    172.20.163.230   <none>        22918:31668/UDP   84m\r\nprod-2-nodeport        NodePort    172.20.84.83     <none>        22918:31667/UDP   84m\r\n```\r\n\r\n3. Test the connection.\r\n\r\nOnce the ProxyGroup has been created, a test Pod can be created and exposed using an [HA cluster ingress](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress#expose-a-tailscale-service-in-ha-mode) to test the static endpoint:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: v1\r\nkind: Pod\r\nmetadata:\r\n       name: test\r\n       namespace: default\r\n       labels:\r\n           app: test\r\nspec:\r\n       containers:\r\n    - name: nginx\r\n        image: nginx:latest\r\n        ports:\r\n        - containerPort: 80\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n    name: test\r\n    namespace: default\r\n    annotations:\r\n        tailscale.com/proxy-group: prod\r\nspec:\r\n    type: LoadBalancer\r\n    loadBalancerClass: tailscale\r\n    selector:\r\n        app: test\r\n    ports:\r\n        - port: 80\r\n            targetPort: 80\r\n            protocol: TCP\r\n```\r\n\r\nWhen applied, you can review the Tailscale Service IP address used to expose the Pod to the tailnet using the command `kubectl get service -n default`.\r\n\r\n```bash\r\nNAME         TYPE           CLUSTER-IP       EXTERNAL-IP                                           PORT(S)           AGE\r\ntest         LoadBalancer   172.20.50.164    100.112.194.186                                       80:31109/TCP      2m17s\r\n```\r\n\r\nTest for a direct connection to the Pod in your tailnet by using the Tailscale Service IP address:\r\n\r\n```bash\r\ntailscale ping <EXTERNAL-IP>\r\n```\r\n\r\nIf a direct connection is successful, you should notice a log output similar to:\r\n\r\n```markup\r\npong from prod-0 (100.80.195.111) via 44.213.106.32:31670 in 91ms\r\n```\r\n\r\nIf unsuccessful, you might notice a log output similar to:\r\n\r\n```markup\r\npong from prod-0 (100.80.195.111) via DERP(nyc) in 90ms\r\n```\r\n\r\nIf this log output is observed, ensure that:\r\n   - Inbound firewall rules are configured appropriately for traffic to flow to the correct Kubernetes nodes and port ranges, as configured in the ProxyClass.\r\n   - Selected nodes using `spec.staticEndpoints.nodePort.selector` have `ExternalIP`s in `status.addresses`.\r\n   - The `staticEndpoints` field on the ProxyGroup's `status.devices` is populated with the correct address using a valid `ExternalIP` and the correct `NodePort` for that replica's Service.\r\n\r\n### [Expose metrics](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#expose-metrics)\r\n\r\nWhen specified for a resource, the following `ProxyClass` definition will enable [client metrics](https://tailscale.com/docs/reference/tailscale-client-metrics) at the path `/metrics` on a container port named \"metrics\":\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\nname: prod\r\nspec:\r\nmetrics:\r\n    enable: true\r\n```\r\n\r\nAdditionally the operator will also create a metrics Service for the proxy in the operator's namespace that will also expose metrics on the path `/metrics` on a port named \"metrics\".\r\n\r\n#### [Prometheus `ServiceMonitor`](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#prometheus-servicemonitor)\r\n\r\nThe Kubernetes Operator can also create a [Prometheus `ServiceMonitor`](https://prometheus-operator.dev/docs/developer/getting-started/#using-servicemonitors) for proxy resources.\r\n\r\nTo enable it:\r\n\r\n1. Ensure that [Prometheus operator](https://github.com/prometheus-operator/prometheus-operator) including its Custom Resource Definitions is installed\r\n\r\n2. Apply `ProxyClass` that enables metrics and `ServiceMonitor` creation:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\n     name: prod\r\nspec:\r\n     metrics:\r\n       enable: true\r\n       serviceMonitor:\r\n         enable: true\r\n```\r\n\r\n\r\nThe ingested metrics will have [labels](https://prometheus.io/docs/practices/naming/#labels) that identify the proxy to which the `ProxyClass` was applied:\r\n\r\n- `ts_proxy_type`: type of the proxy. Values can be `ingress_service`, `ingress_resource`, `connector` or `proxygroup`.\r\n\r\n- `ts_proxy_parent_name`: name of the proxy's parent resource. That is, name of the Ingress resource, Tailscale Service, `Connector` or `ProxyGroup`.\r\n\r\n- `ts_proxy_parent_namespace`: namespace of the proxy's parent resource. This only applies to namespaced resources.\r\n\r\n\r\nCurrently it is not possible to customize the created `ServiceMonitor`. We welcome your feedback as to what customization options would be useful for you.\r\n\r\n### [Debug endpoints](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#debug-endpoints)\r\n\r\nDebug endpoints are unstable, may change without notice, and are not recommended for production use.\r\nIf you rely on the debug metrics (at `/debug/metrics`), you must explicitly enable the following debug option before upgrading to 1.82 which will always default debug to disabled.\r\n\r\nIf enabled, the debug endpoints will be available on a container port named \"debug\". The endpoints include `/debug/metrics` and `/debug/pprof/` paths from Go's [`net/http/pprof`](https://pkg.go.dev/net/http/pprof) library.\r\n\r\nTo maintain backward compatibility, debug endpoints default to enabled if `.spec.metrics.enable` is set to `true`. If `.spec.metrics.enable` is set to `false`, the debug endpoints default to disabled.\r\n\r\nIn Tailscale v1.82 and later, the debug endpoints always default to disabled. You can override the default for debug endpoints using `ProxyClass`:\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\nname: prod\r\nspec:\r\nmetrics:\r\n    enable: true\r\nstatefulSet:\r\n    pod:\r\n      tailscaleContainer:\r\n        debug:\r\n          enable: false\r\n```\r\n\r\n### [Using custom machine names](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#using-custom-machine-names)\r\n\r\nCluster ingress and egress proxies support overriding the hostname they announce while registering with Tailscale. For Services, you can set a custom hostname using a `tailscale.com/hostname` annotation. For Ingresses, you can set a custom hostname using the `.spec.tls.hosts` field (only the first value will be used).\r\n\r\nNote that this only sets a custom operating system (OS) hostname reported by the device. The actual machine name [will differ](https://tailscale.com/docs/concepts/machine-names#how-machine-names-are-determined) if a device is on the network with the same name.\r\n\r\nMachine names are subject to the constraints of DNS: they can be up to 63 characters long, must start and end with a letter, and consist of only letters, numbers, and `-`.\r\n\r\n### [Customize permissions](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#customize-permissions)\r\n\r\nPods for proxies created for [cluster ingress using Service](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress#ingress-service), [cluster egress](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress), [`Connector`](https://tailscale.com/docs/features/kubernetes-operator/how-to/connector) and [`ProxyGroup`](https://tailscale.com/docs/features/kubernetes-operator#proxy-group) contain a main `tailscale` container and an `init` container.\r\n\r\nSince Tailscale v1.78, both containers run as [privileged containers](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).\r\nThe main `tailscale` container requires privileged permissions to create a `/dev/net/tun` device.\r\nAs an alternative, you can restrict the main container's permissions and delegate the device creation to a [Kubernetes device plugin](https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/):\r\n\r\n1. Install the [generic device plugin](https://github.com/squat/generic-device-plugin) to your cluster. Pass a `--device` flag that configures the plugin to create `/dev/net/tun` devices:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```shell\r\n   --device='{\"name\": \"tun\", \"groups\": [{\"paths\": [{\"path\": \"/dev/net/tun\"}]}, \"count\": 1000]}'\r\n```\r\n\r\n2. Apply a `ProxyClass` that restricts the `tailscale` container's permissions to `NET_ADMIN` and `NET_RAW` capabilities, and tells the device plugin to create a `/dev/net/tun` device:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\n     name: tailscale-tun\r\nspec:\r\n     statefulSet:\r\n       pod:\r\n         tailscaleContainer:\r\n           resources:\r\n             limits:\r\n               squat.ai/tun: \"1\"\r\n           securityContext:\r\n             allowPrivilegeEscalation: false\r\n             capabilities:\r\n               drop:\r\n              - ALL\r\n            add:\r\n              - NET_ADMIN\r\n              - NET_RAW\r\n```\r\n\r\n3. Ensure that the `ProxyClass` is applied to all proxies created for [Tailscale ingress Services](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress#ingress-service), [Tailscale egress Services](https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress), [`Connector`s](https://tailscale.com/docs/features/kubernetes-operator/how-to/connector) and [`ProxyGroup`s](https://tailscale.com/docs/features/kubernetes-operator#proxy-group).\r\n\r\n\r\nRefer to the detailed instructions and discussion [on GitHub →](https://github.com/tailscale/tailscale/issues/10814#issuecomment-2479977752)\r\n\r\n## [Limitations](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\\#limitations)\r\n\r\n- You cannot enable metrics for egress proxies that do not use a `ProxyGroup`.\r\n\r\n![Project Logo](https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed)\r\n\r\nAsk AI\r\n\r\nreCAPTCHA\r\n\r\nRecaptcha requires verification.\r\n\r\nprotected by **reCAPTCHA**\r\n","html":"<h1>Customize the Kubernetes operator and resources it manages</h1>\n<p>Last validated: Jan 5, 2026</p>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#cluster-resource-customization-using-proxyclass\">Cluster resource customization using <code>ProxyClass</code></a></h2>\n<p>Tailscale operator v1.60 and later provides the ability to customize the configuration of cluster resources created by the operator using <code>ProxyClass</code> <a href=\"https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources\">Custom Resource Definition</a>.</p>\n<p>You can specify cluster resource configuration for custom labels and resource requests using a <code>ProxyClass</code> Custom Resource.</p>\n<p>You can then:</p>\n<ul>\n<li>\n<p>Apply configuration from a particular <code>ProxyClass</code> to cluster resources created for a Tailscale Ingress or Service by using a <code>tailscale.com/proxy-class=&#x3C;proxy-class-name></code> annotation on the Ingress or Service.</p>\n</li>\n<li>\n<p>Apply configuration from a particular <code>ProxyClass</code> to cluster resources created for a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/connector\"><code>Connector</code></a> using <code>connector.spec.proxyClass</code> field.</p>\n</li>\n</ul>\n<p>The following example shows how to use a <code>ProxyClass</code> that specifies custom labels and node selectors. These are applied to Pods for a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress\">Tailscale Ingress</a>, a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress\">cluster egress proxy</a>, a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/connector\"><code>Connector</code></a>, and a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress#configure-an-egress-service-using-proxygroup\"><code>ProxyGroup</code></a>:</p>\n<ol>\n<li>Create a <code>ProxyClass</code> resource:</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\n     name: prod\r\nspec:\r\n     statefulSet:\r\n       pod:\r\n         labels:\r\n           team: eng\r\n           environment: prod\r\n         nodeSelector:\r\n           beta.kubernetes.io/os: \"linux\"\n</code></pre>\n<ol start=\"2\">\n<li>Create a Tailscale Ingress with <code>tailscale.com/proxy-class=prod</code> annotation:</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: networking.k8s.io/v1\r\nkind: Ingress\r\nmetadata:\r\n     name: my-app\r\n     annotations:\r\n       tailscale.com/proxy-class: \"prod\"\r\nspec:\r\n     rules:\r\n     ...\r\n     ingressClassName: tailscale\n</code></pre>\n<ol start=\"3\">\n<li>Create a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cloud-services\">cluster egress</a> Service with a <code>tailscale.com/proxy-class=prod</code> annotation:</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: v1\r\nkind: Service\r\nmetadata:\r\n     annotations:\r\n       tailscale.com/tailnet-ip: &#x3C;tailnet-ip>\r\n       tailscale.com/proxy-class: \"prod\"\r\n     name: my-tailnet-service\r\nspec:\n</code></pre>\n<ol start=\"4\">\n<li>Create a <code>Connector</code> that refers to the 'prod' <code>ProxyClass</code>:</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: Connector\r\nmetadata:\r\n     name: prod\r\nspec:\r\n     proxyClass: prod\r\n     ...\n</code></pre>\n<ol start=\"5\">\n<li>Create a <code>ProxyGroup</code> that refers to the 'prod' <code>ProxyClass</code>:</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: ProxyGroup\r\nmetadata:\r\n     name: egress\r\nspec:\r\n     proxyClass: prod\r\n     ...\n</code></pre>\n<p>You can find <a href=\"https://github.com/tailscale/tailscale/blob/main/k8s-operator/api.md#proxyclass\">all available <code>ProxyClass</code> configuration options on GitHub →</a></p>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#default-proxyclass\">Default <code>ProxyClass</code></a></h3>\n<p>Tailscale v1.74 and later lets you specify a default <code>ProxyClass</code>. Configuration from a default <code>ProxyClass</code> is applied\r\nto <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress\">cluster ingress</a>, <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress\">cluster egress</a> and\r\n<a href=\"https://tailscale.com/docs/features/kubernetes-operator#proxy-group\"><code>ProxyGroup</code></a> proxies that don't have a <code>ProxyClass</code> explicitly set.\r\nYou can set a default <code>ProxyClass</code> for the cluster by using the <code>proxyConfig.defaultProxyClass</code> Helm value if <a href=\"https://tailscale.com/docs/features/kubernetes-operator#helm\">installing\\\r\nusing Helm</a> or by using the <code>PROXY_DEFAULT_CLASS</code> environment variable if <a href=\"https://tailscale.com/docs/features/kubernetes-operator#static-manifests\">installing using static\\\r\nmanifests</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#proxy-configuration\">Proxy configuration</a></h2>\n<p>You can specify a <code>ProxyClass</code> for <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/connector\"><code>Connector</code></a> resources, and <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress\">egress</a> and <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress\">ingress</a> proxies.</p>\n<p>The <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\">API server proxy</a> currently runs as part of the same process as the Kubernetes operator. You can use <a href=\"https://tailscale.com/docs/features/kubernetes-operator#installation\">the available operator configuration options</a> to configure the API server proxy parameters.</p>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#customizing-tags\">Customizing tags</a></h3>\n<p>All the proxies that the operator creates are <a href=\"https://tailscale.com/docs/features/access-control/device-management\">Tailscale devices</a> tagged by one or more <a href=\"https://tailscale.com/docs/features/tags\">tags</a>.</p>\n<p>The Tailscale operator must be a <a href=\"https://tailscale.com/docs/features/tags#define-tag-owners\">tag owner</a> of all the proxy tags: if you want to tag a proxy device with <code>tag:prod,tag:emea</code>, the <a href=\"https://tailscale.com/docs/reference/syntax/policy-file#tag-owners\"><code>tagOwners</code> section of the tailnet policy file</a> must list <code>tag:k8s-operator</code> as one of the owners of both <code>tag:prod</code> and <code>tag:emea</code>.</p>\n<p>Currently, tags can not be modified after a proxy has been created.</p>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#default-tags\">Default tags</a></h4>\n<p>By default, a proxy device joins your tailnet tagged with the <a href=\"https://tailscale.com/docs/features/tags\">tag</a><code>tag:k8s</code>. You can modify the default tag or tags when installing the operator.</p>\n<p>If you install the operator <a href=\"https://tailscale.com/docs/features/kubernetes-operator#helm\">with Helm</a>, you can use <code>.proxyConfig.defaultTags</code> in the Helm values file.</p>\n<p>If you install the operator <a href=\"https://tailscale.com/docs/features/kubernetes-operator#static-manifests\">with static manifests</a>, you can set the <code>PROXY_TAGS</code> environment variable in the deployment manifest.</p>\n<p>Multiple tags must be passed as a comma separated string, that is, <code>tag:prod,tag:emea</code>.</p>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#tags-for-individual-proxies\">Tags for individual proxies</a></h4>\n<p>To override the default tags for an individual proxy created for a Tailscale Service or Ingress, you can set the <code>tailscale.com/tags</code> annotation on the Service or Ingress resource to a comma separated list of the desired tags.\r\nFor example, setting <code>tailscale.com/tags: \"tag:prod,tag:emea\"</code> annotation will result in the proxy device having the tags <code>tag:prod</code> and <code>tag:emea</code>.</p>\n<p>To override the default tags for the proxy created for a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/connector\"><code>Connector</code></a> custom resource, you can set tags by using the <code>spec.tags</code> field.</p>\n<p>Refer to <a href=\"https://tailscale.com/docs/features/tags#common-patterns-for-tag-names\">Common patterns for tag names</a> for best practices around tag names.</p>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#static-endpoints\">Static endpoints</a></h3>\n<p>This functionality is available in Tailscale v1.86 and later, and is only available to proxies within <a href=\"https://tailscale.com/docs/features/kubernetes-operator#proxy-group\"><code>ProxyGroups</code></a>.</p>\n<p>Tailscale uses various <a href=\"https://tailscale.com/blog/how-nat-traversal-works\">NAT traversal techniques</a> to securely connect to other Tailscale nodes without manual intervention. Most of the time, you do not need to open any <a href=\"https://tailscale.com/docs/integrations/firewalls\">firewall ports</a> for Tailscale. However, in some scenarios where NAT Traversal is unsuccessful, Tailscale proxies deployed by the operator may have to rely on a <a href=\"https://tailscale.com/blog/how-tailscale-works#encrypted-tcp-relays-derp\">relayed connection</a>, resulting in lower throughput and performance compared to direct connections. For example, when using AWS NAT Gateways, which are <a href=\"https://tailscale.com/docs/reference/device-connectivity#hard-nat\">hard NATs</a>).</p>\n<p>In these scenarios, <code>ProxyClass</code> provides the configuration that lets users leverage <a href=\"https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport\">Kubernetes NodePort Services</a> as extra endpoints to facilitate direct connections to <code>ProxyGroups</code>.</p>\n<p>Once configured, these endpoints will only work for tailnet devices on the same network as that Kubernetes Node. If the Kubernetes Node has a public IP address, the configured static endpoint will be reachable by all Tailscale devices.</p>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#configure-firewall-rules\">Configure firewall rules</a></h4>\n<p>A maximum of two static endpoints are now allowed per <code>ProxyGroup</code>. To specify which nodes the operator uses for NodePort Services, configure the <code>spec.staticEndpoints.selector</code> field in the <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#configuring-static-endpoints\">ProxyClass resource</a>.</p>\n<p>To leverage static endpoints, firewall rules will likely need to be configured to allow inbound traffic to be sent to each relevant Node's IP address.</p>\n<p>Given the horizontally scalable nature of ProxyGroups, we recommend configuring a suitable number of ports on the firewall to reduce the chance of running out of ports when scaling the number of ProxyGroup replicas.</p>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#configure-static-endpoints\">Configure static endpoints</a></h4>\n<ol>\n<li>Create a ProxyClass.\r\nThe configuration for static endpoints is exposed as part of the <a href=\"https://github.com/tailscale/tailscale/blob/main/k8s-operator/api.md#proxyclass\">ProxyClass</a> custom resource, under <code>spec.staticEndpoints</code>:</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\n       name: prod\r\nspec:\r\n       staticEndpoints:\r\n       nodePort:\r\n           ports:\r\n        - \"31667-31680\"\r\n        selector:\r\n        kubernetes.io/os: linux\n</code></pre>\n<p>In this example, <code>ProxyClass</code> is configured to use <a href=\"https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport\">Kubernetes NodePort services</a> for the static endpoints. Inside the <code>nodePortConfig</code>, a list of <code>ports</code> can be configured. It's also important to ensure that the specified ranges have the necessary firewall rules configured so that the endpoints are reachable from other tailnet devices. The <code>selector</code> field can also be used to select which Kubernetes node's <code>ExternalIP</code>s should be used for the static endpoints.</p>\n<p>Once created, this ProxyClass can be referenced on a ProxyGroup to configure static endpoints for all its replicas:</p>\n<ol start=\"2\">\n<li>Create a ProxyGroup.</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: ProxyGroup\r\nmetadata:\r\n       name: ingress\r\nspec:\r\n       type: ingress\r\n       proxyClass: prod\r\n       replicas: 3\n</code></pre>\n<p>The example above (once applied) will create three proxy replicas, but given the configuration in the ProxyClass will also create three Kubernetes NodePort services to facilitate connections to the ProxyGroup from other tailnet devices:</p>\n<pre><code class=\"language-bash\">NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)           AGE\r\nprod-0-nodeport        NodePort    172.20.123.3     &#x3C;none>        22918:31669/UDP   84m\r\nprod-1-nodeport        NodePort    172.20.163.230   &#x3C;none>        22918:31668/UDP   84m\r\nprod-2-nodeport        NodePort    172.20.84.83     &#x3C;none>        22918:31667/UDP   84m\n</code></pre>\n<ol start=\"3\">\n<li>Test the connection.</li>\n</ol>\n<p>Once the ProxyGroup has been created, a test Pod can be created and exposed using an <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress#expose-a-tailscale-service-in-ha-mode\">HA cluster ingress</a> to test the static endpoint:</p>\n<pre><code class=\"language-yaml\">apiVersion: v1\r\nkind: Pod\r\nmetadata:\r\n       name: test\r\n       namespace: default\r\n       labels:\r\n           app: test\r\nspec:\r\n       containers:\r\n    - name: nginx\r\n        image: nginx:latest\r\n        ports:\r\n        - containerPort: 80\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n    name: test\r\n    namespace: default\r\n    annotations:\r\n        tailscale.com/proxy-group: prod\r\nspec:\r\n    type: LoadBalancer\r\n    loadBalancerClass: tailscale\r\n    selector:\r\n        app: test\r\n    ports:\r\n        - port: 80\r\n            targetPort: 80\r\n            protocol: TCP\n</code></pre>\n<p>When applied, you can review the Tailscale Service IP address used to expose the Pod to the tailnet using the command <code>kubectl get service -n default</code>.</p>\n<pre><code class=\"language-bash\">NAME         TYPE           CLUSTER-IP       EXTERNAL-IP                                           PORT(S)           AGE\r\ntest         LoadBalancer   172.20.50.164    100.112.194.186                                       80:31109/TCP      2m17s\n</code></pre>\n<p>Test for a direct connection to the Pod in your tailnet by using the Tailscale Service IP address:</p>\n<pre><code class=\"language-bash\">tailscale ping &#x3C;EXTERNAL-IP>\n</code></pre>\n<p>If a direct connection is successful, you should notice a log output similar to:</p>\n<pre><code class=\"language-markup\">pong from prod-0 (100.80.195.111) via 44.213.106.32:31670 in 91ms\n</code></pre>\n<p>If unsuccessful, you might notice a log output similar to:</p>\n<pre><code class=\"language-markup\">pong from prod-0 (100.80.195.111) via DERP(nyc) in 90ms\n</code></pre>\n<p>If this log output is observed, ensure that:</p>\n<ul>\n<li>Inbound firewall rules are configured appropriately for traffic to flow to the correct Kubernetes nodes and port ranges, as configured in the ProxyClass.</li>\n<li>Selected nodes using <code>spec.staticEndpoints.nodePort.selector</code> have <code>ExternalIP</code>s in <code>status.addresses</code>.</li>\n<li>The <code>staticEndpoints</code> field on the ProxyGroup's <code>status.devices</code> is populated with the correct address using a valid <code>ExternalIP</code> and the correct <code>NodePort</code> for that replica's Service.</li>\n</ul>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#expose-metrics\">Expose metrics</a></h3>\n<p>When specified for a resource, the following <code>ProxyClass</code> definition will enable <a href=\"https://tailscale.com/docs/reference/tailscale-client-metrics\">client metrics</a> at the path <code>/metrics</code> on a container port named \"metrics\":</p>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\nname: prod\r\nspec:\r\nmetrics:\r\n    enable: true\n</code></pre>\n<p>Additionally the operator will also create a metrics Service for the proxy in the operator's namespace that will also expose metrics on the path <code>/metrics</code> on a port named \"metrics\".</p>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#prometheus-servicemonitor\">Prometheus <code>ServiceMonitor</code></a></h4>\n<p>The Kubernetes Operator can also create a <a href=\"https://prometheus-operator.dev/docs/developer/getting-started/#using-servicemonitors\">Prometheus <code>ServiceMonitor</code></a> for proxy resources.</p>\n<p>To enable it:</p>\n<ol>\n<li>\n<p>Ensure that <a href=\"https://github.com/prometheus-operator/prometheus-operator\">Prometheus operator</a> including its Custom Resource Definitions is installed</p>\n</li>\n<li>\n<p>Apply <code>ProxyClass</code> that enables metrics and <code>ServiceMonitor</code> creation:</p>\n</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\n     name: prod\r\nspec:\r\n     metrics:\r\n       enable: true\r\n       serviceMonitor:\r\n         enable: true\n</code></pre>\n<p>The ingested metrics will have <a href=\"https://prometheus.io/docs/practices/naming/#labels\">labels</a> that identify the proxy to which the <code>ProxyClass</code> was applied:</p>\n<ul>\n<li>\n<p><code>ts_proxy_type</code>: type of the proxy. Values can be <code>ingress_service</code>, <code>ingress_resource</code>, <code>connector</code> or <code>proxygroup</code>.</p>\n</li>\n<li>\n<p><code>ts_proxy_parent_name</code>: name of the proxy's parent resource. That is, name of the Ingress resource, Tailscale Service, <code>Connector</code> or <code>ProxyGroup</code>.</p>\n</li>\n<li>\n<p><code>ts_proxy_parent_namespace</code>: namespace of the proxy's parent resource. This only applies to namespaced resources.</p>\n</li>\n</ul>\n<p>Currently it is not possible to customize the created <code>ServiceMonitor</code>. We welcome your feedback as to what customization options would be useful for you.</p>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#debug-endpoints\">Debug endpoints</a></h3>\n<p>Debug endpoints are unstable, may change without notice, and are not recommended for production use.\r\nIf you rely on the debug metrics (at <code>/debug/metrics</code>), you must explicitly enable the following debug option before upgrading to 1.82 which will always default debug to disabled.</p>\n<p>If enabled, the debug endpoints will be available on a container port named \"debug\". The endpoints include <code>/debug/metrics</code> and <code>/debug/pprof/</code> paths from Go's <a href=\"https://pkg.go.dev/net/http/pprof\"><code>net/http/pprof</code></a> library.</p>\n<p>To maintain backward compatibility, debug endpoints default to enabled if <code>.spec.metrics.enable</code> is set to <code>true</code>. If <code>.spec.metrics.enable</code> is set to <code>false</code>, the debug endpoints default to disabled.</p>\n<p>In Tailscale v1.82 and later, the debug endpoints always default to disabled. You can override the default for debug endpoints using <code>ProxyClass</code>:</p>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\nname: prod\r\nspec:\r\nmetrics:\r\n    enable: true\r\nstatefulSet:\r\n    pod:\r\n      tailscaleContainer:\r\n        debug:\r\n          enable: false\n</code></pre>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#using-custom-machine-names\">Using custom machine names</a></h3>\n<p>Cluster ingress and egress proxies support overriding the hostname they announce while registering with Tailscale. For Services, you can set a custom hostname using a <code>tailscale.com/hostname</code> annotation. For Ingresses, you can set a custom hostname using the <code>.spec.tls.hosts</code> field (only the first value will be used).</p>\n<p>Note that this only sets a custom operating system (OS) hostname reported by the device. The actual machine name <a href=\"https://tailscale.com/docs/concepts/machine-names#how-machine-names-are-determined\">will differ</a> if a device is on the network with the same name.</p>\n<p>Machine names are subject to the constraints of DNS: they can be up to 63 characters long, must start and end with a letter, and consist of only letters, numbers, and <code>-</code>.</p>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#customize-permissions\">Customize permissions</a></h3>\n<p>Pods for proxies created for <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress#ingress-service\">cluster ingress using Service</a>, <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress\">cluster egress</a>, <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/connector\"><code>Connector</code></a> and <a href=\"https://tailscale.com/docs/features/kubernetes-operator#proxy-group\"><code>ProxyGroup</code></a> contain a main <code>tailscale</code> container and an <code>init</code> container.</p>\n<p>Since Tailscale v1.78, both containers run as <a href=\"https://kubernetes.io/docs/tasks/configure-pod-container/security-context/\">privileged containers</a>.\r\nThe main <code>tailscale</code> container requires privileged permissions to create a <code>/dev/net/tun</code> device.\r\nAs an alternative, you can restrict the main container's permissions and delegate the device creation to a <a href=\"https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/\">Kubernetes device plugin</a>:</p>\n<ol>\n<li>Install the <a href=\"https://github.com/squat/generic-device-plugin\">generic device plugin</a> to your cluster. Pass a <code>--device</code> flag that configures the plugin to create <code>/dev/net/tun</code> devices:</li>\n</ol>\n<pre><code class=\"language-shell\">   --device='{\"name\": \"tun\", \"groups\": [{\"paths\": [{\"path\": \"/dev/net/tun\"}]}, \"count\": 1000]}'\n</code></pre>\n<ol start=\"2\">\n<li>Apply a <code>ProxyClass</code> that restricts the <code>tailscale</code> container's permissions to <code>NET_ADMIN</code> and <code>NET_RAW</code> capabilities, and tells the device plugin to create a <code>/dev/net/tun</code> device:</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: ProxyClass\r\nmetadata:\r\n     name: tailscale-tun\r\nspec:\r\n     statefulSet:\r\n       pod:\r\n         tailscaleContainer:\r\n           resources:\r\n             limits:\r\n               squat.ai/tun: \"1\"\r\n           securityContext:\r\n             allowPrivilegeEscalation: false\r\n             capabilities:\r\n               drop:\r\n              - ALL\r\n            add:\r\n              - NET_ADMIN\r\n              - NET_RAW\n</code></pre>\n<ol start=\"3\">\n<li>Ensure that the <code>ProxyClass</code> is applied to all proxies created for <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-ingress#ingress-service\">Tailscale ingress Services</a>, <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/cluster-egress\">Tailscale egress Services</a>, <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/connector\"><code>Connector</code>s</a> and <a href=\"https://tailscale.com/docs/features/kubernetes-operator#proxy-group\"><code>ProxyGroup</code>s</a>.</li>\n</ol>\n<p>Refer to the detailed instructions and discussion <a href=\"https://github.com/tailscale/tailscale/issues/10814#issuecomment-2479977752\">on GitHub →</a></p>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize#limitations\">Limitations</a></h2>\n<ul>\n<li>You cannot enable metrics for egress proxies that do not use a <code>ProxyGroup</code>.</li>\n</ul>\n<p><img src=\"https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed\" alt=\"Project Logo\"></p>\n<p>Ask AI</p>\n<p>reCAPTCHA</p>\n<p>Recaptcha requires verification.</p>\n<p>protected by <strong>reCAPTCHA</strong></p>\n"}