Skip to content

Tailscale

Provision TLS certificates for your internal Tailscale services.

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.

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 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.

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

Enabling Tailscale certificate resolution

entryPoints:
  web:
    address: ":80"

  websecure:
    address: ":443"

certificatesResolvers:
  myresolver:
    tailscale: {}
[entryPoints]
  [entryPoints.web]
    address = ":80"

  [entryPoints.websecure]
    address = ":443"

[certificatesResolvers.myresolver.tailscale]
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
# ...
--certificatesresolvers.myresolver.tailscale=true

Domain from Router's Rule Example

## Dynamic configuration
labels:
  - traefik.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
  - traefik.http.routers.blog.tls.certresolver=myresolver
## Dynamic configuration
deploy:
  labels:
    - traefik.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
    - traefik.http.routers.blog.tls.certresolver=myresolver
apiVersion: traefik.io/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
## Dynamic configuration
http:
  routers:
    blog:
      rule: "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)"
      tls:
        certResolver: myresolver
## Dynamic configuration
[http.routers]
  [http.routers.blog]
  rule = "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)"
  [http.routers.blog.tls]
    certResolver = "myresolver"

Domain from Router's tls.domain Example

## Dynamic configuration
labels:
  - traefik.http.routers.blog.rule=Path(`/metrics`)
  - traefik.http.routers.blog.tls.certresolver=myresolver
  - traefik.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net
## Dynamic configuration
deploy:
  labels:
    - traefik.http.routers.blog.rule=Path(`/metrics`)
    - traefik.http.routers.blog.tls.certresolver=myresolver
    - traefik.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net
apiVersion: traefik.io/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
## Dynamic configuration
http:
  routers:
    blog:
      rule: "Path(`/metrics`)"
      tls:
        certResolver: myresolver
        domains:
          - main: "monitoring.yak-bebop.ts.net"
## 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

Traefik 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.