大内网战略-tailscale虚拟局域网
前言
Tailscale是基于wireguard的虚拟局域网搭建工具,除开使用官方的服务外,还支持全过程使用自建服务。
此套搭建方式不强制使用HTTPS,支持IP访问,且基于官方原版,不进行额外源码修改。
包含HTTPS的部分都可变更为HTTP,关键配置部分有对应说明。
环境
- Debian以及ubuntu20.04或以上版本
安装本文用到的工具
1 | apt install curl wget vim |
大体搭建流程
- 搭建中转服务器
derp - 搭建协调服务器及协调服务器UI
- 根据安装对应系统的
tailscale客户端 - 组网成功
协调服务器:配置中心,负责管理设备的登入登出以及下发各类配置。
中转服务器:用于中转流量,提供P2P打洞功能。
大内网的所有服务均不推荐通过docker搭建。
1 自建中转服务器derp
如果是有ipv4的家宽想搭建
derp,路由器必须支持nat环回。
否则会导致内网设备无法连接到这个derp支持
nat环回表现为,局域网内可以通过公网IP连接到内网已端口映射设备。
!!!在打开--verify-clients的情况下客户端版本不能低于derp最小支持版本,否则连接会被拒绝!!!
1.1 安装与编译
本节可参考官方文档
安装go编译器
官方推荐使用最新的版本的go进行编译https://golang.org/doc/install,本文使用1.21.4版本的go用于演示。
随着derp的更新,所需的go版本也可能更新,如果出现错误请善用翻译。
1 | apt update && apt upgrade |
编译安装derp
1 | go install tailscale.com/cmd/derper@main |
会将最新的 DERP 服务器编译安装到$HOME/go/bin.
拷贝执行文件到启动目录下
1 | mkdir /etc/derp |
赋予执行权限
1 | chmod +x /etc/derp/derper |
配置为系统服务
1 | vim /etc/systemd/system/derp.service |
1 | [Unit] |
ecs + :wq 保存
其中
31446是http服务端口33478是用于P2P打洞的stun的udp服务端口--verify-clients会在连接时校验客户端是否已在网络内
使用systemctl <start/stop/restart/status> derp对derp进行管理
配置开机自启
1 | systemctl enable derp |
1.2 derp 启动!
1 | systemctl start derp |
1.3 通过nginx提供HTTPS
没有域名可以跳过这一步
安装nginx
1 | apt install nginx |
配置Nginx
配置或路径中的example.com需要换成自己的域名
1 | vim /etc/nginx/conf.d/example.com |
ecs + :wq 保存
HTTPS配置参考
1 | server{ |
proxy_pass对应derp服务的本机地址,如有调整记得更新。
创建证书文件夹
1 | mkdir /etc/nginx/ssl |
SSL证书可以自己申请也可以使用acme.sh或certbot等工具自动创建公钥路径
/etc/nginx/ssl/example.com.pem
私钥路径/etc/nginx/ssl/example.com.key
HTTP配置参考
1 | server{ |
proxy_pass对应derp服务的本机地址,如有调整记得更新。
无域名时注释server_name或将server_name指定为固定IP
应用配置变更
1 | service nginx force-reload |
Nginx报错的解决方案
首次安装nginx基本都会出现,需要配置nginx.conf,用以允许websocket连接。
1 | vim /etc/nginx/nginx.conf |
在http{...}中加入
1 | map $http_upgrade $connection_upgrade { |
ecs + :wq 保存
2 自建协调服务器headscale
2.1 协调服务器headscale搭建
协调服务器的核心,是无界面的后台服务。
通过官方支持的后端 headscale 部署自建协调服务器,这里以0.22.3版本的安装为例
官方仓库地址: https://github.com/juanfont/headscale/releases
1 | wget --output-document=headscale.deb \ |
这是仓库里的deb包下载链接,下载速度慢的自行百度加速站转换地址后下载。
安装
1 | sudo dpkg --install headscale.deb |
设置开机自启动
1 | sudo systemctl enable headscale |
编辑配置
1 | nano /etc/headscale/config.yaml |
ctrl+x退出,Y/N+回车,保存或放弃修改
酌情调整的配置
1 | ... |
你可能会发现headscale有提供内置的derp,但是不建议启用它。
headscale的feat(derp)中对headscale的内置derp验证客户端(
--verify-clients)支持仅为未来计划。
--verify-clients用于在连接时校验客户端是否合法组网,所以不启用--verify-clients与在互联网上裸奔无异(
关于dns_config配置的额外说明
extra_recordshttps://headscale.net/dns-records/restricted_nameservershttps://tailscale.com/kb/1054/dns#nameservers
extra_records类似hosts可用于指定域名的A记录,目前的支持似乎不太完整,请参考官方文档慎用其他记录类型。
1 | extra_records: |
restricted_nameservers用于指定域名及其子域名通过哪一个DNS进行独立解析
1 | restricted_nameservers: |
在上述restricted_nameservers配置下chenxuan.local、www.chenxuan.local会通过1.1.1.1这个DNS服务器来解析域名。
万事俱备 headscale 启动!
1 | sudo systemctl start headscale |
没有报错就表示正常启动了。
自此完成协调服务器后端搭建。
2.2 协调服务器UI
一个简单的界面能极大的优化使用体验。
这里选用的是,headscale-ui(https://github.com/gurucomputing/headscale-ui)
创建目录
1 | UI目录 |
下载解压UI
1 | wget https://github.com/gurucomputing/headscale-ui/releases/download/2023.01.30-beta-1/headscale-ui.zip |
安装nginx
1 | apt install nginx unzip |
配置Nginx
如果协调与中继服务部署在同一台服务器上,并且复用域名,或许可以参考issue
配置或路径中的example.com需要换成自己的域名
1 | vim /etc/nginx/conf.d/example.com |
ecs + :wq 保存
HTTPS配置参考
1 | server{ |
proxy_pass对应协调服务器本机地址,如有调整记得更新。
创建证书文件夹
1 | mkdir /etc/nginx/ssl |
SSL证书可以自己申请也可以使用acme.sh或certbot等工具自动创建公钥路径
/etc/nginx/ssl/example.com.pem
私钥路径/etc/nginx/ssl/example.com.key
HTTP配置参考
1 | server{ |
proxy_pass对应协调服务器本机地址,如有调整记得更新。
无域名时注释server_name或将server_name指定为固定IP
应用配置变更
1 | service nginx force-reload |
Nginx报错的解决方案
首次安装nginx基本都会出现,需要配置nginx.conf,用以允许websocket连接。
1 | vim /etc/nginx/nginx.conf |
在http{...}中加入
1 | map $http_upgrade $connection_upgrade { |
ecs + :wq 保存
配置中转服务器列表derp.json
1 | vim /var/www/tailscale/conf/derp.json |
有域名参考配置
更多配置参考官方文档
1 | { |
STUNPortstun端口,用于P2P打洞DERPPortderp的https端口,中转流量等HostName域名
无域名参考配置
更多配置参考官方文档
1 | { |
InsecureForTests用于禁用ssl验证,官方并不推荐启用这一设置,这可能导致中间人攻击。
在没有域名或ssl证书的情况下必须启用该设置
重新加载nginx配置
1 | service nginx force-reload |
2.3 访问UI页面
通过上述配置,这时应该可以访问到UI界面了。
要想通过UI进行配置,还需要稍稍进行一些配置。
1 | http://example.com |
headscale密钥获取
1 | headscale apikeys create --expiration 30d |
创建了一个30天有效期的密钥
此密钥是配置密码,请妥善保管,可以通过headscale apikeys相关命令进行管理。
配置密钥
在ui上配置
1 | Settings -> Headscale API Key -> 输入获取的密钥 -> Test Server Settings |
之后便可以使用UI来配置Headscale了
3 客户端连接自建协调服务器
大部分的安装包可以到此处下载: https://pkgs.tailscale.com/stable/
本节可参考 官方文档
3.1 Window
管理员powershell运行指令
1 | New-ItemProperty -Path 'HKLM:\Software\Tailscale IPN' -Name UnattendedMode -PropertyType String -Value always |
https://YOUR-HEADSCALE-URL对应协调服务器地址
随后可在UI上登录,或者在命令行登录。
如若未生效,请在 任务管理器->服务->tailscale 处右键重启服务
1 | tailscale login --login-server https://YOUR-HEADSCALE-URL |
server_url对应协调服务器地址
完整登录流程可以参考Linux小节~
3.2 Linux
安装tailscale
1 | curl -fsSL https://tailscale.com/install.sh | sh |
启用tailscale并设置协调服务器
1 | tailscale up --login-server=协调服务器地址 |
如果此前已经连接了官方服务,可以使用
tailscale logout登出服务器地址示例:http://example.com、https://example.com、http://ip:8080
执行命令后会响应出一串地址,就像下面这样
1 | https://xxxxxx/register/nodekey:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
复制nodekey及后续信息
1 | nodekey:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
随后登陆headscale-ui进行配置
在配置Device前需要在User View创建至少一个用户!
1 | Device View -> New Device -> Select User -> ✓ |
添加后稍等片刻linux命令行会显示登录成功
这样就加入了网络
最好给节点改个好记的名字,这样可以通过协调服务器配置的魔法DNS来互访,而不用记IP(
3.3 Docker
不推荐
1 | docker pull tailscale/tailscale:latest |
查看状态
1 | docker exec tailscaled tailscale status |
status可以替换为set等其他tailscale支持的客户端指令与参数。
通常启动后会提示进行设备注册,注册后可正常使用。
注册可参考Linux客户端段落
3.4 其它配置
接受路由
用于不同网段间通信,发布了多个子网的可以启用,出口节点不启用可能会无法路由流量。
1 | tailscale set --accept-routes=true |
解决DNS冲突
由于我部署了一个在tailscale网络内部的dns解析服务,所以有时候会出现DNS冲突。
1 | tailscale set --accept-dns=false |
一般用户大抵用不到……
将节点设为出口节点
本节可参考官方文档
在设为出口节点以后,该节点还需要启用IP转发
已经注册的节点设为出口节点
1 | sudo tailscale set --advertise-exit-node |
启用IP转发
启用 IP 转发时,确保防火墙设置为默认拒绝流量转发。
这是常见防火墙(例如ufw和firewalld)的默认设置,可确保您的设备不会路由您不希望的流量。
如果 Linux 系统有/etc/sysctl.d目录,请使用:
1 | echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf |
否则,使用:
1 | echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf |
将本地子网添加到路由中
通告子网路由
1 | tailscale set --advertise-routes=192.168.0.0/24,192.168.1.0/24 |
将上例中的子网替换为适合您的网络的子网。支持 IPv4 和 IPv6 子网。
协调服务器启用路由
下述操作可以通过UI完成
Device View-> 点开一个需要启用路由的设备 ->Device Routes->pending/active(暂停或激活)
检查路由表
1 | headscale routes list |
启用路由
1 | headscale routes enable -r ID |
4 正文参考资料
- UP主 韩风Talk 的
Tailscale自建视频 https://www.bilibili.com/video/BV1Wh411A73b
本文与视频有许多不同,注意甄别。
5 一些或许有用的解决方案
5.1 Https兼容性修补
在参考视频的评论区发现
--verify-clients可能会因不使用带域名的HTTPS导致不进行客户端校验的情况,故提出此修补方案。
生成自定义ssl证书
1 | openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout /etc/derp/derp.test.com.key -out /etc/derp/derp.test.com.crt -subj "/CN=derp.test.com" -addext "subjectAltName=DNS:derp.test.com" |
调整中继系统服务配置
停止中继服务derp
1 | systemctl disable derp |
修改derp配置
1 | vim /etc/systemd/system/derp.service |
1 | [Unit] |
-a :31446用于指定HTTPS端口
虽然用不到http服务,但是需要占用一个端口,默认占用80,所以需要设置http-port防止占用失败的启动报错。
启动derp
1 | systemctl enable derp |
修改nginx配置
将proxy_pass的http修改为https,并添加proxy_ssl_verify off;用于忽略derp的ssl证书。
修改proxy_set_header的值为derp.test.com
1 | server{ |
proxy_set_header用于伪装域名,其值与生成证书时指定的域名有关
重新加载nginx配置
1 | service nginx force-reload |
5.2 通过acme.sh自动获取SSL证书
这里使用阿里云dns为示例,其他服务器商请善用搜索引擎。
大抵区别只是创建
AccessKey与配置密钥这两步
创建AccessKey
首先在阿里云 AccessKey管理 页面创建AccessKey
安装acme.sh
1 | curl https://get.acme.sh | sh |
配置密钥
1 | export Ali_Key="你的key" |
安装证书
其中example.com的部分需要替换为自己的域名,需要为每个域名各运行一次。
1 |
|
生成ssl并安装到nginx(会自动续签)
5.3 关于阿里云服务器部署可能出现的问题以及解决方案
问题简述
Tailscale使用的网段100.64.0.0/10(100.64.0.1-100.127.255.254)
该网段为运营商级NAT(Carrier Grade NAT, CGNAT),与阿里云使用的网段冲突只是其一。
关键在于Tailscale为了解决安全问题,在防火墙网络规则里加入了丢弃该网段网络数据的规则。
导致使用该网段通信的阿里云应用无法连接,其中包括DNS解析、APT包下载以及云助手等功能
服务器默认DNS无法连接进一步导致依赖域名解析的服务无法运行
解决方案零,最推荐的方案
摆烂方案,修改DNS为其它可信DNS。并给包管理器换源。
代价是无法使用一些阿里云的功能。
解决方案一
此方案存在安全隐患,不推荐使用
在启动tailscale时加入--netfilter-mod=off
该设置会取消设置丢弃100.64.0.0/10网段的防火墙规则
解决方案二
该方案在重新启动
tailscale后失效。
原因是tailscale会在启动时添加一个高优先级的iptables规则,先一步把包丢弃了。
headscale的dns_config下添加:
需要参考阿里云文档 配置云助手Agent网络权限 获取需要允许的部分IP数据,示例中添加的是阿里云广州的权限。
1 | extra_records: |
1 | 查看当前DNS地址 |
通过防火墙规则允许该网段内关键阿里云服务的连接。
1 | 创建规则 |
需通过
iptables -L INPUT确认ts-input-whitelist处于ts-input前方
否则会优先处理ts-input的丢弃操作
每次tailscale的重新启动都可能导致优先级发生变化
解决方案三
[[tailscale 解决阿里云服务器受影响的问题]]
本节参考
- https://maxng.cc/posts/headscale-ez-tutorial/
- https://nyan.im/p/troubleshoot-tailscale
- https://zhuanlan.zhihu.com/p/653295049
- https://help.aliyun.com/zh/ecs/user-guide/configure-network-permissions-for-the-cloud-assistant-agent
6 关于ACL
headscale支持通过acl控制网络访问。
在默认情况下任何用户都可以访问任意连入网络的设备
同时与tailscale不同的是,在打上标签之后用户不会被置空,但用户规则依然部分有效(允许ping)。
后续可能会出一篇新的文章探讨ACL的配置。