---# headscale will look for a configuration file named `config.yaml` (or `config.json`) in the following order:## - `/etc/headscale`# - `~/.headscale`# - current working directory# The url clients will connect to.# Typically this will be a domain like:## https://myheadscale.example.com:443#server_url:https://<headscale.example.com># Address to listen to / bind to on the server## For production:listen_addr:0.0.0.0:8080#listen_addr: 127.0.0.1:8080# Address to listen to /metrics, you may want# to keep this endpoint private to your internal# network#metrics_listen_addr:127.0.0.1:9090# Address to listen for gRPC.# gRPC is used for controlling a headscale server# remotely with the CLI# Note: Remote access _only_ works if you have# valid certificates.## For production:grpc_listen_addr:0.0.0.0:50443#grpc_listen_addr: 127.0.0.1:50443# Allow the gRPC admin interface to run in INSECURE# mode. This is not recommended as the traffic will# be unencrypted. Only enable if you know what you# are doing.grpc_allow_insecure:false# The Noise section includes specific configuration for the# TS2021 Noise protocolnoise:# The Noise private key is used to encrypt the# traffic between headscale and Tailscale clients when# using the new Noise-based protocol.private_key_path:/var/lib/headscale/noise_private.key# List of IP prefixes to allocate tailaddresses from.# Each prefix consists of either an IPv4 or IPv6 address,# and the associated prefix length, delimited by a slash.# It must be within IP ranges supported by the Tailscale# client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48.# See below:# IPv6: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#LL81C52-L81C71# IPv4: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#L33# Any other range is NOT supported, and it will cause unexpected issues.prefixes:v4:100.64.0.0/10v6:fd7a:115c:a1e0::/48# Strategy used for allocation of IPs to nodes, available options:# - sequential (default): assigns the next free IP from the previous given IP.# - random: assigns the next free IP from a pseudo-random IP generator (crypto/rand).allocation:sequential# DERP is a relay system that Tailscale uses when a direct# connection cannot be established.# https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp## headscale needs a list of DERP servers that can be presented# to the clients.derp:server:# If enabled, runs the embedded DERP server and merges it into the rest of the DERP config# The Headscale server_url defined above MUST be using https, DERP requires TLS to be in placeenabled:false# Region ID to use for the embedded DERP server.# The local DERP prevails if the region ID collides with other region ID coming from# the regular DERP config.region_id:999# Region code and name are displayed in the Tailscale UI to identify a DERP regionregion_code:"headscale"region_name:"Headscale Embedded DERP"# Listens over UDP at the configured address for STUN connections - to help with NAT traversal.# When the embedded DERP server is enabled stun_listen_addr MUST be defined.## For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/stun_listen_addr:"0.0.0.0:3478"# Private key used to encrypt the traffic between headscale DERP# and Tailscale clients.# The private key file will be autogenerated if it's missing.#private_key_path:/var/lib/headscale/derp_server_private.key# This flag can be used, so the DERP map entry for the embedded DERP server is not written automatically,# it enables the creation of your very own DERP map entry using a locally available file with the parameter DERP.paths# If you enable the DERP server and set this to false, it is required to add the DERP server to the DERP map using DERP.pathsautomatically_add_embedded_derp_region:true# For better connection stability (especially when using an Exit-Node and DNS is not working),# it is possible to optionally add the public IPv4 and IPv6 address to the Derp-Map using:ipv4:1.2.3.4ipv6:2001:db8::1# List of externally available DERP maps encoded in JSONurls:- https://controlplane.tailscale.com/derpmap/default# Locally available DERP map files encoded in YAML## This option is mostly interesting for people hosting# their own DERP servers:# https://tailscale.com/kb/1118/custom-derp-servers/## paths:# - /etc/headscale/derp-example.yamlpaths:[]# If enabled, a worker will be set up to periodically# refresh the given sources and update the derpmap# will be set up.auto_update_enabled:true# How often should we check for DERP updates?update_frequency:24h# Disables the automatic check for headscale updates on startupdisable_check_updates:false# Time before an inactive ephemeral node is deleted?ephemeral_node_inactivity_timeout:30mdatabase:# Database type. Available options: sqlite, postgres# Please note that using Postgres is highly discouraged as it is only supported for legacy reasons.# All new development, testing and optimisations are done with SQLite in mind.type:sqlite# Enable debug mode. This setting requires the log.level to be set to "debug" or "trace".debug:false# GORM configuration settings.gorm:# Enable prepared statements.prepare_stmt:true# Enable parameterized queries.parameterized_queries:true# Skip logging "record not found" errors.skip_err_record_not_found:true# Threshold for slow queries in milliseconds.slow_threshold:1000# SQLite configsqlite:path:/var/lib/headscale/db.sqlite# Enable WAL mode for SQLite. This is recommended for production environments.# https://www.sqlite.org/wal.htmlwrite_ahead_log:true# Maximum number of WAL file frames before the WAL file is automatically checkpointed.# https://www.sqlite.org/c3ref/wal_autocheckpoint.html# Set to 0 to disable automatic checkpointing.wal_autocheckpoint:1000# # Postgres config# Please note that using Postgres is highly discouraged as it is only supported for legacy reasons.# See database.type for more information.# postgres:# # If using a Unix socket to connect to Postgres, set the socket path in the 'host' field and leave 'port' blank.# host: localhost# port: 5432# name: headscale# user: foo# pass: bar# max_open_conns: 10# max_idle_conns: 10# conn_max_idle_time_secs: 3600# # If other 'sslmode' is required instead of 'require(true)' and 'disabled(false)', set the 'sslmode' you need# # in the 'ssl' field. Refers to https://www.postgresql.org/docs/current/libpq-ssl.html Table 34.1.# ssl: false### TLS configuration### Let's encrypt / ACME## headscale supports automatically requesting and setting up# TLS for a domain with Let's Encrypt.## URL to ACME directoryacme_url:https://acme-v02.api.letsencrypt.org/directory# Email to register with ACME provideracme_email:""# Domain name to request a TLS certificate for:tls_letsencrypt_hostname:""# Path to store certificates and metadata needed by# letsencrypt# For production:tls_letsencrypt_cache_dir:/var/lib/headscale/cache# Type of ACME challenge to use, currently supported types:# HTTP-01 or TLS-ALPN-01# See: docs/ref/tls.md for more informationtls_letsencrypt_challenge_type:HTTP-01# When HTTP-01 challenge is chosen, letsencrypt must set up a# verification endpoint, and it will be listening on:# :http = port 80tls_letsencrypt_listen:":http"## Use already defined certificates:tls_cert_path:""tls_key_path:""log:# Output formatting for logs: text or jsonformat:textlevel:info## Policy# headscale supports Tailscale's ACL policies.# Please have a look to their KB to better# understand the concepts: https://tailscale.com/kb/1018/acls/policy:# The mode can be "file" or "database" that defines# where the ACL policies are stored and read from.mode:file# If the mode is set to "file", the path to a# HuJSON file containing ACL policies.path:""## DNS## headscale supports Tailscale's DNS configuration and MagicDNS.# Please have a look to their KB to better understand the concepts:## - https://tailscale.com/kb/1054/dns/# - https://tailscale.com/kb/1081/magicdns/# - https://tailscale.com/blog/2021-09-private-dns-with-magicdns/## Please note that for the DNS configuration to have any effect,# clients must have the `--accept-dns=true` option enabled. This is the# default for the Tailscale client. This option is enabled by default# in the Tailscale client.## Setting _any_ of the configuration and `--accept-dns=true` on the# clients will integrate with the DNS manager on the client or# overwrite /etc/resolv.conf.# https://tailscale.com/kb/1235/resolv-conf## If you want stop Headscale from managing the DNS configuration# all the fields under `dns` should be set to empty values.dns:# Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/).magic_dns:true# Defines the base domain to create the hostnames for MagicDNS.# This domain _must_ be different from the server_url domain.# `base_domain` must be a FQDN, without the trailing dot.# The FQDN of the hosts will be# `hostname.base_domain` (e.g., _myhost.example.com_).base_domain:<hs.example.com># List of DNS servers to expose to clients.nameservers:global:- 1.1.1.1- 1.0.0.1- 2606:4700:4700::1111- 2606:4700:4700::1001# NextDNS (see https://tailscale.com/kb/1218/nextdns/).# "abc123" is example NextDNS ID, replace with yours.# - https://dns.nextdns.io/abc123# Split DNS (see https://tailscale.com/kb/1054/dns/),# a map of domains and which DNS server to use for each.split:{}# foo.bar.com:# - 1.1.1.1# darp.headscale.net:# - 1.1.1.1# - 8.8.8.8# Set custom DNS search domains. With MagicDNS enabled,# your tailnet base_domain is always the first search domain.search_domains:[]# Extra DNS records# so far only A and AAAA records are supported (on the tailscale side)# See: docs/ref/dns.mdextra_records:[]# - name: "grafana.myvpn.example.com"# type: "A"# value: "100.64.0.3"## # you can also put it in one line# - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" }## Alternatively, extra DNS records can be loaded from a JSON file.# Headscale processes this file on each change.# extra_records_path: /var/lib/headscale/extra-records.json# Unix socket used for the CLI to connect without authentication# Note: for production you will want to set this to something like:unix_socket:/var/run/headscale/headscale.sockunix_socket_permission:"0770"## headscale supports experimental OpenID connect support,# it is still being tested and might have some bugs, please# help us test it.# OpenID Connectoidc:only_start_if_oidc_is_available:trueissuer:"https://your-oidc.issuer.com/path"client_id:"your-oidc-client-id"client_secret:"your-oidc-client-secret"# Alternatively, set `client_secret_path` to read the secret from the file.# It resolves environment variables, making integration to systemd's# `LoadCredential` straightforward:# client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"# # client_secret and client_secret_path are mutually exclusive.# The amount of time from a node is authenticated with OpenID until it# expires and needs to reauthenticate.# Setting the value to "0" will mean no expiry.expiry:180d# Use the expiry from the token received from OpenID when the user logged# in, this will typically lead to frequent need to reauthenticate and should# only been enabled if you know what you are doing.# Note: enabling this will cause `oidc.expiry` to be ignored.use_expiry_from_token:false# Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query# parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email".scope:["openid","profile","email"]# extra_params:# domain_hint: example.com## # List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the# # authentication request will be rejected.## allowed_domains:# - example.com# # Note: Groups from keycloak have a leading '/'# allowed_groups:# - /headscale# allowed_users:# - [email protected]## # Optional: PKCE (Proof Key for Code Exchange) configuration# # PKCE adds an additional layer of security to the OAuth 2.0 authorization code flow# # by preventing authorization code interception attacks# # See https://datatracker.ietf.org/doc/html/rfc7636# pkce:# # Enable or disable PKCE support (default: false)# enabled: false# # PKCE method to use:# # - plain: Use plain code verifier# # - S256: Use SHA256 hashed code verifier (default, recommended)# method: S256## # Map legacy users from pre-0.24.0 versions of headscale to the new OIDC users# # by taking the username from the legacy user and matching it with the username# # provided by the OIDC. This is useful when migrating from legacy users to OIDC# # to force them using the unique identifier from the OIDC and to give them a# # proper display name and picture if available.# # Note that this will only work if the username from the legacy user is the same# # and there is a possibility for account takeover should a username have changed# # with the provider.# # When this feature is disabled, it will cause all new logins to be created as new users.# # Note this option will be removed in the future and should be set to false# # on all new installations, or when all users have logged in with OIDC once.# map_legacy_users: false# Logtail configuration# Logtail is Tailscales logging and auditing infrastructure, it allows the control panel# to instruct tailscale nodes to log their activity to a remote server.logtail:# Enable logtail for this headscales clients.# As there is currently no support for overriding the log server in headscale, this is# disabled by default. Enabling this will make your clients send logs to Tailscale Inc.enabled:false# Enabling this option makes devices prefer a random port for WireGuard traffic over the# default static port 41641. This option is intended as a workaround for some buggy# firewall devices. See https://tailscale.com/kb/1181/firewalls/ for more information.randomize_client_port:false
server:host:"0.0.0.0"port:3000cookie_secret:"32-character-long-random-string"cookie_secure:falseheadscale:url:"https://<headscale.example.com>"config_path:"/etc/headscale/config.yaml"config_strict:trueintegration:docker:enabled:truecontainer_name:"headscale"socket:"unix:///var/run/docker.sock"oidc:issuer:"https://<authelia.example.com>"client_id:"headplane"# The client secret for the OIDC client# Either this or `client_secret_path` must be set for OIDC to workclient_secret:"some-random-client-secret"# You can alternatively set `client_secret_path` to read the secret from disk.# The path specified can resolve environment variables, making integration# with systemd's `LoadCredential` straightforward:# client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"disable_api_key_login:falsetoken_endpoint_auth_method:"client_secret_post"# If you are using OIDC, you need to generate an API key# that can be used to authenticate other sessions when signing in.## This can be done with `headscale apikeys create --expiration 999d`headscale_api_key:"your-headscale-api-key"# Optional, but highly recommended otherwise Headplane# will attempt to automatically guess this from the issuer## This should point to your publicly accessibly URL# for your Headplane instance with /admin/oidc/callbackredirect_uri:'https://<url-to-your-headplane>/admin/oidc/callback'# Stores the users and their permissions for Headplane# This is a path to a JSON file, default is specified below.user_storage_file:"/var/lib/headplane/users.json"
2025-04-30T21:45:45-04:00 WRN home/runner/work/headscale/headscale/hscontrol/noise.go:66 > No Upgrade header in TS2021 request. If headscale is behind a reverse proxy, make sure it is configured to pass WebSockets through.
Jun 24 15:29:02 fedora.attlocal.net tailscaled[885490]: Received error: register request: Post "https://headscale.example.com/machine/register": connection attempts aborted by context: context deadline exceeded
Jun 24 15:29:02 fedora.attlocal.net tailscaled[885490]: control: LoginInteractive -> regen=trueJun 24 15:29:02 fedora.attlocal.net tailscaled[885490]: control: doLogin(regen=true, hasUrl=false)Jun 24 15:29:02 fedora.attlocal.net tailscaled[885490]: control: control server key from https://headscale.example.com: ts2021=[lx/4O], legacy=Jun 24 15:29:02 fedora.attlocal.net tailscaled[885490]: control: Generating a new nodekey.
Jun 24 15:29:02 fedora.attlocal.net tailscaled[885490]: control: RegisterReq: onode=node=[yFWNe]fup=falsenks=falseJun 24 15:29:02 fedora.attlocal.net tailscaled[885490]: control: controlhttp: forcing port 443 dial due to recent noise dial
Headscale容器的日志中有如下错误:
1
2025-06-24T17:53:20Z WRN home/runner/work/headscale/headscale/hscontrol/noise.go:66 > No Upgrade header in TS2021 request. If headscale is behind a reverse proxy, make sure it is configured to pass WebSockets through.