Skip to main content

Serve multiple domains and wildcards

Inspect 1.36

One ingress controller (the reverse proxy running in your cluster) behind one Hetzner load balancer can serve many domains, including wildcard subdomains. This is how an agency places dozens of client domains on a single load balancer instead of one per client. The controller routes each request to the correct application by the Host header.

Many hosts, one or many Ingress objects#

You can lay this out in two ways, and both route identically:

  • One Ingress with several host rules, when the applications reside in one namespace and one team owns them.
  • One Ingress per application, each with its own host. This is the usual choice for multi-tenant setups, because each application's route sits alongside the application, in its own namespace, and a tenant modifies only their own object.
ingress-per-tenant.yamlyaml
		apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tenant-a
  namespace: tenant-a
spec:
  ingressClassName: nginx
  rules:
    - host: app.tenant-a.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80
	

The controller merges every Ingress that names its class into one routing table, so tenant A's object and tenant B's object share the load balancer without being aware of each other.

Wildcard hosts#

A wildcard rule matches every subdomain at one level:

yaml
		rules:
  - host: "*.tenant-a.com"
	

*.tenant-a.com matches app.tenant-a.com and api.tenant-a.com, but not tenant-a.com itself or a deeper a.b.tenant-a.com. Add an exact host rule for the bare domain if you need it.

Certificates: SNI and wildcards#

When a client connects, it sends the hostname it wants in the TLS handshake (SNI, Server Name Indication). The controller uses that name to select the matching certificate from the Secrets its Ingress objects reference. Many domains on one load balancer therefore each use their own certificate, selected per connection. Each certificate is held and served the same way as for a single host; see .

A wildcard certificate for *.tenant-a.com covers every subdomain with one certificate. Note one requirement: a certificate authority will only issue a wildcard after a DNS-01 challenge, which proves you control the domain by writing a TXT record, rather than the HTTP-01 challenge that ordinary certificates use. Configure cert-manager with access to your DNS provider so it can solve DNS-01. See .

One DNS record for every subdomain#

A wildcard also simplifies DNS. Point a wildcard record, *.tenant-a.com, at the load balancer once (a CNAME to the load balancer's hostname, or an A and AAAA to its addresses), and every subdomain resolves to your ingress with no new record per application. Paired with a wildcard certificate, you add api.tenant-a.com or app.tenant-a.com by creating an Ingress alone: no DNS change, no new certificate. can manage these records for you.

Delegate the DNS-01 challenge with a CNAME#

DNS-01 requires cert-manager to write a _acme-challenge TXT record in your zone, which requires granting it API access to that zone. Keep that access limited by delegating only the challenge: add a CNAME from _acme-challenge.tenant-a.com to a record in a separate, less-privileged zone, and give cert-manager credentials for that zone alone. With cnameStrategy: Follow on the solver, cert-manager follows the CNAME and writes the TXT record in the delegated zone, so your main zone's API token is never exposed to the cluster.

Isolate tenants by namespace#

Give each tenant a namespace and keep their Ingress, Services, and certificate Secrets in it. A certificate Secret is only readable in its own namespace, so one tenant's key is never stored where another tenant's application can read it. RBAC on the namespace decides who can edit which routes.

A default backend for unmatched hosts#

A request whose Host matches no rule reaches the controller's default backend, which returns a 404. Set a default backend that returns a plain "not found" page rather than revealing the name of whichever application happens to be first, so a stray or probing request learns nothing about your tenants.

Tip

The Gateway API serves the same many-domains setup with a Gateway and per-application HTTPRoute objects, and gives each tenant their own route to own. See .

Next#

For how agencies run many client clusters on Syself Autopilot, see .