docker 部署 tailscale/headscale

发布于 2023-03-26  344 次阅读


版本

前言

简介及原理

tailscale/headscale 是个虚拟组网工具,不同于 frp 之类的需要中间节点的,tailscale/headscale 在 UDP 打洞完成后,就可以两台设备直连,也就是 P2P 内网穿透啦!好处显而易见,比如有一台笔记本和一个 NAS 需要连接,两个设备都在 A 市,但是作为中心节点的服务端部署在 B 市,那么类似 frp 这种的流量走向就是(偷下 tailscale 官网的图):

传统 VPN 需要经过中心节点连接,速度取决于中心节点,并且中心节点的距离远的话,延迟会很高。

而 tailscale/headscale 连接后,首先也会先按照上述流程,确保最低限度能马上连接,其次会尝试 UDP 打洞,如果一旦成功,会自动切到双方互通,也就不需要经过中间节点了:

UDP 打洞成功后自动会切为直连,没有中间商赚差价!

tailscale 和 headscale

tailscale 的客户端及 DERP 服务端是开源的,但是作为服务端的中心节点是闭源的(单人,且有 20 个连接数限制,不过对于一般人而言也够用了),所以有人就弄了个 headscale 的开源服务端中心节点项目!

下面就以 headscale 作服务端,其余客户端用 tailscale 进行部署!

tailscale/headscale 本质上也是一种 VPN,所以,如果你的客户端在国内,建议服务端也一并部署在国内服务器上!别问我为什么要建议🤣

服务端部署

当然采用我最喜欢的 docker 啦!这里我分别部署 headscale 和 headscale-webui,然后两者都用 nginx 反代的方式!

部署 headscale

创建配置文件

首先建好 headscale 要用到的文件夹:

mkdir -p ./headscale/config
cd ./headscale

再创建一个空的 sqlite 数据库文件:

touch ./config/db.sqlite

然后把官方的配置样例文件放进去(当然你也可以自己新建,手动配置参数):

curl https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml -o ./config/config.yaml

编辑 config.yaml,要修改的地方如下:

server_url:改成你对外提供服务的 URL 地址,例:https://xxx.com。

这个地址其实只是一个对外的展示地址,例如下面 Windows 客户端部署时,服务端页面可以下载的注册表值里面的地址等,跟你真正的访问地址没有任何关系,当然你要乱写也可以!

listen_addr:因为是在 docker 容器中,所以监听 ip 地址改成 0.0.0.0,例:0.0.0.0:8080。

metrics_listen_addr:监听详细信息地址,不建议暴露在公网。因为后面要结合 headscale webui 界面一起部署,里面就能显示一些信息,所以这里我是改成了 0.0.0.0:9090 但是没反代(登录 VPS 的时候手动看)。大家可以根据自己实际情况写或直接保持默认就行!

ip_prefixes:建议维持默认,不要去改动。

你若真要改,参考官方文档:ipv4ipv6 的范围改,超出范围是不支持的!

randomize_client_port:随机客户端端口,如果为 False 的话,默认端口是 41641。

其他的暂时用不到,可以先不管,当然,有兴趣的话,你也可以参阅里面的注释,每个参数说明都很详细描述了!修改完后保存文档!

创建 docker compose 文件

在 headscale 文件夹下,创建 headscale.yaml 文件:

nano headscale.yaml

输入以下内容:

version: '3'
services:
  headscale:
    image: headscale/headscale:latest
    volumes:
      - "./config:/etc/headscale" # 改成上个步骤中 config 文件夹所在路径
    restart: always
    networks:
      - mynet
    command: ["headscale", "serve"]
    environment:
      - TZ=Asia/Shanghai
#    ports:
#      - "8080:8080"

networks:
  mynet:
    external: true
这里说一下,因为我创建了一个自定义 docker 网络,后续我也打算把其他容器直接通过接入这个网络进行容器间的通讯,所以这里我注释掉了上面 ports 部分。如果你不想使用自定义网络,请取消注释上面的 ports 及其子项,注释 networks 及其子项(有2处)!下同!

编辑完成后,Ctrl+O 保存,Ctrl+X 退出。

部署 headscale-webui

headscale-webui 就是 headscale 的一个图形化界面,我们可以在页面上查看 headscale 的信息(包括设备,用户等)而不用进入容器中去输命令查了,谁不爱呢~

首先创建需要用到的文件夹,我这里就直接部署到 headscale 文件夹下了:

mkdir webui

然后要给新建的文件夹更改用户权限,这个 docker 容器里面默认是 UID 和 GID 都是 1000:

