From 72adc5ff2a9d83a4792a94b861f707c5f03e2bb6 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Fri, 19 Jun 2026 06:14:55 +0000 Subject: [PATCH] docs: add changelog and refresh the API reference for the v1 API --- CHANGELOG.md | 28 ++++++++++++++++++++++++++ cmd/dev/README.md | 3 +-- docs/about/faq.md | 6 +++--- docs/ref/api.md | 29 ++++++++++++--------------- docs/ref/integration/reverse-proxy.md | 5 +---- docs/setup/requirements.md | 3 --- 6 files changed, 46 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6630e6c3..82f8251c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,34 @@ **Minimum supported Tailscale client version: v1.xx.0** +### v1 REST API replaced; gRPC and Protobuf removed + +The v1 REST API now provides an OpenAPI 3.1 specification at +`/api/v1/openapi.yaml`, with interactive documentation at `/api/v1/docs`. This +replaces the Swagger 2.0 document and the `/swagger` UI. The Protobuf, gRPC and +grpc-gateway stack behind it is gone, and the `headscale` CLI now talks to the +HTTP API directly. + +[#3324](https://github.com/juanfont/headscale/pull/3324) + +### BREAKING + +#### API + +- The gRPC API is removed; all programmatic access now goes through the HTTP API at `/api/v1` [#3324](https://github.com/juanfont/headscale/pull/3324) +- API errors are now RFC 7807 `application/problem+json`, including authentication failures, instead of the previous gRPC-status JSON shape [#3324](https://github.com/juanfont/headscale/pull/3324) +- Errors that previously returned HTTP 500 — unknown users or nodes, malformed input, duplicate names — now return the correct 404, 400 or 409 [#3324](https://github.com/juanfont/headscale/pull/3324) +- The OpenAPI document is OpenAPI 3.1 at `/api/v1/openapi.yaml` (docs at `/api/v1/docs`), replacing Swagger 2.0 at `/swagger` [#3324](https://github.com/juanfont/headscale/pull/3324) + +#### CLI + +- `--output json` / `--output yaml` now emit the API's shape — camelCase fields, string-encoded IDs, RFC3339 timestamps — instead of the old Protobuf encoding [#3324](https://github.com/juanfont/headscale/pull/3324) +- `headscale policy` renames the database-bypass flag from `--bypass-grpc-and-access-database-directly` to `--bypass-server-and-access-database-directly` [#3324](https://github.com/juanfont/headscale/pull/3324) + +### Changes + +- Expiring or deleting a non-existent pre-auth key now returns an error instead of silently succeeding [#3324](https://github.com/juanfont/headscale/pull/3324) + ## 0.29.1 (2026-06-18) **Minimum supported Tailscale client version: v1.80.0** diff --git a/cmd/dev/README.md b/cmd/dev/README.md index 46da415d..f703f442 100644 --- a/cmd/dev/README.md +++ b/cmd/dev/README.md @@ -42,8 +42,7 @@ go tool mts node1 status | `--port` | 8080 | Headscale listen port | | `--keep` | false | Keep state directory on exit | -The metrics/debug port is `port + 1010` (default 9090) and the gRPC -port is `port + 42363` (default 50443). +The metrics/debug port is `port + 1010` (default 9090). ## What it does diff --git a/docs/about/faq.md b/docs/about/faq.md index 09792653..25cdb112 100644 --- a/docs/about/faq.md +++ b/docs/about/faq.md @@ -152,15 +152,15 @@ See also . Headscale checks if the policy is valid during startup and refuses to start if it detects an error. The error message indicates which part of the policy is invalid. Follow these steps to fix your policy: -- Dump the policy to a file: `headscale policy get --bypass-grpc-and-access-database-directly > policy.json` +- Dump the policy to a file: `headscale policy get --bypass-server-and-access-database-directly > policy.json` - Edit and fixup `policy.json`. Use the command `headscale policy check --file policy.json` to validate the policy. -- Load the modified policy: `headscale policy set --bypass-grpc-and-access-database-directly --file policy.json` +- Load the modified policy: `headscale policy set --bypass-server-and-access-database-directly --file policy.json` - Start Headscale as usual. !!! warning "Full server configuration required" The above commands to get/set the policy require a complete server configuration file including database settings. A - minimal config to [control Headscale via remote CLI](../ref/api.md#grpc) is not sufficient. You may use + minimal config to [control Headscale via remote CLI](../ref/api.md#remote-control) is not sufficient. You may use `headscale -c /path/to/config.yaml` to specify the path to an alternative configuration file. ## How can I migrate back to the recommended IP prefixes? diff --git a/docs/ref/api.md b/docs/ref/api.md index 4337da13..5e3677f8 100644 --- a/docs/ref/api.md +++ b/docs/ref/api.md @@ -1,10 +1,10 @@ # API -Headscale provides a [HTTP REST API](#rest-api) and a [gRPC interface](#grpc) which may be used to integrate a [web -interface](integration/web-ui.md), [remote control Headscale](#setup-remote-control) or provide a base for custom +Headscale provides a [HTTP REST API](#rest-api) which may be used to integrate a [web +interface](integration/web-ui.md), [remote control Headscale](#remote-control) or provide a base for custom integration and tooling. -Both interfaces require a valid API key before use. To create an API key, log into your Headscale server and generate +The API requires a valid API key before use. To create an API key, log into your Headscale server and generate one with the default expiration of 90 days: ```shell @@ -58,15 +58,14 @@ Headscale server at `/swagger` for details. https://headscale.example.com/api/v1/auth/register ``` -## gRPC +## Remote control -The gRPC interface can be used to control a Headscale instance from a remote machine with the `headscale` binary. +The `headscale` binary can control a Headscale instance from a remote machine over the HTTP API. ### Prerequisite - A workstation to run `headscale` (any supported platform, e.g. Linux). -- A Headscale server with gRPC enabled. -- Connections to the gRPC port (default: `50443`) are allowed. +- The Headscale server reachable over HTTP(S). - Remote access requires an encrypted connection via TLS. - An [API key](#api) to authenticate with the Headscale server. @@ -88,19 +87,20 @@ The gRPC interface can be used to control a Headscale instance from a remote mac ```yaml title="config.yaml" cli: - address: : + address: api_key: ``` === "Environment variables" ```shell - export HEADSCALE_CLI_ADDRESS=":" + export HEADSCALE_CLI_ADDRESS="" export HEADSCALE_CLI_API_KEY="" ``` - This instructs the `headscale` binary to connect to a remote instance at `:`, instead of - connecting to the local instance. + This instructs the `headscale` binary to connect to a remote instance at `` (e.g. + `https://headscale.example.com`), instead of connecting to the local instance. A bare host without a scheme is + assumed to be `https`. 1. Test the connection by listing all nodes: @@ -113,15 +113,12 @@ The gRPC interface can be used to control a Headscale instance from a remote mac ### Behind a proxy -It's possible to run the gRPC remote endpoint behind a reverse proxy, like Nginx, and have it run on the _same_ port as Headscale. - -While this is _not a supported_ feature, an example on how this can be set up on -[NixOS is shown here](https://github.com/kradalby/dotfiles/blob/4489cdbb19cddfbfae82cd70448a38fde5a76711/machines/headscale.oracldn/headscale.nix#L61-L91). +The remote CLI uses the same HTTP API as everything else, so it works through the reverse proxy already in front of +Headscale with no extra setup. ### Troubleshooting - Make sure you have the _same_ Headscale version on your server and workstation. -- Ensure that connections to the gRPC port are allowed. - Verify that your TLS certificate is valid and trusted. - If you don't have access to a trusted certificate (e.g. from Let's Encrypt), either: - Add your self-signed certificate to the trust store of your OS _or_ diff --git a/docs/ref/integration/reverse-proxy.md b/docs/ref/integration/reverse-proxy.md index 723ef634..2729786a 100644 --- a/docs/ref/integration/reverse-proxy.md +++ b/docs/ref/integration/reverse-proxy.md @@ -69,7 +69,6 @@ on inbound requests with sanitized values. Headscale picks the first valid IP ad - A reverse proxy adds another layer of complexity that needs to be able to handle the [Tailscale Control Protocol](#websocket) properly. Be sure to test your setup without a reverse proxy before raising an issue. - STUN (used along with the [embedded DERP server](../derp.md)) requires udp/3478 to be served publicly. -- [gRPC](../api.md#grpc) (used to remote control Headscale) may not be proxied. ## Reverse proxy specific configuration @@ -84,14 +83,12 @@ is [assumed](../../setup/requirements.md): - Service for Tailscale clients is served via HTTPS on port 443. - The reverse proxy redirects HTTP to HTTPS and is terminating TLS. - Both Headscale and the reverse proxy are running on the same host. -- [Metrics](../debug.md#metrics-and-debug-endpoint) and [gRPC](../api.md#grpc) are not proxied, those are available via - localhost. +- [Metrics](../debug.md#metrics-and-debug-endpoint) are not proxied, those are available via localhost. ```yaml title="config.yaml" hl_lines="1" server_url: https:// listen_addr: 127.0.0.1:8080 metrics_listen_addr: 127.0.0.1:9090 -grpc_listen_addr: 127.0.0.1:50443 trusted_proxies: - 127.0.0.1/32 - ::1/128 diff --git a/docs/setup/requirements.md b/docs/setup/requirements.md index 6c11386c..da84ae85 100644 --- a/docs/setup/requirements.md +++ b/docs/setup/requirements.md @@ -26,9 +26,6 @@ The ports in use vary with the intended scenario and enabled features. Some of t - udp/3478 - Expose publicly: yes - STUN, required if the [embedded DERP server](../ref/derp.md) is enabled -- tcp/50443 - - Expose publicly: yes - - Only required if the gRPC interface is used to [remote-control Headscale](../ref/api.md#grpc). - tcp/9090 - Expose publicly: no - [Metrics and debug endpoint](../ref/debug.md#metrics-and-debug-endpoint)