caddy-tailscale

repository·main·Indexed 21 days ago

https://github.com/tailscale/caddy-tailscale

A Caddy plugin that allows the web server to run a Tailscale node directly within its process. It enables Caddy to join a Tailnet, serve sites privately using the Tailscale network listener, proxy to other Tailnet devices, and authenticate users via the tailscale_auth directive without requiring a separate Tailscale client on the host.

Tokens
5K
Snippets
20
Records
26
Agent score
75%

What's inside caddy-tailscale

  1. Build Caddy with the Tailscale plugin

    main

    To use the Tailscale plugin, you must build a custom Caddy binary that includes it. The recommended way is using xcaddy.

    Alternatively, you can build the included cmd/caddy package directly using go build.

    # Using xcaddy (Recommended)
    xcaddy build v2.9.1 --with github.com/tailscale/caddy-tailscale
    
    # Using go build
    go build ./cmd/caddy
  2. Use the tailscale_auth directive for user authentication

    main

    The tailscale_auth directive sets up a Tailscale authentication provider in Caddy. It enforces that all incoming requests originate from a Tailscale user and populates the Caddy user object with Tailscale-specific identity metadata.

    Key constraints:

    • It currently only works with connections from user-owned devices; it does not support connections from [tagged devices].
    • If used with a Tailscale listener, the node is used to identify the user. Otherwise, it attempts to connect to a local Tailscale daemon.

    Available User Fields: When tailscale_auth is active, the following fields are available on the Caddy user object:

    • user.id: The Tailscale email-ish user ID.
    • user.tailscale_login: The username portion of the Tailscale user ID.
    • user.tailscale_user: Same as user.id.
    • user.tailscale_name: The display name of the Tailscale user.
    • user.tailscale_profile_picture: The URL of the Tailscale user's profile picture.
    • user.tailscale_tailnet: The name of the Tailscale network the user is a member of.
    :80 {
      tailscale_auth
    }
  3. Use the Tailscale network listener to serve sites privately

    main

    The Tailscale network listener allows Caddy to serve sites directly on your tailnet. Use the bind directive within a site block to specify a Tailscale network address.

    • Use tailscale/ (with a trailing slash) to use the default node configuration.
    • Use tailscale/<node_name> to use a specific named node configuration.
    • You can bind to multiple addresses (e.g., Tailscale and localhost) in a single site block.
    # Bind to the default Tailscale node
    :80 {
      bind tailscale/
    }
    
    # Bind to a specific named node
    :80 {
      bind tailscale/myapp
    }
    
    # Bind to multiple interfaces
    :80 {
      bind tailscale/myhost tailscale/my-other-host localhost
    }
  4. Configure HTTPS for Tailscale nodes

    main

    Caddy can use Tailscale's HTTPS support to automatically issue certificates for your node's hostname.

    1. If using the full ts.net hostname: No extra configuration is needed.
    2. If using a partial hostname: You must explicitly specify the tailscale certificate manager in the tls block.
    # Option 1: Full hostname (Automatic)
    https://myhost.tail1234.ts.net {
      bind tailscale/myhost
    }
    
    # Option 2: Partial hostname (Requires explicit cert manager)
    :443 {
      bind tailscale/myhost
      tls {
        get_certificate tailscale
      }
    }
  5. Run Caddy with Tailscale in Docker

    main

    You can use a pre-built Docker image containing the plugin, or build your own using the provided Dockerfile.

    When running via Docker, it is recommended to:

    1. Provide a TS_AUTHKEY environment variable.
    2. Mount a volume to /config to persist the Tailscale state directory so nodes aren't re-registered on every restart.
    3. Mount a custom Caddyfile to /etc/caddy/Caddyfile.
    docker run -it --rm \
      -e TS_AUTHKEY="tskey-auth-XXX" \
      -v ./custom.caddyfile:/etc/caddy/Caddyfile -v ./config:config \
      ghcr.io/tailscale/caddy-tailscale
  6. Configure Tailscale nodes in Caddyfile

    main

    Use the tailscale global option in your Caddyfile to define how Tailscale nodes are registered and managed. You can define global settings or specific named node configurations that override the globals.

    Note: Nodes are only registered and connected to your tailnet when they are actually used (e.g., via a bind directive).

    {
      tailscale {
        # Global settings
        auth_key <auth_key>
        ephemeral true
        state_dir /var/lib/tailscale
    
        # Named node override
        my-app {
          auth_key <different-key>
          hostname custom-host
          tags tag:production
        }
      }
    }
  7. Use the tailscale directive in a Caddyfile

    main

    The Tailscale plugin provides a global tailscale directive for Caddyfiles to configure the App and its Nodes.

    Basic syntax:

    tailscale {
        auth_key <key>
        ephemeral
        tags <tag1> <tag2>
    
        node-name {
            auth_key <key>
            hostname <name>
        }
    }

    Note: For ephemeral and webui, providing the keyword without a value (e.g., just ephemeral) defaults the value to true during parsing.

    tailscale {
        auth_key tskey-auth-123
        state_dir /var/lib/tailscale
    
        web-server-node {
            hostname caddy-node
            port 443
            tags tag:production
        }
    }
  8. Use the Tailscale transport in Caddy

    main

    The Transport module is a Caddy HTTP reverse proxy transport that routes requests through a Tailscale node. It allows Caddy to proxy traffic to services running on your Tailnet.

    To use it, configure a reverse_proxy block in your Caddyfile and specify the tailscale transport followed by the name of the node you wish to use.

    If no node name is provided, it defaults to caddy-proxy.

    reverse_proxy {
      transport tailscale my-node
    }
  9. Use the Tailscale authentication provider in Caddy

    main

    The Auth module is an HTTP authentication provider that identifies users based on their Tailscale identity. When a request is made through a Tailscale node, this provider extracts user metadata and attaches it to the Caddy User object.

    How it works

    1. Identity Extraction: It uses the Tailscale LocalClient to call WhoIs based on the request's remote address.
    2. Node Requirements: The authentication will fail if the Tailscale node servicing the request has any tags assigned to it.
    3. Metadata Injection: Upon successful authentication, the following metadata is added to the caddyauth.User.Metadata map:
      • tailscale_login: The user's login name without the domain (e.g., user).
      • tailscale_user: The user's full login name (e.g., user@example.com).
      • tailscale_name: The user's display name.
      • tailscale_profile_picture: The URL to the user's profile picture.
      • tailscale_tailnet: The user's tailnet name (if the user is not connecting to a shared node).

    Integration

    In a Caddyfile, you can use the tailscale_auth directive. It is registered to appear after basicauth in the directive order.

    # Example Caddyfile usage (conceptual)
    {
        route {
            tailscale_auth
            # Subsequent handlers can access user.Metadata["tailscale_user"]
        }
    }
  10. Map Tailscale user identity to HTTP headers for upstream applications

    main

    You can pass Tailscale identity information to upstream applications (like Gitea or Grafana) by mapping the tailscale_auth user fields to HTTP headers using header_up within a reverse_proxy block. This is useful for applications that support proxy authentication.

    :80 {
      bind tailscale/gitea
      tailscale_auth
      reverse_proxy http://localhost:3000 {
        header_up X-Webauth-User {http.auth.user.tailscale_login}
        header_up X-Webauth-Email {http.auth.user.tailscale_user}
        header_up X-Webauth-Name {http.auth.user.tailscale_name}
      }
    }
  11. Use the tailscale proxy transport

    main

    The tailscale proxy transport allows Caddy to use a Tailscale node to connect to an upstream reverse proxy. This enables proxying non-Tailscale traffic to a node on your tailnet (similar to Tailscale Funnel).

    In the reverse_proxy directive, you can specify a named node configuration. If no name is provided, the default caddy-proxy node is used. Note that the node name is separated by a space (not a slash) in the transport configuration.

    :8080 {
      reverse_proxy http://my-other-node:10000 {
        transport tailscale myhost
      }
    }