chown 1000:1000 webui/

接着还是创建 docker compose 文件:

nano headscale-webui.yaml

再来写入文件:

version: '3'
services:
  headscale-webui:
    image: ifargle/headscale-webui:latest
    restart: always
    networks:
      - mynet
    environment:
      - TZ=Asia/Shanghai
      - COLOR=red
      - HS_SERVER=http://headscale:8080 # 改成你上步中 headscale 对外的 IP 和端口
      - DOMAIN_NAME=https://headscale.$YOURDOMAIN # 改成你的域名
      - SCRIPT_NAME=/admin
      - KEY="fwyMUCWWpQB+0vry5CIA9OcEULIrEZolKIbkWXIM11Y="
      - AUTH_TYPE=basic
      - LOG_LEVEL=info
      - BASIC_AUTH_USER=YourAdmin # 改成你的面板登录用户名
      - BASIC_AUTH_PASS=YourAdminPassword # 改成你的面板登录密码
    volumes:
      - ./webui:/data # 改成你上步建立的 webui 文件夹路径
      - ./config/:/etc/headscale/:ro # 改成先前建立的 headscale config 文件夹路径
#    ports:
#      - "5000:5000"


networks:
  mynet:
    external: true

说一下环境变量里面的几个参数:

TZ:时区,改成你希望的时区。

COLOR:就是 webui 的主题色,可以自定,去这里挑!

注意,只包含基本颜色!例:red 有好几种(red lighten-5、red darken-1 等等),不能写入后缀,只能填 red!

HS_SERVER:headscale 服务端的地址。

这里我用了自定义网络,它们都包含在同一网络下,所以直接用容器名代替即可!你可以按照实际情况修改!

DOMAIN_NAME:你希望的部署域名,由于后面要 nginx 反代,所以这个项填不填都不要紧!

SCRIPT_NAME:子路径。比如你填的 DOMAIN_NAME 是 headscale.yourdomain.com,子路径是 /admin,那么你最终访问面板的真正路径就是 headscale.yourdomain.com/admin。不需要的话,直接 / 即可!

KEY:加密密钥,面板会需要 headscale 生成的 API KEY 授权才能访问,这个就是对获取的 API KEY 进行加密的 KEY 😂。可以用 openssl rand -base64 32 随机生成一个!

编辑完成后,Ctrl+O 保存,Ctrl+X 退出。

至此,headscale 的服务端就搭建完了,当然,如果你没有 nginx 反代的话,现在就可以尝试把容器运行起来了。

nginx 反代

nginx 的部署这里就不说了(我也是用的 docker😄),进入 nginx 持久化出来的 conf.d 文件夹里面,新建一个 headscale.conf 文件,然后配置反向代理(以下配置仅供参考,你也可以参阅官方部署文档 headscaleheadscale-webui):

