{"id":13562970,"url":"https://github.com/tailscale/caddy-tailscale","last_synced_at":"2025-04-14T11:17:49.396Z","repository":{"id":59045738,"uuid":"524317145","full_name":"tailscale/caddy-tailscale","owner":"tailscale","description":"A highly experimental exploration of integrating Tailscale and Caddy.","archived":false,"fork":false,"pushed_at":"2025-02-07T16:39:06.000Z","size":273,"stargazers_count":544,"open_issues_count":17,"forks_count":56,"subscribers_count":35,"default_branch":"main","last_synced_at":"2025-04-14T11:17:39.736Z","etag":null,"topics":["caddy","tailscale","tsnet"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tailscale.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-13T06:08:48.000Z","updated_at":"2025-04-13T22:13:35.000Z","dependencies_parsed_at":"2024-04-08T20:10:21.832Z","dependency_job_id":"ba0d1589-8c8f-45a0-b0b9-7b394d55673a","html_url":"https://github.com/tailscale/caddy-tailscale","commit_stats":null,"previous_names":["tailscale/caddy-tailscale-auth"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tailscale%2Fcaddy-tailscale","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tailscale%2Fcaddy-tailscale/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tailscale%2Fcaddy-tailscale/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tailscale%2Fcaddy-tailscale/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tailscale","download_url":"https://codeload.github.com/tailscale/caddy-tailscale/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248868766,"owners_count":21174758,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["caddy","tailscale","tsnet"],"created_at":"2024-08-01T13:01:13.868Z","updated_at":"2025-04-14T11:17:49.372Z","avatar_url":"https://github.com/tailscale.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Tailscale plugin for Caddy\n\n[![status: experimental](https://img.shields.io/badge/status-experimental-blue)](https://tailscale.com/kb/1167/release-stages/#experimental)\n\nThe Tailscale plugin for Caddy allows running a Tailscale node directly inside of the Caddy web server.\nThis allows a caddy server to join your Tailscale network directly without needing a separate Tailscale client.\n\nIt's really a collection of plugins, providing:\n\n- a Caddy network listener, to serve sites privately on your tailnet\n- a Caddy proxy transport, to proxy requests to another device on your tailnet\n- a Caddy authentication provider, to pass a user's Tailscale identity to an application\n- a Caddy subcommand, to quickly setup a reverse-proxy using either or both of the network listener or authentication provider\n\nThis plugin is still very experimental.\n\n## Why\n\nIt's important to note that you don't necessarily need this plugin to use Caddy with Tailscale.\nWith Tailscale [installed] on a machine, Caddy can already bind to the Tailscale network interface,\nproxy requests to other Tailnet nodes, get [automatic certificates], and [authenticate Tailscale users].\n\nHowever, there may be cases where it is inconvenient to install Tailscale on a machine,\nand it would be preferable to have everything self-contained in the single caddy binary.\nOr, you may want to serve multiple sites, each connected as a separate Tailnet node.\nIn those cases, this plugin may be helpful.\n\n[installed]: https://tailscale.com/download\n[automatic certificates]: https://caddyserver.com/docs/automatic-https#activation\n[authenticate Tailscale users]: https://caddyserver.com/docs/caddyfile/directives/forward_auth#tailscale\n\n## Building\n\nUse [xcaddy](https://github.com/caddyserver/xcaddy) to build Caddy with the Tailscale plugin included.\n\n```sh\nxcaddy build v2.9.1 --with github.com/tailscale/caddy-tailscale\n```\n\nAlternatively, you can build the included `cmd/caddy` package, or create your own similar package:\n\n```sh\ngo build ./cmd/caddy\n```\n\n### Docker Builds\n\nCaddy provides [builder docker images] (e.g. `caddy:2.9-builder`) that have xcaddy pre-installed.\nThese can be used to build caddy-tailscale in a docker container,\nbut may result in issues with the Go version used for the build due to project release cycles.\n\nThe caddy builder images are built with the specific Go version that was used for that Caddy version.\nIf a new version of Go has been released, that will not be reflected until a future Caddy release.\nTailscale, and by extension the caddy-tailscale plugin, adopts new Go versions much more quickly,\nwhich may result in a caddy-tailscale version requiring a more recent version of Go than is in the caddy builder image.\n\nThis can be addressed in two ways:\n\n1. don't use the caddy builder images directly, but install xcaddy in a newer Go build image\n   as [discussed in this comment].\n2. unset the `GOTOOLCHAIN` environment variable so that Go is able to upgrade itself:\n\n   ```sh\n   docker run -e GOTOOLCHAIN= -i -t --rm docker.io/caddy:2.9-builder sh -c \"xcaddy build --with github.com/tailscale/caddy-tailscale@fd3f49d73216641b9cbe9167bbb05250c0ffc6d6\"\n   ```\n\n[builder docker images]: https://hub.docker.com/_/caddy\n[discussed in this comment]: https://github.com/tailscale/caddy-tailscale/issues/34#issuecomment-2145764893\n\n### Running examples\n\nMultiple example configurations are provided in the [examples directory].\nThese examples expect an [auth key] to be set in the `TS_AUTHKEY` environment variable.\nAll nodes registered while running these examples will be ephemeral and removed after disconnect.\nSee the comments in the individual files for details.\n\nRun them with:\n\n```\nTS_AUTHKEY=\u003ctskey-auth-XXXXX\u003e ./caddy run -c examples/\u003cfile\u003e\n```\n\n[examples directory]: ./examples/\n\n## Configuration\n\nIn a [Caddyfile], use the `tailscale` [global option] to configure your Tailscale nodes.\nMost options can be set at the top-level, in which case they will apply to all nodes.\nThey can also be set for a specific named node, which override the top-level options.\nNamed node configurations can be referenced elsewhere in the caddy configuration.\n\nThe `tailscale` global option only defines configuration values for Tailscale nodes.\nNodes are not actually registered and connected to your tailnet until they are used,\nsuch as listening on the node's interface or using it as a proxy transport.\n\nString options support the use of [placeholders] to populate values dynamically,\nsuch as from an environment variable.\n\nSupported options are:\n\n```caddyfile\n{\n  tailscale {\n    # Tailscale auth key used to register nodes.\n    auth_key \u003cauth_key\u003e\n\n    # Alternate control server URL. Leave empty to use the default server.\n    control_url \u003ccontrol_url\u003e\n\n    # If true, register ephemeral nodes that are removed after disconnect.\n    # Default: false\n    ephemeral true|false\n\n    # Directory to store Tailscale state in. A subdirectory will be created for each node.\n    # The default is to store state in the user's config dir (see os.UserConfDir).\n    state_dir \u003cfilepath\u003e\n\n    # If true, run the Tailscale web UI for remotely managing the node. (https://tailscale.com/kb/1325)\n    # Default: false\n    webui true|false\n\n    # Any number of named node configs can be specified to override global options.\n    \u003cnode_name\u003e {\n      # Tailscale auth key used to register this node.\n      auth_key \u003cauth_key\u003e\n\n      # Alternate control server URL.\n      control_url \u003ccontrol_url\u003e\n\n      # If true, remove this node after disconnect.\n      ephemeral true|false\n\n      # Hostname to request when registering this node.\n      # Default: \u003cnode_name\u003e used for this node configuration\n      hostname \u003chostname\u003e\n\n      # Directory to store Tailscale state in for this node. No subdirectory is created.\n      state_dir \u003cfilepath\u003e\n\n      # If true, run the Tailscale web UI for remotely managing this node.\n      webui true|false\n    }\n  }\n}\n```\n\nAll configuration values are optional, though an [auth key] is strongly recommended.\nIf no auth key is present, one will be loaded from the default `$TS_AUTHKEY` environment variable.\nFailing that, it will log an auth URL to the Caddy log that can be used to register the node.\n\nUnless the node is registered as `ephemeral`, the auth key is only needed on first run.\nNode state is stored in `state_dir` and reused when Caddy restarts.\nWhen running in a container, it is generally recommended to use `ephemeral` and always provide an auth key,\nor to mount the state directory on a persistent volume, depending on the use case.\n\nFor Caddy [JSON config], add the `tailscale` app with fields from [tscaddy.App]:\n\n```json\n{\n  \"apps\": {\n    \"tailscale\": {\n      ...\n    }\n  }\n}\n```\n\n[Caddyfile]: https://caddyserver.com/docs/caddyfile\n[global option]: https://caddyserver.com/docs/caddyfile/options\n[placeholders]: https://caddyserver.com/docs/conventions#placeholders\n[auth key]: https://tailscale.com/kb/1085/auth-keys/\n[JSON config]: https://caddyserver.com/docs/json/\n[tscaddy.App]: https://pkg.go.dev/github.com/tailscale/caddy-tailscale#App\n\n### Logging\n\nTailscale logs as the `tailscale` named Caddy logger.\nTo customize logging level or output, use the [log global option]:\n\n```caddyfile\n{\n  log tailscale {\n    level DEBUG\n  }\n}\n```\n\n[log global option]: https://caddyserver.com/docs/caddyfile/options#log\n\n## Network listener\n\nThe provided network listener allows privately serving sites on your tailnet.\nConfigure a site block as usual, and use the [bind] directive to specify a tailscale network address:\n\n```caddyfile\n:80 {\n  bind tailscale/\n}\n```\n\nThe trailing slash is required.\nYou can also specify a named node configuration to use for the Tailscale node:\n\n```caddyfile\n:80 {\n  bind tailscale/myapp\n}\n```\n\nIf no node configuration is specified, a default configuration will be used,\nwhich names the node based on the name of the running binary (typically, `caddy`).\n\nIf using the Caddy JSON configuration, specify a \"tailscale/\" network in your listen address:\n\n```json\n{\n  \"apps\": {\n    \"http\": {\n      \"servers\": {\n        \"srv0\": {\n          \"listen\": [\"tailscale/myhost:80\"]\n        }\n      }\n    }\n  }\n}\n```\n\nCaddy will join your Tailscale network and listen only on that network interface.\nMultiple addresses can be specified if you want to listen on different Tailscale nodes as well as a local address:\n\n```caddyfile\n:80 {\n  bind tailscale/myhost tailscale/my-other-host localhost\n}\n```\n\nDifferent sites can be configured to join the network as different nodes:\n\n```caddyfile\n:80 {\n  bind tailscale/myhost\n}\n\n:80 {\n  bind tailscale/my-other-host\n}\n```\n\nOr they can be served on different ports of the same Tailscale node:\n\n```caddyfile\n:80 {\n  bind tailscale/myhost\n}\n\n:8080 {\n  bind tailscale/myhost\n}\n```\n\n[bind]: https://caddyserver.com/docs/caddyfile/directives/bind\n\n### HTTPS support\n\nCaddy's automatic HTTPS support can be used with the Tailscale network listener like any other site.\nCaddy will use [Tailscale's HTTPS support] to issue certificates for your node's hostname.\nIf the site address includes the full `ts.net` hostname, no additional configuration is necessary:\n\n```caddyfile\nhttps://myhost.tail1234.ts.net {\n  bind tailscale/myhost\n}\n```\n\nIf the site address does not include the full hostname, specify the `tailscale` cert manager:\n\n```caddyfile\n:443 {\n  bind tailscale/myhost\n  tls {\n    get_certificate tailscale\n  }\n}\n```\n\nThis plugin previously used a `tailcale+tls` network listener that required disabling caddy's `auto_https` feature.\nThat is no longer required nor recommended and will be removed in a future version.\n\n[Tailscale's HTTPS support]: https://tailscale.com/kb/1153/enabling-https\n\n## Authentication provider\n\nSet up the Tailscale authentication provider with the `tailscale_auth` directive.\nThe provider will enforce that all requests are coming from a Tailscale user,\nas well as set various fields on the Caddy user object that can be passed to applications.\nFor sites listening only on the Tailscale network interface,\nuser access will already be enforced by the tailnet access controls.\nThe authentication provider currently only works with connections from user-owned devices.\nIt does not currently support connections from [tagged devices].\n\nFor example, in a Caddyfile:\n\n```caddyfile\n:80 {\n  tailscale_auth\n}\n```\n\nThe following fields are set on the Caddy user object:\n\n- `user.id`: the Tailscale email-ish user ID\n- `user.tailscale_login`: the username portion of the Tailscale user ID\n- `user.tailscale_user`: same as `user.id`\n- `user.tailscale_name`: the display name of the Tailscale user\n- `user.tailscale_profile_picture`: the URL of the Tailscale user's profile picture\n- `user.tailscale_tailnet`: the name of the Tailscale network the user is a member of\n\nThese values can be mapped to HTTP headers that are then passed to\nan application that supports proxy authentication such as [Gitea] or [Grafana].\nYou might have something like the following in your Caddyfile:\n\n```caddyfile\n:80 {\n  bind tailscale/gitea\n  tailscale_auth\n  reverse_proxy http://localhost:3000 {\n    header_up X-Webauth-User {http.auth.user.tailscale_login}\n    header_up X-Webauth-Email {http.auth.user.tailscale_user}\n    header_up X-Webauth-Name {http.auth.user.tailscale_name}\n  }\n}\n```\n\nWhen used with a Tailscale listener (described above), that Tailscale node is used to identify the remote user.\nOtherwise, the authentication provider will attempt to connect to the Tailscale daemon running on the local machine.\n\n[tagged devices]: https://tailscale.com/kb/1068/acl-tags\n[Gitea]: https://docs.gitea.com/usage/authentication#reverse-proxy\n[Grafana]: https://grafana.com/docs/grafana/latest/setup-grafana/configure-security/configure-authentication/auth-proxy/\n\n## Proxy Transport\n\nThe `tailscale` proxy transport allows using a Tailscale node to connect to a reverse proxy upstream.\nThis might be useful to proxy non-Tailscale traffic to a node on your tailnet, similar to [Funnel].\n\nYou can specify a named node configuration, or a default `caddy-proxy` node will be used.\n\n```caddyfile\n:8080 {\n  reverse_proxy http://my-other-node:10000 {\n    transport tailscale myhost\n  }\n}\n```\n\nNote that the node name is separated by a space, rather than a slash, as in the network listener.\n\n[Funnel]: https://tailscale.com/kb/1223/funnel\n\n## tailscale-proxy subcommand\n\nThe Tailscale Caddy plugin also includes a `tailscale-proxy` subcommand that\nsets up a simple reverse proxy that can optionally join your Tailscale network,\nand will enforce Tailscale authentication and map user values to HTTP headers.\n\nFor example:\n\n```sh\nxcaddy tailscale-proxy --from \"tailscale/myhost:80\" --to localhost:8000\n```\n\n(The `tailscale-proxy` subcommand does not yet work with the tailscale proxy transport.)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftailscale%2Fcaddy-tailscale","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftailscale%2Fcaddy-tailscale","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftailscale%2Fcaddy-tailscale/lists"}