[Bug] metrics_listen_addr set to "" results in metrics listening on random port #1143

Closed
opened 2025-12-29 02:28:31 +01:00 by adam · 0 comments
Owner

Originally created by @vikanezrimaya on GitHub (Nov 10, 2025).

Is this a support request?

  • This is not a support request

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Headscale with metrics_listen_addr: "" in the config listens on an ephemeral port for metrics.

Expected Behavior

metrics_listen_addr: "" should kill metrics. Alternatively, there should be a knob in the config to kill the metrics listener.

Steps To Reproduce

  1. Set metrics_listen_addr: ""
  2. Launch headscale
  3. lsof -i -a -p $(pidof headscale), observe a second listener
  4. curl localhost:$PORT/metrics, observe metrics endpoint being available

Environment

- OS: NixOS unstable
- Headscale version: 0.26.1
- Tailscale version: n/a

Runtime environment

  • Headscale is behind a (reverse) proxy n/a
  • Headscale runs in a container

Debug information Additional context

In hscontrol/app.go:

    debugHTTPListener, err := net.Listen("tcp", h.cfg.MetricsAddr)
    if err != nil {
        return fmt.Errorf("failed to bind to TCP address: %w", err)
    }

    debugHTTPServer := h.debugHTTPServer()
    errorGroup.Go(func() error { return debugHTTPServer.Serve(debugHTTPListener) })

    log.Info().
        Msgf("listening and serving debug and metrics on: %s", h.cfg.MetricsAddr)

It looks like net.Listen picks an ephemeral port and listens on all interfaces if passed an empty string as an address, instead of failing to parse and bailing out. (This is probably because Go considers not distinguishing between nulls and empty values an intentional language design feature.)

This codepath should probably be guarded behind a null-check. Accordingly, the shutdown should check if the server was started and not try to stop it in this case (I have no idea what happens in Go if you do this).

Originally created by @vikanezrimaya on GitHub (Nov 10, 2025). ### Is this a support request? - [x] This is not a support request ### Is there an existing issue for this? - [x] I have searched the existing issues ### Current Behavior Headscale with `metrics_listen_addr: ""` in the config listens on an ephemeral port for metrics. ### Expected Behavior `metrics_listen_addr: ""` should kill metrics. Alternatively, there should be a knob in the config to kill the metrics listener. ### Steps To Reproduce 1. Set `metrics_listen_addr: ""` 2. Launch headscale 3. `lsof -i -a -p $(pidof headscale)`, observe a second listener 4. `curl localhost:$PORT/metrics`, observe metrics endpoint being available ### Environment ```markdown - OS: NixOS unstable - Headscale version: 0.26.1 - Tailscale version: n/a ``` ### Runtime environment - [ ] ~~Headscale is behind a (reverse) proxy~~ n/a - [ ] Headscale runs in a container ### ~~Debug information~~ Additional context In [hscontrol/app.go](https://github.com/juanfont/headscale/blob/2024219bd10adbb5c0d29f900ed0961ace8cc15c/hscontrol/app.go#L732): ```go debugHTTPListener, err := net.Listen("tcp", h.cfg.MetricsAddr) if err != nil { return fmt.Errorf("failed to bind to TCP address: %w", err) } debugHTTPServer := h.debugHTTPServer() errorGroup.Go(func() error { return debugHTTPServer.Serve(debugHTTPListener) }) log.Info(). Msgf("listening and serving debug and metrics on: %s", h.cfg.MetricsAddr) ``` It looks like `net.Listen` picks an ephemeral port and listens on all interfaces if passed an empty string as an address, instead of failing to parse and bailing out. (This is probably because Go considers not distinguishing between nulls and empty values an intentional language design feature.) This codepath should probably be guarded behind a null-check. Accordingly, the shutdown should check if the server was started and not try to stop it in this case (I have no idea what happens in Go if you do this).
adam added the bughelp wantedgood first issueno-stale-bot labels 2025-12-29 02:28:31 +01:00
adam closed this issue 2025-12-29 02:28:31 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/headscale#1143