# 80 端口跳转 443
server {
  listen 80 default_server;
  listen [::]:80 default_server;
  server_name _;
  location / { return 301 https://$host$request_uri; }
}

map $http_upgrade $connection_upgrade {
    default      keep-alive;
    'websocket'  upgrade;
    ''           close;
}

# headscale & webui
server {
  listen 443 proxy_protocol http2;
  listen [::]:443 proxy_protocol http2;
  server_name <yourdomain.com>; # 改成你的域名

  ssl_certificate <PATH_TO_CERT>;
  ssl_certificate_key <PATH_CERT_KEY>;
  ssl_protocols TLSv1.2 TLSv1.3;

  location / {
    proxy_pass http://headscale:8080; # 改成你的 headscale 容器地址
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header Host $server_name;
    proxy_redirect http:// https://;
    proxy_buffering off;
    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 $http_x_forwarded_proto;
    add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
  }

  location /admin {
    proxy_pass http://headscale-webui:5000/admin; # 改成你的 headscale-webui 容器地址
    proxy_http_version 1.1;
    proxy_set_header Host $server_name;
    proxy_buffering off;
    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 $http_x_forwarded_proto;
  }
}

配置服务端

全部完成后,先把容器运行起来,然后重载下 nginx:

docker compose -f headscale.yaml up -d
docker compose -f headscale-webui.yaml up -d
docker compose -f nginx.yaml restart nginx
温馨提示:如果 yaml 文件都不在当前命令路径下,记得指定路径哦~

不出意外的话,容器应该都能正常起来,然后进入 headscale 容器内部,创建用户和 API KEY!

创建用户

用户就是你的账号,先用 docker ps 查看你的容器名,然后进入创建:

# 下面一行记得改成你的容器名
docker exec headscale-headscale-1 \
  headscale users create user1

上面就创建了一个叫 user1 的账户了!

创建 API KEY

创建 API KEY 是为了授权面板使用,后面的一些操作就可以直接在面板里面进行了,还是进入容器创建:

docker exec headscale-headscale-1 \
  headscale apikeys create

记好显示的一串 KEY,然后我们访问刚刚反代的 headscale-webui 网址,输入刚刚获取的 KEY,点击 save 保存即可!

如果提示权限问题,确保部署 headscale-webui 时,对文件夹进行了用户权限变更!

至此,服务端的所有部署工作就完成了!我们在面板的 user 标签里面,应该能看到刚刚在 headscale 中创建的账户。

在 headscale 中创建的账户信息!

客户端使用

Windows

首先从 tailscale 官网下载对应客户端,安装后先别急着登录。打开你部署的 headscale 服务器域名,访问 /windows 路径,例:yourdomain.com/windows,然后下载注册表导入 Windows!

下载并导入注册表!
如果先前你在 headscale config.yaml 中乱填的 server_url,这里可能生成出错误的结果,记得改!🤣

然后在 Windows 任务管理器->服务中找到 tailscale 服务,右键重启一下。

最后再右下角托盘图标中右键,点击 login,此时,会弹出来一个网页,大致如下:

点击 login 后弹出的页面。

去服务器中,我们要手动允许下该设备的接入:

# NAMESPACE 和 key 替换成你自己的
docker exec headscale-headscale-1 \
   headscale -n <NAMESPACE> nodes register --key mkey:<key>
注意,上面代码第二行可以直接复制浏览器中给出的 code,NAMESPACE 替换成你的账号名!

可以在 webui 中看到已经添加的设备了:

显示设备列表。

这样就添加完成了,可以在其他已添加的设备上通过 ip 或 name 进行直接访问了!

使用 name 进行访问(上图 webui 中 RENAME 可以改名),需要 headscale config.yaml 中开启 magic_dns 项(默认是已开启的)!

其他

目前 Windows 下好像没有清理登录痕迹的地方(登录后,该账号就一直存在了),可以手动删除 C:\ProgramData\Tailscale 这个文件夹,达到清理的目的!
Windows 下其实也像 Linux 下那边用命令行,进入 tailscale 安装目录,按住 Shift 键+鼠标右键,选择“在此处打开 PowerShell”,就可以用命令行了。

Linux

同样 docker,不过客户端用的是 tailscale 官方 docker。

创建配置文件:

nano tailscale.yaml

写入配置:

version: '3'

services:
  tailscale:
    image: tailscale/tailscale
    restart: always
    devices:
      - /dev/net/tun
    network_mode: host
    volumes:
      - './tailscale/data:/var/lib' # 改成你的 tailscale 路径
      - '/dev/net/tun:/dev/net/tun'
    cap_add:
      - NET_ADMIN
      - NET_RAW
    command: sh -c "mkdir -p /var/run/tailscale && ln -s /tmp/tailscaled.sock /var/run/tailscale/tailscaled.sock && tailscaled"
需要存在 command 那行,否则容器运行起来时,可能会报错!(有可能是 BUG)

然后进入到容器内部:

docker exec -it tailscale /bin/sh

加入网络:

tailscale up --login-server=https://yourservers --accept-routes=true --accept-dns=false

--login-server:你的服务器地址。

--accept-routes:是否接受服务器路由配置。

--accept-dns:是否接受服务器下发的 DNS。这里推荐关闭,否则会修改掉你系统的 DNS。

同样输完后,也会出现一个网址访问,把他复制出来在浏览器中打开,参照 Windows 客户端中服务器手动添加一下设备即可,这里就不在赘述了。

使用 Pre-Auth

如果不想每次有设备加入都去服务器手动添加,也可以用预验证密钥,这样客户端可以直接通过预验证密钥进行加入了。

在 webui 的 User 界面中可以快速创建密钥:

添加预验证密钥。
设定相关内容后,点击 ADD 即可添加密钥。

然后客户端可以通过预验证密钥接入:

# login-server 替换成你的,$KEY 替换成获取到的密钥
tailscale up --login-server=https://yourservers --accept-routes=true --accept-dns=false --authkey $KEY

Android

这个应该是最简单了的吧,同样先从 tailscale 官网 下载 APP,安装后点右上角三个点,需要来回多点几次后,就会出现 Change server 选项,点击后填入你的服务器地址,点击 Save and restart,不会操作的看下面视频:

然后点击 Sign in,同样弹出来一个网址,想办法拷出来,去服务器添加就行!