Files
zeekayandHanzo Dev 15d100931d
Hanzo CI/CD / cicd (push) Failing after 9m46s
CI/CD / cicd (push) Failing after 10m4s
Name the ingress in the docs, and fix what that exposed
Most of it was stale, not cosmetic: the docs taught `TRAEFIK_*` env,
`traefik.http.*` labels, `traefik.ingress.kubernetes.io/` annotations,
`.traefik.yml` plugins and `traefik_*` metrics. This binary answers to
`INGRESS_*`, `ingress.http.*`, `ingress.kubernetes.io/`, `.ingress.yml` and
`ingress.*` — a reader following the old text configured nothing.

Two were worse than stale. Gateway API examples gave `group: traefik.io` for an
IngressService backendRef, which kubernetes.go:1265 refuses against hanzo.ai.
The contributing guide built with `github.com/traefik/ingress` ldflags against
a module that is `github.com/hanzoai/ingress/v3`.

script/code-gen.sh globs `hanzo.ai_*.yaml` and matched nothing — the per-CRD
dumps had been deleted and never regenerated, so `cat` failed the script under
`set -e`. controller-gen v0.19.0 restores all ten; they concatenate
byte-for-byte into the committed definition and fixture.

CHANGELOG.md is untouched: 6,789 lines of imported release history, where a
rewrite would falsify the record rather than rebrand it. `@traefiklabs/faency`,
`traefik/whoami`, k3s's `--disable=traefik`, the `traefik.io` CRD group and the
MIT attribution stay — upstream's addresses, not our brand.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-16 13:01:19 -07:00

5.7 KiB

title, description
title description
Hanzo Ingress Tailscale Documentation Learn how to configure Hanzo Ingress to resolve TLS certificates for your Tailscale services. Read the technical documentation.

Tailscale

Provision TLS certificates for your internal Tailscale services. {: .subtitle }

To protect a service with TLS, a certificate from a public Certificate Authority is needed. In addition to its vpn role, Tailscale can also provide certificates for the machines in your Tailscale network.

Certificate resolvers

To obtain a TLS certificate from the Tailscale daemon, a Tailscale certificate resolver needs to be configured as below.

!!! info "Referencing a certificate resolver"

Defining a certificate resolver does not imply that routers are going to use it automatically.
Each router or entrypoint that is meant to use the resolver must explicitly [reference](../routing/routers/index.md#certresolver) it.
certificatesResolvers:
    myresolver:
        tailscale: {}
[certificatesResolvers.myresolver.tailscale]
--certificatesresolvers.myresolver.tailscale=true

Domain Definition

A certificate resolver requests certificates for a set of domain names inferred from routers, according to the following:

  • If the router has a tls.domains option set, then the certificate resolver derives this router domain name from the main option of tls.domains.

  • Otherwise, the certificate resolver derives the domain name from any Host() or HostSNI() matchers in the router's rule.

!!! info "Tailscale Domain Format"

The domain is only taken into account if it is a Tailscale-specific one,
i.e. of the form `machine-name.domains-alias.ts.net`.

Configuration Example

!!! example "Enabling Tailscale certificate resolution"

```yaml tab="File (YAML)"
entryPoints:
  web:
    address: ":80"

  websecure:
    address: ":443"

certificatesResolvers:
  myresolver:
    tailscale: {}
```

```toml tab="File (TOML)"
[entryPoints]
  [entryPoints.web]
    address = ":80"

  [entryPoints.websecure]
    address = ":443"

[certificatesResolvers.myresolver.tailscale]
```

```bash tab="CLI"
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
# ...
--certificatesresolvers.myresolver.tailscale=true
```

!!! example "Domain from Router's Rule Example"

```yaml tab="Docker & Swarm"
## Dynamic configuration
labels:
  - ingress.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
  - ingress.http.routers.blog.tls.certresolver=myresolver
```

```yaml tab="Docker (Swarm)"
## Dynamic configuration
deploy:
  labels:
    - ingress.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
    - ingress.http.routers.blog.tls.certresolver=myresolver
```

```yaml tab="Kubernetes"
apiVersion: hanzo.ai/v1alpha1
kind: IngressRoute
metadata:
  name: blogtls
spec:
  entryPoints:
    - websecure
  routes:
    - match: Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
      kind: Rule
      services:
        - name: blog
          port: 8080
  tls:
    certResolver: myresolver
```

```yaml tab="File (YAML)"
## Dynamic configuration
http:
  routers:
    blog:
      rule: "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)"
      tls:
        certResolver: myresolver
```

```toml tab="File (TOML)"
## Dynamic configuration
[http.routers]
  [http.routers.blog]
  rule = "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)"
  [http.routers.blog.tls]
    certResolver = "myresolver"
```

!!! example "Domain from Router's tls.domain Example"

```yaml tab="Docker & Swarm"
## Dynamic configuration
labels:
  - ingress.http.routers.blog.rule=Path(`/metrics`)
  - ingress.http.routers.blog.tls.certresolver=myresolver
  - ingress.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net
```

```yaml tab="Docker (Swarm)"
## Dynamic configuration
deploy:
  labels:
    - ingress.http.routers.blog.rule=Path(`/metrics`)
    - ingress.http.routers.blog.tls.certresolver=myresolver
    - ingress.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net
```

```yaml tab="Kubernetes"
apiVersion: hanzo.ai/v1alpha1
kind: IngressRoute
metadata:
  name: blogtls
spec:
  entryPoints:
    - websecure
  routes:
    - match: Path(`/metrics`)
      kind: Rule
      services:
        - name: blog
          port: 8080
  tls:
    certResolver: myresolver
    domains:
      - main: monitoring.yak-bebop.ts.net
```

```yaml tab="File (YAML)"
## Dynamic configuration
http:
  routers:
    blog:
      rule: "Path(`/metrics`)"
      tls:
        certResolver: myresolver
        domains:
          - main: "monitoring.yak-bebop.ts.net"
```

```toml tab="File (TOML)"
## Dynamic configuration
[http.routers]
  [http.routers.blog]
    rule = "Path(`/metrics`)"
    [http.routers.blog.tls]
      certResolver = "myresolver"
      [[http.routers.blog.tls.domains]]
        main = "monitoring.yak-bebop.ts.net"
```

Automatic Renewals

Hanzo Ingress automatically tracks the expiry date of each Tailscale certificate it fetches, and starts to renew a certificate 14 days before its expiry to match Tailscale daemon renew policy.