Skip to main content

Exposing Spaces externally

You can expose Spaces externally using one of three options:

OptionWhen to use
LoadBalancer ServiceSimplest setup, recommended for most deployments
Gateway APIOrganization already using Gateway API, or need shared gateway across services
IngressOrganization already using Ingress, or need shared load balancer across services

LoadBalancer Service

Upbound recommends a LoadBalancer Service to expose spaces-router.

important

Use a Network Load Balancer (L4), not an Application Load Balancer (L7). Spaces uses long-lived connections for watch traffic that L7 load balancers may timeout.

Configuration

externalTLS:
host: proxy.example.com # Externally routable hostname for TLS certificates

router:
proxy:
service:
type: LoadBalancer
annotations:
# AWS NLB (see Cloud-Specific Annotations for other clouds)
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip

See Cloud-Specific Annotations for GCP and Azure.

Get the LoadBalancer address

After installation:

kubectl get svc -n upbound-system spaces-router \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}'

Create or update a DNS record pointing your externalTLS.host to this address.

Ingress

Use Ingress if you need to share a load balancer across multiple services or have specific networking requirements.

Requirements

  • TLS passthrough support in your Ingress controller
  • Network Load Balancer (L4) strongly recommended for long-lived connections

Configure your Ingress controller's Service with NLB annotations.

Configuration

ingress:
provision: true
host: proxy.example.com
ingressClassName: "<your-ingress-class>"
# Annotations to add to the Ingress resource
annotations: {}
# Pod labels of the Ingress controller - used for network policy
podLabels: {}
# Namespace labels of the Ingress controller - used for network policy
namespaceLabels: {}

Traefik (with nginx provider)

Traefik can use the kubernetesIngressNGINX provider to handle nginx-style Ingress resources with TLS passthrough.

ingress:
provision: true
host: proxy.example.com
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
podLabels:
app.kubernetes.io/name: traefik
namespaceLabels:
kubernetes.io/metadata.name: traefik

Gateway API

Spaces supports the Gateway API. Use this option if your organization is already using Gateway API or needs a shared gateway across multiple services.

Requirements

  • A Gateway API controller (for example, Envoy Gateway, Cilium, or Traefik)
  • Gateway API CRDs installed in your cluster
  • TLS passthrough support
  • Network Load Balancer (L4) strongly recommended

For step-by-step setup including installing a controller (such as Envoy Gateway) and creating the GatewayClass, see Migrate away from ingress-nginx - Gateway API.

Gateway API configuration

Add the following to your Helm values (or use --set when upgrading). Disable Ingress when using Gateway API.

gatewayAPI:
host: proxy.example.com # Externally routable hostname; must match your DNS
gateway:
provision: true
name: spaces
className: spaces # Must match your GatewayClass name
spacesRouterRoute:
provision: true
podLabels:
app.kubernetes.io/name: envoy
app.kubernetes.io/component: proxy
app.kubernetes.io/managed-by: envoy-gateway
namespaceLabels:
kubernetes.io/metadata.name: envoy-gateway-system

The podLabels and namespaceLabels must match your Gateway API controller's pods and namespace (for NetworkPolicy). The example above uses Envoy Gateway; adjust for your controller.

Install or upgrade Spaces with these values:

helm upgrade spaces oci://xpkg.upbound.io/spaces-artifacts/spaces \
--namespace upbound-system \
-f values.yaml \
--wait

Get the Gateway address

After the Gateway is configured by your controller:

kubectl get gateway -n upbound-system spaces \
-o jsonpath='{.status.addresses[0].value}'

Create or update a DNS record so that gatewayAPI.host points to this address.

Troubleshooting

  • Gateway status: kubectl get gateway -n upbound-system spaces -o yaml — look for Accepted and Programmed in status.conditions.
  • TLSRoute status: kubectl get tlsroute -n upbound-system spaces-router -o yaml — route should show Accepted: True.
  • Connectivity: curl -k "https://<your-host>/version" — expected response is 401 Unauthorized (routing works, auth required).

Cloud-specific annotations

Network Load Balancers (L4) are strongly recommended. Spaces uses long-lived watch connections (hours or days) for kubectl and ArgoCD. L7 load balancers may timeout these connections. Use these annotations on the LoadBalancer Service (spaces-router, Ingress controller, or Gateway).

CloudAnnotations
AWSservice.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
GCPcloud.google.com/l4-rbs: enabled
AzureNone required (L4 by default)