Headscale Control Server On Loopback, Proven By A Pre-Auth Key

Headscale, the self-hosted Tailscale control server, from the upstream release binary (sha256-verified) as a hardened system service on loopback with sqlite; configtest runs as the service user (it opens the database). The live test creates a user over the unix socket, issues a reusable pre-auth key for it, reads the user back from the key, destroys it. Original role, live-tested on Rocky 10.

ansibleNetworking & VPC

Verification

Live-tested

Really deployed to a container sandbox, proven idempotent (a second run changes nothing), verified against the role’s assertions, then torn down.

Conformance

  • Static validation (yamllint · ansible-lint)

Provenance

  • SHA-256 checksum
  • Signature (pending)

Functional

  • Live-tested - applied, verified, destroyed

Last verified 2026-09-20 · podman 4.9.3 · ansible 2.21.4 · how we verify

Cite it in your README

badge · attribution

Paste this beside the module in the repository that uses it. The badge is rendered from this artifact's verification record, so it reads live-tested because the record says so, and the link lands on this page.

README.md, GitLab, Gitea
[![IaC Bazaar: live-tested](https://www.iac-bazaar.com/api/artifacts/ansible-headscale/badge)](https://www.iac-bazaar.com/catalog/ansible-headscale?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)

Ansible role 1.0.0, live-tested on IaC Bazaar: [Headscale Control Server On Loopback, Proven By A Pre-Auth Key](https://www.iac-bazaar.com/catalog/ansible-headscale?utm_source=syndication&utm_medium=readme&utm_campaign=artifact)

```yaml
# Headscale Control Server On Loopback, Proven By A Pre-Auth Key: https://www.iac-bazaar.com/catalog/ansible-headscale (download from your IaC Bazaar account)
```

Preview:IaC Bazaar: live-tested

Documentation

headscale

Headscale, the self-hosted Tailscale control server, from the upstream release binary (sha256-verified), as a hardened system service on loopback with sqlite, for a proxy that terminates TLS. Original role for EL 10, live-tested with podman on Rocky Linux 10.

No package, so the checksum is the whole story. EL 10 carries no headscale; Headscale ships a release with a checksum file beside it. The role downloads both and has Ansible's get_url refuse the binary unless its SHA-256 is the one in the vendor's file, then installs it as root's in /usr/local/bin, pinned by headscale_version.

A service account, a hardened unit, a loopback listener. headscale is a system user with no shell that owns the data directory and nothing else; the unit runs with NoNewPrivileges, PrivateTmp, ProtectHome and ProtectSystem=strict. The listener is 127.0.0.1:8080 by default, for a proxy that authenticates or a client on the same host; the live test reads the listening sockets and expects loopback only.

configtest runs as the service. headscale configtest opens the database and creates the noise private key while it checks the file, so run by root (the obvious validate:) it leaves root-owned files in the data directory and the service dies at start unable to read them. The role runs it as the headscale user after the file lands, before the unit is touched. Two keys the older guides show, randomize_client_port and ephemeral_node_inactivity_timeout, were removed in 0.29 and refuse the start; the role writes the current shape.

Proven by a key. The live test creates a user through the CLI over the unix socket, lists the users back as JSON, issues a reusable pre-authentication key for that user (the thing a new node joins with), reads the user's name back from the key, and destroys the user. The listener is loopback; headscale_server_url is what clients are told, so behind the proxy it is the public https address. Metrics are on 127.0.0.1:9090, the vendor's default and Prometheus's port: change one if both run on a host.

License

Commercial - IaC Bazaar EULA. (c) IaC Bazaar.

Usage code & full reference need an account

The complete copy-paste usage, the full input/output reference, and operational notes are free with an account - shown here and bundled in the download. Sign in and this section fills in.

  • Variables
  • Test

Related modules

Live-tested

ansible-squid

The stock squid.conf allows localhost before it denies loopback destinations, so a local client can proxy into loopback services. This role puts every deny first and binds loopback. The live test fetches a page through it, then sees squid itself refuse loopback, 169.254.169.254, an unsafe port, CONNECT to 25 and a non-loopback client. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-consul-server

HashiCorp Consul as a single-node server from the upstream release (sha256-verified), as a hardened system service with HTTP, DNS, RPC and both serf listeners on loopback and its configuration checked by consul validate before it lands. The live test waits for a leader, writes a KV key through the API, reads it back and reads the member alive. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-dante

Dante SOCKS5 server from EPEL for the accounts the role makes, and only those: each expired for every other service, since its password otherwise opened SSH tunnels, and private, link-local and loopback ranges out of reach by address or by name. The live test is refused by each range, another account and SSH. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-frr

FRR from AppStream: BGP that announces only your prefixes, accepts from each neighbour only what you list for it, signs sessions with TCP MD5, and applies a change without dropping them. The live test peers with a real BGP speaker in its own namespace; a filtered prefix stays out of the kernel and a wrong password keeps the session down. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-kea-dhcp4

Kea DHCPv4 from AppStream: your subnets, pools, options and reservations in Kea's own keys, checked with kea-dhcp4 -t and applied by reload, leases on disk. The live test runs a raw-socket DHCP client in a namespace: an address with router, DNS and lease time, the reserved address for its MAC, and nothing on a segment no subnet covers. Original role, live-tested on Rocky Linux 10.

View module
Live-tested

ansible-libreswan

Libreswan from AppStream: IPsec connections authenticated by a pre-shared key made on the host, negotiated with IKEv2 under the system crypto policy, IKE kept to one address, each connection checked by its keywords and again by pluto. The live test brings a peer in a namespace up, sees the ping cross as ESP only, and is refused with a different key. Original role, live-tested on Rocky Linux 10.

View module