V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
liuzimin
V2EX  ›  服务器

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

  •  
  •   liuzimin · 8 天前 · 655 次点击

    背景:

    • 服务器:阿里云轻量
    • 主体搭建方案: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
    	}
    }
    
    16 条回复    2025-03-11 11:01:08 +08:00
    lexfoxrush
        1
    lexfoxrush  
       8 天前
    tailscale login --login-server https://<服务器域名>:61111 --auth-key 带上 auth-key 能行吗
    lexfoxrush
        2
    lexfoxrush  
       8 天前
    https://www.v2ex.com/t/1055354 我看这里有说未备案会被阻断 我用的 ip 和自签名证书,客户端添加下信任
    liuzimin
        3
    liuzimin  
    OP
       8 天前
    @lexfoxrush 试了下,还是一样的症状。
    liuzimin
        4
    liuzimin  
    OP
       8 天前
    @lexfoxrush 不过为啥用域名能打开 https://域名/windows 的指引页呢?而且安卓、linux 端用这个域名方式可以成功添加。
    之前我也考虑过纯 IP+自签名证书方案,后来不知道哪里没搞对,把证书装上还是没走通 https ,就放弃了。
    liuzimin
        5
    liuzimin  
    OP
       8 天前
    @lexfoxrush 我用纯 IP 的方式试了下,windows 端可以正常显示一个加入链接了。。。看来确实问题出在 https 上,可能真的是域名备案问题吧。。唉,太恶心了。
    liuzimin
        6
    liuzimin  
    OP
       7 天前
    @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
        7
    lexfoxrush  
       7 天前
    openssl s_client -connect ip:8080
    openssl s_client -connect ip:3000
    客户端命令行试试这俩正常吗
    liuzimin
        8
    liuzimin  
    OP
       6 天前
    @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
        9
    liuzimin  
    OP
       6 天前
    @lexfoxrush 老哥你确定国内的云用 IP+自签名可以成功走 https 吗?
    我今天又试了下,在本地电脑的 WSL 上搭了同一套,用 IP+自签名一点毛病都没有,正常启用 https 访问;但阿里云上就死活调不通😣
    lexfoxrush
        10
    lexfoxrush  
       6 天前
    我用的就是阿里云的,不过没有 headscale-ui
    lexfoxrush
        11
    lexfoxrush  
       6 天前
    自己装的 nixos ,没用自带的,不能是这个的影响吧
    liuzimin
        12
    liuzimin  
    OP
       6 天前
    @lexfoxrush 我用的阿里云的 Ubuntu22.04 ,和我 WSL 的版本一致。
    liuzimin
        13
    liuzimin  
    OP
       6 天前
    @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
        14
    ray1980  
       6 天前
    不用设置 derp 吗?
    liuzimin
        15
    liuzimin  
    OP
       6 天前
    @ray1980 derp 我以前自建过。所以这里只讨论了 headscale 相关。
    liuzimin
        16
    liuzimin  
    OP
       6 天前
    头大,现在 https 网页访问没问题了,但 tailscale 客户端用 https 的服务器地址就死活不跳转。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5291 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 07:51 · PVG 15:51 · LAX 00:51 · JFK 03:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.