Configure multi-cluster ingress with regional routing
Last validated:
This guide shows how to expose an application deployed across two different clusters to your tailnet. A single MagicDNS name routes each Tailscale client to their closest cluster using regional routing.
This guide requires regional routing, which is available on the Premium and Enterprise plans and must be explicitly enabled on your tailnet. Without it, all clients are routed to a single backend regardless of geography.
- A
ProxyGroupin each cluster manages a set of highly available proxies. - A Tailscale
Ingressin each cluster configures the proxies to forward traffic to the backend KubernetesServiceconfigured on theIngress. - A single Tailscale Service represents both replicas of the application that are in each cluster. Clients are automatically routed to the closest cluster based on their proximity to Tailscale's DERP regions.
This tutorial covers Layer 7 ingress using a Kubernetes Ingress resource. You can use the same approach for Layer 3 ingress using a Kubernetes Service resource.
Prerequisites
Before you begin, make sure you have the following:
- Two Kubernetes clusters available, preferably in different geographical regions.
- Tailscale Kubernetes Operator installed in each cluster.
- Necessary permissions configured for high availability ingress.
- Auto-approvers configured in your ACL policy to permit your proxy tag to advertise Tailscale Services.
- Regional routing enabled on your tailnet.
- Client devices configured to accept routes.
Configure the clusters
Perform these steps in each cluster.
Create a ProxyGroup and ProxyClass
Apply the following manifest to manage the ingress proxies and configure them to use Let's Encrypt's staging environment for initial testing.
Set hostnamePrefix to a unique value per cluster (for example, eu-west, us-east). This determines the hostname of each cluster's proxy devices on your tailnet.
apiVersion: tailscale.com/v1alpha1
kind: ProxyGroup
metadata:
name: ingress-proxies
spec:
type: ingress
hostnamePrefix: eu-west
replicas: 2
proxyClass: letsencrypt-staging
---
apiVersion: tailscale.com/v1alpha1
kind: ProxyClass
metadata:
name: letsencrypt-staging
spec:
useLetsEncryptStagingEnvironment: true
kubectl apply -f proxygroup.yaml
Deploy a sample application
If you don't have an existing workload, deploy this sample nginx application.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
kubectl apply -f nginx.yaml
Create the Ingress resource
Expose the nginx service with a shared MagicDNS name. The spec.tls.hosts field determines the MagicDNS name. Use the same hostname in both clusters so they share a single Tailscale Service.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
annotations:
tailscale.com/proxy-group: ingress-proxies
spec:
defaultBackend:
service:
name: nginx
port:
number: 80
ingressClassName: tailscale
tls:
- hosts:
- nginx
kubectl apply -f ingress.yaml
Test the staging environment
-
Check the MagicDNS name:
kubectl get ingress nginx -
Test traffic flow. Because you are using staging certificates, use the
-kflag to bypass certificate warnings:curl -ksS https://nginx.<tailnet>.ts.net -
Verify in the Services that proxy pods from both clusters are listed as backends for the nginx service.
Switch to production certificates
Update the ProxyClass in each cluster to disable the staging environment:
apiVersion: tailscale.com/v1alpha1
kind: ProxyClass
metadata:
name: letsencrypt-staging
spec:
useLetsEncryptStagingEnvironment: false
kubectl apply -f proxyclass.yaml
Test the production environment
Confirm that traffic is served with a valid production certificate:
curl https://nginx.<tailnet>.ts.net
How regional routing works
When the same Ingress is created in multiple clusters pointing to the same MagicDNS hostname, the operator registers proxy pods from each cluster as backends for a single Tailscale Service. The Tailscale control plane then routes each client to the geographically closest healthy backend using the same mechanism as high availability subnet routers.
Further exploration
- Configure resilient Kubernetes deployments with high availability with ProxyGroup.
- Expose a Kubernetes workload to your tailnet at Layer 7 with Expose a workload to your tailnet (L7).
- Route traffic to Kubernetes workloads using Tailscale Services.
- Direct traffic to the appropriate region with Regional routing.