Skip to content

[Feature Request] tailscale: add control_websocket option for coordination servers behind CDNs / Cloudflare #4504

Description

@hluwa

Background & Problem

Tailscale clients establish their coordination control plane session (TS2021) by making an HTTP POST /ts2021 request with non-standard upgrade
headers:

POST /ts2021 HTTP/1.1
Upgrade: tailscale-control-protocol
Connection: upgrade
X-Tailscale-Handshake: <base64>

When self-hosting a coordination server (e.g. Headscale) behind CDNs or restrictive reverse proxies (such as Cloudflare Tunnel / Cloudflare Proxy):

  1. RFC 6455 Violation: RFC 6455 Section 4.1 (https://datatracker.ietf.org/doc/html/rfc6455#section-4.1) mandates that the WebSocket upgrade
    handshake must use the GET method.
  2. Upgrade Header Filtering: Cloudflare and similar edge proxies strictly filter WebSocket upgrade requests. They drop non-GET upgrades and only
    accept standard Upgrade: websocket. Any non-standard Upgrade: tailscale-control-protocol sent with POST is immediately rejected with an HTTP
    error (e.g. 500 Internal Server Error or 405 Method Not Allowed).

This limitation is well documented across the community:

Tailscale's repository actually already contains native WebSocket tunneling implementations (control/controlhttp/client_js.go, net/wsconn, and
controlhttpserver.acceptWebsocket), but it is only compiled in for js/wasm targets.

Proposed Solution

Add a control_websocket boolean option to TailscaleEndpointOptions:

{
 "type": "tailscale",
 "tag": "ts-ep",
 "control_url": "https://headscale.example.com",
 "control_websocket": true
}

Reference Implementation

A fully verified and tested implementation is available on my fork:

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions