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.

File (YAML)

  1. certificatesResolvers:
  2. myresolver:
  3. tailscale: {}

File (TOML)

  1. [certificatesResolvers.myresolver.tailscale]

CLI

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

File (YAML)

  1. entryPoints:
  2. web:
  3. address: ":80"
  4. websecure:
  5. address: ":443"
  6. certificatesResolvers:
  7. myresolver:
  8. tailscale: {}

File (TOML)

  1. [entryPoints]
  2. [entryPoints.web]
  3. address = ":80"
  4. [entryPoints.websecure]
  5. address = ":443"
  6. [certificatesResolvers.myresolver.tailscale]

CLI

  1. --entrypoints.web.address=:80
  2. --entrypoints.websecure.address=:443
  3. # ...
  4. --certificatesresolvers.myresolver.tailscale=true

Domain from Router’s Rule Example

Docker & Swarm

  1. ## Dynamic configuration
  2. labels:
  3. - traefik.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
  4. - traefik.http.routers.blog.tls.certresolver=myresolver

Docker (Swarm)

  1. ## Dynamic configuration
  2. deploy:
  3. labels:
  4. - traefik.http.routers.blog.rule=Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
  5. - traefik.http.routers.blog.tls.certresolver=myresolver

Kubernetes

  1. apiVersion: traefik.io/v1alpha1
  2. kind: IngressRoute
  3. metadata:
  4. name: blogtls
  5. spec:
  6. entryPoints:
  7. - websecure
  8. routes:
  9. - match: Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)
  10. kind: Rule
  11. services:
  12. - name: blog
  13. port: 8080
  14. tls:
  15. certResolver: myresolver

File (YAML)

  1. ## Dynamic configuration
  2. http:
  3. routers:
  4. blog:
  5. rule: "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)"
  6. tls:
  7. certResolver: myresolver

File (TOML)

  1. ## Dynamic configuration
  2. [http.routers]
  3. [http.routers.blog]
  4. rule = "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)"
  5. [http.routers.blog.tls]
  6. certResolver = "myresolver"

Domain from Router’s tls.domain Example

Docker & Swarm

  1. ## Dynamic configuration
  2. labels:
  3. - traefik.http.routers.blog.rule=Path(`/metrics`)
  4. - traefik.http.routers.blog.tls.certresolver=myresolver
  5. - traefik.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net

Docker (Swarm)

  1. ## Dynamic configuration
  2. deploy:
  3. labels:
  4. - traefik.http.routers.blog.rule=Path(`/metrics`)
  5. - traefik.http.routers.blog.tls.certresolver=myresolver
  6. - traefik.http.routers.blog.tls.domains[0].main=monitoring.yak-bebop.ts.net

Kubernetes

  1. apiVersion: traefik.io/v1alpha1
  2. kind: IngressRoute
  3. metadata:
  4. name: blogtls
  5. spec:
  6. entryPoints:
  7. - websecure
  8. routes:
  9. - match: Path(`/metrics`)
  10. kind: Rule
  11. services:
  12. - name: blog
  13. port: 8080
  14. tls:
  15. certResolver: myresolver
  16. domains:
  17. - main: monitoring.yak-bebop.ts.net

File (YAML)

  1. ## Dynamic configuration
  2. http:
  3. routers:
  4. blog:
  5. rule: "Path(`/metrics`)"
  6. tls:
  7. certResolver: myresolver
  8. domains:
  9. - main: "monitoring.yak-bebop.ts.net"

File (TOML)

  1. ## Dynamic configuration
  2. [http.routers]
  3. [http.routers.blog]
  4. rule = "Path(`/metrics`)"
  5. [http.routers.blog.tls]
  6. certResolver = "myresolver"
  7. [[http.routers.blog.tls.domains]]
  8. 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.