背景:

  • 服务器:阿里云轻量
  • 主体搭建方案:headscale-ui 的 github 页提供的 docker-compose
  • 域名:有域名,未备案,已配好 dns 解析
  • 反代方案:caddy
  • ssl 证书方案:自编译支持阿里云的 caddy ,走 dns 挑战

操作表现&&症状:

  • 搭好后,浏览器访问 http://<服务器 IP>:3000/web,可成功访问 headscale-ui 后台页面
  • hs-ui 后面页面填入 https://<服务器域名>:61111 与 apikeys ,可成功通过页面与 headscale 进行交互(增删用户、增删 PreAuthKey 等操作)
  • 可正常通过 https:///<服务器域名>:61111/windows 打开 win 客户端的登陆指引页面,浏览器 https 标识正常,查看证书信息正常,显示 Let's Encrypt 证书,三个月后到期
  • 安卓客户端通过修改 server ,可正常跳转到浏览器,但是打不开页面,显示 ERR_CONNECTION_RESET ,但复制链接里的 mkey 到后台,可以成功添加设备,后续安卓端可在线
  • win 端按提示 tailscale login --login-server https://<服务器域名>:61111 ,执行后,会弹出小气泡,点击气泡和点击任务栏图标登陆都没反应
  • 清除相关文件、卸载重装 tailscale ,问题依旧
  • 查看 tailscale 日志:
Received error: fetch control key: Get "https://<服务器域名>:61111/key?v=113": read tcp 192.168.11.86:55438->服务器 IP:61111: wsarecv: An existing connection was forcibly closed by the remote host.
  • 查看 headscale 日志:
2025-03-08T09:05:21Z ERR noise upgrade failed error="noise handshake failed: decrypting machine key: chacha20poly1305: message authentication failed"
2025/03/08 09:05:21 http: response.WriteHeader on hijacked connection from github.com/juanfont/headscale/hscontrol.(*Headscale).NoiseUpgradeHandler (noise.go:83)
2025/03/08 09:05:21 http: response.Write on hijacked connection from fmt.Fprintln (print.go:305)


配置文件

  • headscale-config.yaml

server_url: https://<我的域名>:61111
listen_addr: 0.0.0.0:8080

metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false

noise:
   private_key_path: /var/lib/headscale/noise_private.key

prefixes:
  v4: 100.64.0.0/10
  v6: fd7a:115c:a1e0::/48

  allocation: sequential

derp:
  server:
    region_id: 996
    region_code: "headscale"
    region_name: "Headscale Embedded DERP"
    stun_listen_addr: "0.0.0.0:3478"
    private_key_path: /var/lib/headscale/derp_server_private.key

    automatically_add_embedded_derp_region: true

    ipv4: 1.2.3.4
    ipv6: 2001:db8::1

  urls: 
    []

  paths:
    - /etc/headscale/my-derp.yaml

  auto_update_enabled: true
  update_frequency: 24h
disable_check_updates: true
ephemeral_node_inactivity_timeout: 30m

database:
  type: sqlite
  debug: false
  gorm:
    prepare_stmt: true
    parameterized_queries: true

    skip_err_record_not_found: true
    slow_threshold: 1000

  sqlite:
    path: /var/lib/headscale/db.sqlite
    write_ahead_log: true
    wal_autocheckpoint: 1000


acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: ""
tls_letsencrypt_hostname: ""
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
tls_letsencrypt_challenge_type: HTTP-01
tls_letsencrypt_listen: ":http"
tls_cert_path: ""
tls_key_path: ""

log:
  format: text
  level: info

policy:
  mode: file
  path: ""

dns:
  magic_dns: true
  base_domain: <服务器域名>
  nameservers:
    global:
      - 1.1.1.1
      - 1.0.0.1
      - 2606:4700:4700::1111
      - 2606:4700:4700::1001

    split:
      {}

  search_domains: []

  extra_records: []

unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
logtail:
  enabled: false
randomize_client_port: false

  • compose.yaml 文件
version: '3.5'
services:
  headscale:
    image: headscale/headscale:0.24.0
    container_name: headscale
    volumes:
      - ./headscale-config/:/etc/headscale/
      - ./headscale-data/:/var/lib/headscale/
    ports:
      - 8080:8080
    command: serve
    restart: unless-stopped

  headscale-ui:
    image: ghcr.io/gurucomputing/headscale-ui:latest
    restart: unless-stopped
    container_name: headscale-ui
    ports:
      - 3000:8080
  • Caddyfile 配置文件
https://<服务器域名>:61111 {
    tls {
        dns alidns {
           access_key_id "XXXXXXXXXXXXXXX"
           access_key_secret "XXXXXXXXXXXXXXX"
        }
    }
		
	#匹配跨域请求
	@hs-options {
		host 服务器域名
		method OPTIONS
	}
	@hs-other {
		host 服务器域名
	}
	
	#处理跨域请求
	handle @hs-options {
		header {
			Access-Control-Allow-Origin "http://<服务器 IP>:3000"
			Access-Control-Allow-Headers *
			Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE"
			Access-Control-Allow-Credentials true
		}
		respond 204 
	}
	
	handle @hs-other {
	    header Access-Control-Allow-Origin "http://<服务器 IP>:3000"
        header Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE"
		header Access-Control-Allow-Headers *
		header Access-Control-Allow-Credentials true
		
		reverse_proxy http://localhost:8080
	}
}
举报· 520 次点击
登录 注册 站外分享
4 条回复  
lexfoxrush 初学 2025-3-8 17:48:59
tailscale login --login-server https://<服务器域名>:61111 --auth-key 带上 auth-key 能行吗
lexfoxrush 初学 2025-3-8 17:55:57
https://www.fex.com/t/1055354 我看这里有说未备案会被阻断 我用的 ip 和自签名证书,客户端添加下信任
liuzimin 楼主 初学 2025-3-8 17:57:33
@lexfoxrush 试了下,还是一样的症状。
liuzimin 楼主 初学 2025-3-8 18:07:03
@lexfoxrush 不过为啥用域名能打开 https://域名/windows 的指引页呢?而且安卓、linux 端用这个域名方式可以成功添加。 之前我也考虑过纯 IP+自签名证书方案,后来不知道哪里没搞对,把证书装上还是没走通 https ,就放弃了。
返回顶部