求助😭, HeadScale 自建后, win 端 Tailscale 无法登陆

2025 年 3 月 8 日
 liuzimin

背景:


操作表现&&症状:

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.
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)


配置文件


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

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
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
	}
}
3110 次点击
所在节点    服务器
21 条回复
lexfoxrush
2025 年 3 月 8 日
tailscale login --login-server https://<服务器域名>:61111 --auth-key 带上 auth-key 能行吗
lexfoxrush
2025 年 3 月 8 日
https://www.v2ex.com/t/1055354 我看这里有说未备案会被阻断 我用的 ip 和自签名证书,客户端添加下信任
liuzimin
2025 年 3 月 8 日
@lexfoxrush 试了下,还是一样的症状。
liuzimin
2025 年 3 月 8 日
@lexfoxrush 不过为啥用域名能打开 https://域名/windows 的指引页呢?而且安卓、linux 端用这个域名方式可以成功添加。
之前我也考虑过纯 IP+自签名证书方案,后来不知道哪里没搞对,把证书装上还是没走通 https ,就放弃了。
liuzimin
2025 年 3 月 8 日
@lexfoxrush 我用纯 IP 的方式试了下,windows 端可以正常显示一个加入链接了。。。看来确实问题出在 https 上,可能真的是域名备案问题吧。。唉,太恶心了。
liuzimin
2025 年 3 月 9 日
@lexfoxrush 老哥救命。。。。我现在也在尝试纯 IP 加自签名。
现在的情况是:
- 自签名的证书导入电脑,局域网内电脑架个纯 IP 的 Web 页面,可以成功走 https ,感觉自签名方式没问题
- headscale-ui 走 http 就能正常访问页面
- 给服务器自签名( Caddy 反代里面配置),用 https 访问 headscale-ui ,Chrome 始终报错:ERR_SSL_PROTOCOL_ERROR

(headscale 在 8080 ,headscale-ui 在 3000)

我感觉这是 Caddy 有问题?
Caddyfile:
```
{
auto_https disable_redirects
}

https://<服务器 IP>:8081 {
tls /home/admin/docker/cert/crt.crt /home/admin/docker/cert/private.key #全局签名

@cors header Origin http://<服务器 IP>:3000
@options method OPTIONS

handle @options {
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"
respond 204
}

handle @cors {
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 127.0.0.1:8080
}


https://<服务器 IP>:3001 {
tls /home/admin/docker/cert/crt.crt /home/admin/docker/cert/private.key

reverse_proxy 127.0.0.1:3000
}

```
lexfoxrush
2025 年 3 月 9 日
openssl s_client -connect ip:8080
openssl s_client -connect ip:3000
客户端命令行试试这俩正常吗
liuzimin
2025 年 3 月 10 日
@lexfoxrush openssl s_client -connect <服务器 ip>:3001 -showcerts
CONNECTED(00000003)
801B3E9AD17F0000:error:0A000438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error:../ssl/record/rec_layer_s3.c:1584:SSL alert number 80
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 293 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
liuzimin
2025 年 3 月 10 日
@lexfoxrush 老哥你确定国内的云用 IP+自签名可以成功走 https 吗?
我今天又试了下,在本地电脑的 WSL 上搭了同一套,用 IP+自签名一点毛病都没有,正常启用 https 访问;但阿里云上就死活调不通😣
lexfoxrush
2025 年 3 月 10 日
我用的就是阿里云的,不过没有 headscale-ui
lexfoxrush
2025 年 3 月 10 日
自己装的 nixos ,没用自带的,不能是这个的影响吧
liuzimin
2025 年 3 月 10 日
@lexfoxrush 我用的阿里云的 Ubuntu22.04 ,和我 WSL 的版本一致。
liuzimin
2025 年 3 月 10 日
@lexfoxrush 卧槽,老哥我解决了!!我放弃了 Caddy ,让 deepseek 帮我写了一个 nginx 的反代,直接一步成功,现在自签名证书走 https 稳稳的,太爽了😁。。还是老玩意儿比新东西成熟靠谱啊。

-----

在这做下笔记,给后人指个路:
- 自签名证书生成 (假设服务器 IP 以 192.168.1.1 为例):
```
openssl req -x509 -newkey rsa:4096 -sha256 -keyout private.key -out cert.crt -days 3650 -subj "/CN=192.168.1.1" -addext "subjectAltName=IP:192.168.1.1" -nodes
```

- nginx 反代配置:
```
# Headscale-UI 的反向代理( 3001 -> 3000 )
server {
listen 3001 ssl;
server_name 192.168.1.1; # 替换为你的服务器 IP 或域名

# 自签名证书路径
ssl_certificate /home/admin/docker/cert/192.168.1.1.crt;
ssl_certificate_key /home/admin/docker/cert/192.168.1.1.key;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass http://localhost:3000; # 将请求转发到 Headscale-UI
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

# Headscale 的反向代理( 8081 -> 8080 )
server {
listen 8081 ssl;
server_name 192.168.1.1; # 替换为你的服务器 IP 或域名

# 自签名证书路径
ssl_certificate /home/admin/docker/cert/192.168.1.1.crt;
ssl_certificate_key /home/admin/docker/cert/192.168.1.1.key;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass http://localhost:8080; # 将请求转发到 Headscale
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
Nginx 启动!!😁

-END-
ray1980
2025 年 3 月 11 日
不用设置 derp 吗?
liuzimin
2025 年 3 月 11 日
@ray1980 derp 我以前自建过。所以这里只讨论了 headscale 相关。
liuzimin
2025 年 3 月 11 日
头大,现在 https 网页访问没问题了,但 tailscale 客户端用 https 的服务器地址就死活不跳转。。。
nunterr
2025 年 6 月 24 日
我开始也自建过,各种问题,现在是使用 tailscale+derp,这种使用很方便
liuzimin
2025 年 6 月 24 日
@nunterr #17 tailscale+derp 确实省心。但就国内这恶劣的网络环境,我很担忧未来某一天 tailscale 会被和谐,所以我才折腾 headscale 实现全流程可控。

最后我还是老老实实备案了域名,然后一切都跑通了,直到目前一直很稳定。
nunterr
2025 年 6 月 25 日
@liuzimin 我使用 HeadScale 很难打通直连,tailscale 大部分都能打洞成功,不成功的走国内 derp
liuzimin
2025 年 6 月 25 日
@nunterr #19 哈哈我从来就没打洞成功过。。。不管是用哪种方案,都是走自建 derp 中转。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1116908

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX