Headscale 是什么
Tailscale 的控制服务器是不开源的,而且对免费用户有诸多限制,这是人家的摇钱树,可以理解。好在目前有一款开源的实现叫 Headscale,这也是唯一的一款,希望能发展壮大。
Headscale 由欧洲航天局的 Juan Font 使用 Go 语言开发,在 BSD 许可下发布,实现了 Tailscale 控制服务器的所有主要功能,可以部署在企业内部,没有任何设备数量的限制,且所有的网络流量都由自己控制。
目前 Headscale 还没有可视化界面,期待后续更新吧。
1、创建初始化目录和数据库
echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
mkdir -p /data/headscale/config
mkdir -p /data/headscale/data
cd /data/headscale/data
touch db.sqlite
cd /data/headscale/config;
#下载模板配置文件
wget https://github.com/juanfont/headscale/raw/main/config-example.yaml
#代理下载任何GitHub下载加上:https://ghproxy.com/
wget https://ghproxy.com/https://github.com/juanfont/headscale/raw/main/config-example.yaml2、修改配置文件
2.1 参数注释
#注意更改公网IP或者换成域名:xxx.com
需要修改的参数有:
#访问服务端的公网IP或者域名
server_url
#开放的端口
listen_addr
#修改/etc/headscale/private.key的存放路径
private_key_path
#修改/etc/headscale/noise_private.key的存放路径
private_key_path
#关闭ipv6,用不到
ip_prefixes
#开启随机端口
randomize_client_port
#定义数据库路径
db_path
#dns改为国内223.5.5.5,可以多个
nameservers2.2 写入配置
vim /data/headscale/config/config.yaml
---
server_url: http://headscale.xxx.com:8080
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
private_key_path: /var/lib/headscale/private.key
noise:
private_key_path: /var/lib/headscale/noise_private.key
ip_prefixes:
- 100.64.0.0/10
derp:
server:
enabled: false
region_id: 999
region_code: "headscale"
region_name: "Headscale Embedded DERP"
stun_listen_addr: "0.0.0.0:3478"
urls:
- https://controlplane.tailscale.com/derpmap/default
paths: []
auto_update_enabled: true
update_frequency: 24h
disable_check_updates: false
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
db_type: sqlite3
db_path: /var/lib/headscale/db.sqlite
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
acl_policy_path: ""
dns_config:
override_local_dns: true
nameservers:
- 223.5.5.5
- 114.114.114.114
- 8.8.8.8
- 1.1.1.1
domains: []
magic_dns: true
base_domain: example.com
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
logtail:
enabled: false
randomize_client_port: true3、启动docker服务
服务端操作,前提是自己安装好docekr服务,百度一大把
docker run -d --name headscale --restart always -v /data/headscale/config:/etc/headscale/ -p 8089:8089 -p 9090:9090 headscale/headscale:0.22.3 headscale serve
#进入容器并创建默认用户
docker exec -it headscale bash
headscale users create default
#生成24小时密钥,注意下面密钥客户端加入需要用到
headscale preauthkeys create --user default --reusable --expiration 24h
#下面是输出信息
a8438d05e623563aa908b1c190d56e2f2547e3713da693b7
#退出容器
exit
#安装客户端--advertise-routes=参数是运行连接客户端可以被访问的网段比如内网(可选)
#如果安装慢可以选择手动安装
curl -fsSL https://tailscale.com/install.sh | sh
#(可选)
tailscale up --login-server=http://xxx.com:8089 --accept-routes=true --accept-dns=false --advertise-routes=10.10.1.0/24 --authkey a8438d05e623563aa908b1c190d56e2f2547e3713da693b7
3.1.1 docker-compose方式
cat > /data/headscale/docker-compose.yml << EOF
version: "3.4"
services:
headscale:
image: headscale/headscale:0.22.3
container_name: headscale
restart: unless-stopped
entrypoint: headscale serve
volumes:
- /data/headscale/config:/etc/headscale/
- /data/headscale/data:/var/lib/headscale/
ports:
- "53450:8080"
- "9090:9090"
EOF
#启动容器
cd /data/headscale/;
docker-compose -f docker-compose.yml up -d --force-recreate
代证书https测试
cat > /data/headscale/docker-compose.yml << EOF
version: "3.4"
services:
headscale:
image: headscale/headscale:0.22.3
container_name: headscale
restart: unless-stopped
entrypoint: headscale serve
volumes:
- /data/headscale/config:/etc/headscale/
- /data/headscale/data:/var/lib/headscale/
ports:
- "53450:8080"
- "9090:9090"
cat > /data/caddy/docker-compose.yml << EOF
version: "3.4"
services:
caddy:
image: caddy:2.7.4
container_name: caddy
restart: unless-stopped
volumes:
- /data/caddy/Caddyfile:/etc/caddy/Caddyfile
- /data/caddy/certs:/root/certs
- caddy_data:/data
- caddy_conf:/config
ports:
- "80:80"
- "443:443"
volumes:
caddy_data: { }
caddy_conf: { }
EOF4、客户端加入
#客户端安装,如果安装慢可以选择手动安装
curl -fsSL https://tailscale.com/install.sh | sh
#--advertise-routes=参数是运行连接客户端可以被访问的网段比如内网
tailscale up --login-server=http://xxx.com:8089 --accept-routes=true --accept-dns=false --advertise-routes=192.168.1.0/24 --authkey a8438d05e623563aa908b1c190d56e2f2547e3713da693b7
#添加多个访问网段,重新加入步骤
tailscale down
tailscale up --login-server=http://xxx.com:8089 --accept-routes=true --accept-dns=false --advertise-routes="192.168.1.0/24,172.168.1.0/24" --reset --authkey a8438d05e623563aa908b1c190d56e2f2547e3713da693b75、允许路由访问
#进入容器并创建默认用户
docker exec -it headscale bash
#查看加入的节点信息
root@c532c6ca56ae:/# headscale nodes list
ID | Hostname | Name | MachineKey | NodeKey | User | IP addresses | Ephemeral | Last seen | Expiration | Online | Expired
1 | localhost | localhost | [HLoyZ] | [ZIiB/] | test | 100.64.0.1, | false | 2023-08-16 05:36:02 | 0001-01-01 00:00:00 | online | no
#查看路由信息
root@c532c6ca56ae:/# headscale routes list -i 1
ID | Machine | Prefix | Advertised | Enabled | Primary
1 | localhost | 165.198.105.0/24 | true | false | false
#允许路由访问
root@c532c6ca56ae:/# headscale routes enable -r 1 "165.198.105.0/24"
#再次查看确认Enabled | Primary 是否等于true
root@c532c6ca56ae:/# headscale routes list -i 1
ID | Machine | Prefix | Advertised | Enabled | Primary
1 | localhost | 165.198.105.0/24 | true | true | true
#允许所有效果相同于headscale routes enable -r 1 "165.198.105.0/24"命令
root@c532c6ca56ae:/# headscale routes enable -i 1 -a
root@c532c6ca56ae:/# headscale routes list -i 1
ID | Machine | Prefix | Advertised | Enabled | Primary
1 | localhost | 165.198.105.0/24 | true | true | true6、测试ping
要放开icmp协议或者防火墙
服务端测试ping
root@test:/# ping 100.64.0.1
PING 100.64.0.1 (100.64.0.1) 56(84) bytes of data.
64 bytes from 100.64.0.1: icmp_seq=1 ttl=64 time=79.1 ms
64 bytes from 100.64.0.1: icmp_seq=2 ttl=64 time=79.2 ms
64 bytes from 100.64.0.1: icmp_seq=3 ttl=64 time=84.9 ms
64 bytes from 100.64.0.1: icmp_seq=4 ttl=64 time=86.0 ms
64 bytes from 100.64.0.1: icmp_seq=5 ttl=64 time=86.5 ms
#客户端测试ping
root@localhost:~# ping 100.64.0.2
PING 100.64.0.2 (100.64.0.2) 56(84) bytes of data.
64 bytes from 100.64.0.2: icmp_seq=1 ttl=64 time=86.4 ms
64 bytes from 100.64.0.2: icmp_seq=2 ttl=64 time=86.5 ms
64 bytes from 100.64.0.2: icmp_seq=3 ttl=64 time=86.1 ms
64 bytes from 100.64.0.2: icmp_seq=4 ttl=64 time=86.5 ms
64 bytes from 100.64.0.2: icmp_seq=5 ttl=64 time=86.7 ms
#服务端测试ping客户端内网IP
root@test:/# ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=63 time=88.8 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=63 time=86.2 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=63 time=87.1 ms
64 bytes from 192.168.1.1: icmp_seq=4 ttl=63 time=86.1 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=63 time=83.3 ms7、二进制客户端手动安装篇(可选)
(可选参考)
前面用脚本安装了,就不要操作了,适合手动安装模式
#下载官方二进制包
wget https://pkgs.tailscale.com/stable/tailscale_1.48.1_amd64.tgz
#解压
tar xf tailscale_1.48.1_amd64.tgz
#将二进制文件复制到官方软件包默认的路径下
cp tailscale_1.48.1_amd64/tailscaled /usr/sbin/tailscaled
cp tailscale_1.48.1_amd64/tailscale /usr/bin/tailscale
#将 systemD service 配置文件复制到系统路径下:
cp tailscale_1.48.1_amd64/systemd/tailscaled.service /lib/systemd/system/tailscaled.service
#将环境变量配置文件复制到系统路径下:
cp tailscale_1.48.1_amd64/systemd/tailscaled.defaults /etc/default/tailscaled
#开机启动和启动
systemctl enable --now tailscaled
#查看状态
systemctl status tailscaledwindows客户端提示
最新的tailscale版本(1.34.0 及更高版本)
tailscale在 1.34 版中添加了快速用户切换,您现在可以使用 新的登录命令,用于连接到一个或多个tailscale 服务器。以前使用的配置文件不再起作用。
使用Tailscale的登录命令添加您的个人资料:
tailscale login --login-server https://headscale.amjun.com
################################################
Windows 注册表配置(1.32.0 及更低版本)
此页面提供官方 Windows 的 Windows 注册表信息 tailscale客户端。
注册表文件将配置尾标以用作 其控制服务器。https://headscale.amjun.com
谨慎
在安装之前,应始终下载并检查注册表文件 它:
curl https://headscale.amjun.com/windows/tailscale.reg8、部署derp中转服务器
此教程适合家用家庭公网宽带使用,纯公网IP的。
8.1.1 安装go服务环境
#安装必要的工具
apt install -y wget git openssl curl
cd /root/;mkdir go;cd go;
wget https://go.dev/dl/go1.21.0.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version
echo "export PATH=$PATH:/usr/local/go/bin" >> /etc/profile
source /etc/profile
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
go install tailscale.com/cmd/derper@main
cd ~/go/pkg/mod/tailscale.com\@v1.1.1-0.20230818020430-af2e4909b6e9/cmd/derper
chmod +w cert.go
vim cert.go
#将这段代码的if hi.ServerName != m.hostname,return nil……,}加上//注释掉,注释3行保存
func (m *manualCertManager) getCertificate(hi *tls.ClientHelloInfo) (*tls.Certificate, error) {
//if hi.ServerName != m.hostname { 这行注释
// fmt.Errorf("cert mismatch with hostname: %q", hi.ServerName) 这行注释
//} 这行注释
// Return a shallow copy of the cert so the caller can append to its
// Certificate field.
certCopy := new(tls.Certificate)
*certCopy = *m.cert
certCopy.Certificate = certCopy.Certificate[:len(certCopy.Certificate):len(certCopy.Certificate)]
return certCopy, nil
}
#创建derp目录
mkdir -p /etc/derp
rm -rf /etc/derp/derper && go build -o /etc/derp/derper
ls /etc/derp
8.1.2 创建自签证书和derp服务
openssl req -x509 -newkey rsa:4096 -sha256 -days 36500 -nodes -keyout /etc/derp/derp.poc.test.com.key -out /etc/derp/derp.poc.test.com.crt -subj "/CN=derp.poc.test.com" -addext "subjectAltName=DNS:derp.poc.test.com"
#如果需要防白嫖可以在ExecStart=/etc/derp/derper后面加上这个参数,但derp节点需要加入到同样vpn中
--verify-clients
cat > /etc/systemd/system/derp.service <<EOF
[Unit]
Description=TS Derper
After=network.target
Wants=network.target
[Service]
User=root
Restart=always
ExecStart=/etc/derp/derper -hostname derp.poc.test.com -a :33445 -http-port 33446 -stun-port 13478 -certmode manual -certdir /etc/derp
RestartPreventExitStatus=1
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable derp
systemctl restart derp
#自己建一个nginx,可以get的到,注意,可以是域名或者ip,如果是家庭公网域名,需要在本地/etc/hosts做本地解析,要不然是连接不上derp服务器。其它客户端不用本地解析
{
"Regions": {
"901": {
"RegionID": 901,
"RegionCode": "my-home-node",
"RegionName": "my-home-node-Derper",
"Nodes": [
{
"Name": "901a",
"RegionID": 901,
"DERPPort": 33445,
"STUNPort": 13478,
"STUNOnly": false,
"HostName": "xxx.com",
"InsecureForTests": true
}
]
}
}
}
8.1.3 配置headscale的derp服务
#修改headscale配置,并重启headscale服务
vim /data/headscale/config/config.yaml
derp:
server:
# If enabled, runs the embedded DERP server and merges it into the rest of the DERP config
# The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place,把这个改为true
enabled: true
# Region ID to use for the embedded DERP server.
# The local DERP prevails if the region ID collides with other region ID coming from
# the regular DERP config.
region_id: 999
# Region code and name are displayed in the Tailscale UI to identify a DERP region
region_code: "headscale"
region_name: "Headscale Embedded DERP"
# Listens over UDP at the configured address for STUN connections - to help with NAT traversal.
# When the embedded DERP server is enabled stun_listen_addr MUST be defined.
#
# For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/
stun_listen_addr: "0.0.0.0:3478"
# List of externally available DERP maps encoded in JSON,把你公开的derp链接放到这里去。注释官方链接
urls:
#- https://controlplane.tailscale.com/derpmap/default
- https://xxx
#重启服务生效
docker restart headscale8.1.4 把端口映射或者防火墙放开33445/tcp和13478/udp端口
9、二进制安装headscale服务端(测试)
9.1.1 下载服务端文件
#挑选适合自己环境的版本下载
https://github.com/juanfont/headscale/releases
#比如
mkdir /etc/headscale;cd /etc/headscale
touch db.sqlite
wget https://github.com/juanfont/headscale/releases/download/v0.22.3/headscale_0.22.3_linux_amd64
#下载后,放到/etc/headscale目录里
cp headscale_0.22.3_linux_amd64 /usr/bin/headscale
chmod +x /usr/bin/headscale
echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.conf
sysctl -p /etc/sysctl.conf9.1.2 配置启动文件
cat > /lib/systemd/system/headscale.service << EOF
[Unit]
After=syslog.target
After=network.target
Description=headscale coordination server for Tailscale
X-Restart-Triggers=/etc/headscale/config.yaml
[Service]
Type=simple
User=root
Group=root
ExecStart=/usr/bin/headscale serve
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF9.1.3 配置服务端配置
vim /etc/headscale/config.yaml
---
server_url: http://xxx.com:8089
listen_addr: 0.0.0.0:8089
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false
private_key_path: /etc/headscale/private.key
noise:
# The Noise private key is used to encrypt the
# traffic between headscale and Tailscale clients when
# using the new Noise-based protocol. It must be different
# from the legacy private key.
private_key_path: /etc/headscale/noise_private.key
#private_key_path: /var/lib/headscale/noise_private.key
ip_prefixes:
#- fd7a:115c:a1e0::/48
- 100.64.0.0/10
derp:
server:
# If enabled, runs the embedded DERP server and merges it into the rest of the DERP config
# The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place
enabled: false
# Region ID to use for the embedded DERP server.
# The local DERP prevails if the region ID collides with other region ID coming from
# the regular DERP config.
region_id: 999
# Region code and name are displayed in the Tailscale UI to identify a DERP region
region_code: "headscale"
region_name: "Headscale Embedded DERP"
# Listens over UDP at the configured address for STUN connections - to help with NAT traversal.
# When the embedded DERP server is enabled stun_listen_addr MUST be defined.
#
# For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/
stun_listen_addr: "0.0.0.0:3478"
# List of externally available DERP maps encoded in JSON
urls:
- https://controlplane.tailscale.com/derpmap/default
# Locally available DERP map files encoded in YAML
#
# This option is mostly interesting for people hosting
# their own DERP servers:
# https://tailscale.com/kb/1118/custom-derp-servers/
#
# paths:
# - /etc/headscale/derp-example.yaml
paths: []
# If enabled, a worker will be set up to periodically
# refresh the given sources and update the derpmap
# will be set up.
auto_update_enabled: true
# How often should we check for DERP updates?
update_frequency: 24h
disable_check_updates: false
ephemeral_node_inactivity_timeout: 30m
node_update_check_interval: 10s
db_type: sqlite3
db_path: /etc/headscale/db.sqlite
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:
# Output formatting for logs: text or json
format: text
level: info
acl_policy_path: ""
dns_config:
# Whether to prefer using Headscale provided DNS or use local.
override_local_dns: true
# List of DNS servers to expose to clients.
nameservers:
- 223.5.5.5
- 8.8.8.8
- 1.1.1.1
# NextDNS (see https://tailscale.com/kb/1218/nextdns/).
# "abc123" is example NextDNS ID, replace with yours.
#
# With metadata sharing:
# nameservers:
# - https://dns.nextdns.io/abc123
#
# Without metadata sharing:
# nameservers:
# - 2a07:a8c0::ab:c123
# - 2a07:a8c1::ab:c123
# Split DNS (see https://tailscale.com/kb/1054/dns/),
# list of search domains and the DNS to query for each one.
#
# restricted_nameservers:
# foo.bar.com:
# - 1.1.1.1
# darp.headscale.net:
# - 1.1.1.1
# - 8.8.8.8
# Search domains to inject.
domains: []
# Extra DNS records
# so far only A-records are supported (on the tailscale side)
# See https://github.com/juanfont/headscale/blob/main/docs/dns-records.md#Limitations
# extra_records:
# - name: "grafana.myvpn.example.com"
# type: "A"
# value: "100.64.0.3"
#
# # you can also put it in one line
# - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" }
# Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/).
# Only works if there is at least a nameserver defined.
magic_dns: true
# Defines the base domain to create the hostnames for MagicDNS.
# `base_domain` must be a FQDNs, without the trailing dot.
# The FQDN of the hosts will be
# `hostname.user.base_domain` (e.g., _myhost.myuser.example.com_).
base_domain: example.com
unix_socket: /var/run/headscale.sock
unix_socket_permission: "0770"
logtail:
# Enable logtail for this headscales clients.
# As there is currently no support for overriding the log server in headscale, this is
# disabled by default. Enabling this will make your clients send logs to Tailscale Inc.
enabled: false
randomize_client_port: true9.1.4 启动服务
systemctl daemon-reload
systemctl restart headscale
systemctl enable headscale10、家宽公网&泛域名证书配置
前置条件:安装好docker服务和docker-compose服务,需要域名一个,如果没域名,可以参考上面步骤自签域名来实现,自签证书不适合下面教程。
注意,需要在托管商dns里加入*解析,如果是静态公网IP直接修改就行了,如果是动态的IP需要通过ddns-go来实现
10.1.1 部署ddns-go
这里是通过cloudflare来代理的,其它的自行百度ddns-go配置,这里不用ipv6,申请一个dns的toke密钥
注意配置secret:的访问密钥,配置用户名和密码username:xxx password: xxx,更改域名domains: xxx.com
mkdir -p /data/ddns-go
vim /data/ddns-go/.ddns_go_config.yaml
dnsconf:
- ipv4:
enable: true
gettype: url
url: https://myip4.ipip.net,https://ddns.oray.com/checkip,https://ip.3322.net,https://4.ipw.cn,https://ifconfig.me
netinterface: ""
cmd: ""
domains:
- '*.xxx.com'
- xxx.com
ipv6:
enable: false
gettype: netInterface
url: https://speed.neu6.edu.cn/getIP.php,https://v6.ident.me,https://6.ipw.cn
netinterface: ""
cmd: ""
ipv6reg: ""
domains:
- ""
dns:
name: cloudflare
id: ""
secret: nFE-xxxxxxx
ttl: ""
user:
username: xxx
password: xxx
webhook:
webhookurl: ""
webhookrequestbody: ""
webhookheaders: ""
notallowwanaccess: false
docker run -d --name ddns-go --restart=always -p 9876:9876 -v /data/ddns-go:/root jeessy/ddns-go
10.1.2 注册免费证书
#安装证书服务国外会GitHub下载失败情况
curl https://get.acme.sh | sh -s email=xxx@qq.com
#国内下载
curl https://gitee.com/zerohacker/other-downloads/raw/master/linux/Centos_x86_64/7/acme.sh/install-acme.sh | sh -s email=xxx@qq.com
mkdir -p /data/certs/
#增加定时自动更新证书
crontab -e
10 23 1 */2 * /usr/bin/bash /data/certs/update-certs.sh
#编写自动更新证书脚本,我这里用的是cf的dns托管,每个运营商都不同,具体去GitHub参考acme.sh的项目
#CF_Key=这个是全局api-key那个,不是区域toke
vim /data/certs/update-certs.sh
export CF_Email="xxx@qq.com"
export CF_Key="xxxxxxxx"
/root/.acme.sh/acme.sh --install-cert --issue --dns dns_cf -d xxx.com -d '*.xxx.com' --key-file /data/certs/privkey.pem --fullchain-file /data/certs/fullchain.pem --force
chmod 644 /data/certs/privkey.pem
#systemctl restart derp
#systemctl restart caddy
#docker restart headscale
#systemctl restart tailscaled
#赋予执行权限
chmod +x /data/certs/update-certs.sh
bash /data/certs/update-certs.sh配置headscale为https访问
前提条件:需要安装好derp服务部署
10.1.3 derp 部署
#derp 部署
#安装必要的工具
apt install -y wget git openssl curl
cd /root/;mkdir go;cd go;
wget https://go.dev/dl/go1.21.0.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version
echo "export PATH=$PATH:/usr/local/go/bin" >> /etc/profile
source /etc/profile
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
go install tailscale.com/cmd/derper@main
#注意此路径由于安装版本不同,@v1.1xxxx会有所不同,其它路径没变化
cd ~/go/pkg/mod/tailscale.com\@v1.1.1-0.20230818020430-af2e4909b6e9/cmd/derper
#创建derp目录
mkdir -p /etc/derp/tls
#如果编辑过程出现版本问题,需要下载新版重新编译
rm -rf /etc/derp/derper && go build -o /etc/derp/derper
ls /etc/derp
#如果需要防白嫖可以在ExecStart=/etc/derp/derper后面加上这个参数,但derp节点需要加入到同样vpn中
--verify-clients
#注意更改域名,这里默认是使用https方式的需要开放33445https端口和13478/udp端口,stun端口可以改
cat > /etc/systemd/system/derp.service <<EOF
[Unit]
Description=TS Derper
After=network.target
Wants=network.target
[Service]
User=root
Restart=always
ExecStart=/etc/derp/derper -hostname derp.xxx.com -a :33445 -http-port 33446 -stun-port 13478 -certmode manual -certdir /etc/derp/tls --verify-clients
RestartPreventExitStatus=1
[Install]
WantedBy=multi-user.target
EOF
#链接证书过去,注意命名文件格式
cd /etc/derp/tls
ln -s /data/certs/fullchain.pem derp.xxx.com.crt
ln -s /data/certs/privkey.pem derp.xxx.com.key
systemctl daemon-reload
systemctl enable derp
systemctl restart derp
#在本地hosts上添加自己的derp解析
cat >> /etc/hosts << EOF
192.168.x.x derp.xxx.com
EOF10.1.4 搭建caddy代理服务
443一般都是被禁用的,自己在路由上把443,转发到你要访问的端口就行了
mkdir -p /etc/caddy/{certs,www/derp};cd /etc/caddy
#下载caddy二进制文件
wget https://caddyserver.com/api/download?os=linux&arch=amd64&idempotency=81291252395604
chmod +x caddy_linux_amd64
cp caddy_linux_amd64 /usr/bin/caddy
#配置启动文件
vim /lib/systemd/system/caddy.service
[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target
[Service]
Type=notify
User=root
Group=root
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
#链接证书
cd /etc/caddy/certs;
ln -s /data/certs/fullchain.pem .
ln -s /data/certs/privkey.pem .
vim /etc/caddy/Caddyfile
https://derp.xxx.com: {
root * /etc/caddy/www/derp
tls /etc/caddy/certs/fullchain.pem /etc/caddy/certs/privkey.pem
file_server
header {
Access-Control-Allow-Origin *.xxx.com
Strict-Transport-Security "max-age=31536000;"
X-XSS-Protection "1; mode=block"
X-Frame-Options "SAMEORIGIN"
X-Robots-Tag "none"
-Server
}
}
在线json格式为:
vim /etc/caddy/www/derp/index.html
{
"Regions": {
"901": {
"RegionID": 901,
"RegionCode": "my-home-node",
"RegionName": "my-home-node-Derper",
"Nodes": [
{
"Name": "901a",
"RegionID": 901,
"DERPPort": 33445,
"STUNPort": 13478,
"STUNOnly": false,
"HostName": "derp.xxx.com"
}
]
}
}
}
#启动服务
systemctl daemon-reload
systemctl enable caddy
systemctl restart caddy10.1.5 配置headscale服务
注意更改在线json链接,证书路径
echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
mkdir -p /data/headscale/config
mkdir -p /data/headscale/data
cd /data/headscale/data
touch db.sqlite
cd /data/headscale/config;
#配置你的域名
vim config.yamlvim /data/headscale/config/config.yaml
---
# headscale will look for a configuration file named `config.yaml` (or `config.json`) in the following order:
#
# - `/etc/headscale`
# - `~/.headscale`
# - current working directory
# The url clients will connect to.
# Typically this will be a domain like:
#
# https://myheadscale.example.com:443
#
server_url: https://headscale.xxx.com:53450
# Address to listen to / bind to on the server
#
# For production:
listen_addr: 0.0.0.0:53450
#listen_addr: 127.0.0.1:8080
#tls:
# cert: /data/caddy/certs/fullchain.pem
# key: /data/caddy/certs/privkey.pem
# redirect_http_to_https: false
# Address to listen to /metrics, you may want
# to keep this endpoint private to your internal
# network
#
metrics_listen_addr: 127.0.0.1:9090
# Address to listen for gRPC.
# gRPC is used for controlling a headscale server
# remotely with the CLI
# Note: Remote access _only_ works if you have
# valid certificates.
#
# For production:
# grpc_listen_addr: 0.0.0.0:50443
grpc_listen_addr: 127.0.0.1:50443
# Allow the gRPC admin interface to run in INSECURE
# mode. This is not recommended as the traffic will
# be unencrypted. Only enable if you know what you
# are doing.
grpc_allow_insecure: false
# Private key used to encrypt the traffic between headscale
# and Tailscale clients.
# The private key file will be autogenerated if it's missing.
#
private_key_path: /var/lib/headscale/private.key
# The Noise section includes specific configuration for the
# TS2021 Noise protocol
noise:
# The Noise private key is used to encrypt the
# traffic between headscale and Tailscale clients when
# using the new Noise-based protocol. It must be different
# from the legacy private key.
private_key_path: /var/lib/headscale/noise_private.key
# List of IP prefixes to allocate tailaddresses from.
# Each prefix consists of either an IPv4 or IPv6 address,
# and the associated prefix length, delimited by a slash.
# It must be within IP ranges supported by the Tailscale
# client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48.
# See below:
# IPv6: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#LL81C52-L81C71
# IPv4: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#L33
# Any other range is NOT supported, and it will cause unexpected issues.
ip_prefixes:
# - fd7a:115c:a1e0::/48
- 100.64.0.0/10
# DERP is a relay system that Tailscale uses when a direct
# connection cannot be established.
# https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp
#
# headscale needs a list of DERP servers that can be presented
# to the clients.
derp:
server:
# If enabled, runs the embedded DERP server and merges it into the rest of the DERP config
# The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place
enabled: true
# enabled: true
# Region ID to use for the embedded DERP server.
# The local DERP prevails if the region ID collides with other region ID coming from
# the regular DERP config.
region_id: 999
# Region code and name are displayed in the Tailscale UI to identify a DERP region
region_code: "headscale"
region_name: "Headscale Embedded DERP"
# Listens over UDP at the configured address for STUN connections - to help with NAT traversal.
# When the embedded DERP server is enabled stun_listen_addr MUST be defined.
#
# For more details on how this works, check this great article: https://tailscale.com/blog/how-tailscale-works/
stun_listen_addr: "0.0.0.0:3478"
# List of externally available DERP maps encoded in JSON
urls:
# - https://controlplane.tailscale.com/derpmap/default
- https://xxx.com/derp.json
# Locally available DERP map files encoded in YAML
#
# This option is mostly interesting for people hosting
# their own DERP servers:
# https://tailscale.com/kb/1118/custom-derp-servers/
#
paths:
# - /etc/headscale/derp-example.yaml
# If enabled, a worker will be set up to periodically
# refresh the given sources and update the derpmap
# will be set up.
auto_update_enabled: true
# How often should we check for DERP updates?
update_frequency: 24h
# Disables the automatic check for headscale updates on startup
disable_check_updates: false
# Time before an inactive ephemeral node is deleted?
ephemeral_node_inactivity_timeout: 30m
# Period to check for node updates within the tailnet. A value too low will severely affect
# CPU consumption of Headscale. A value too high (over 60s) will cause problems
# for the nodes, as they won't get updates or keep alive messages frequently enough.
# In case of doubts, do not touch the default 10s.
node_update_check_interval: 10s
# SQLite config
db_type: sqlite3
# For production:
db_path: /var/lib/headscale/db.sqlite
# # Postgres config
# If using a Unix socket to connect to Postgres, set the socket path in the 'host' field and leave 'port' blank.
# db_type: postgres
# db_host: localhost
# db_port: 5432
# db_name: headscale
# db_user: foo
# db_pass: bar
# If other 'sslmode' is required instead of 'require(true)' and 'disabled(false)', set the 'sslmode' you need
# in the 'db_ssl' field. Refers to https://www.postgresql.org/docs/current/libpq-ssl.html Table 34.1.
# db_ssl: false
### TLS configuration
#
## Let's encrypt / ACME
#
# headscale supports automatically requesting and setting up
# TLS for a domain with Let's Encrypt.
#
# URL to ACME directory
acme_url: https://acme-v02.api.letsencrypt.org/directory
# Email to register with ACME provider
acme_email: ""
# Domain name to request a TLS certificate for:
tls_letsencrypt_hostname: ""
# Path to store certificates and metadata needed by
# letsencrypt
# For production:
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
# Type of ACME challenge to use, currently supported types:
# HTTP-01 or TLS-ALPN-01
# See [docs/tls.md](docs/tls.md) for more information
tls_letsencrypt_challenge_type: HTTP-01
# When HTTP-01 challenge is chosen, letsencrypt must set up a
# verification endpoint, and it will be listening on:
# :http = port 80
tls_letsencrypt_listen: ":http"
## Use already defined certificates:
tls_cert_path: "/certs/fullchain.pem"
tls_key_path: "/certs/privkey.pem"
log:
# Output formatting for logs: text or json
format: text
level: info
# Path to a file containg ACL policies.
# ACLs can be defined as YAML or HUJSON.
# https://tailscale.com/kb/1018/acls/
acl_policy_path: ""
## DNS
#
# headscale supports Tailscale's DNS configuration and MagicDNS.
# Please have a look to their KB to better understand the concepts:
#
# - https://tailscale.com/kb/1054/dns/
# - https://tailscale.com/kb/1081/magicdns/
# - https://tailscale.com/blog/2021-09-private-dns-with-magicdns/
#
dns_config:
# Whether to prefer using Headscale provided DNS or use local.
override_local_dns: true
# List of DNS servers to expose to clients.
nameservers:
- 223.5.5.5
- 114.114.114.114
- 8.8.8.8
- 1.1.1.1
# NextDNS (see https://tailscale.com/kb/1218/nextdns/).
# "abc123" is example NextDNS ID, replace with yours.
#
# With metadata sharing:
# nameservers:
# - https://dns.nextdns.io/abc123
#
# Without metadata sharing:
# nameservers:
# - 2a07:a8c0::ab:c123
# - 2a07:a8c1::ab:c123
# Split DNS (see https://tailscale.com/kb/1054/dns/),
# list of search domains and the DNS to query for each one.
#
# restricted_nameservers:
# foo.bar.com:
# - 1.1.1.1
# darp.headscale.net:
# - 1.1.1.1
# - 8.8.8.8
# Search domains to inject.
domains: []
# Extra DNS records
# so far only A-records are supported (on the tailscale side)
# See https://github.com/juanfont/headscale/blob/main/docs/dns-records.md#Limitations
# extra_records:
# - name: "grafana.myvpn.example.com"
# type: "A"
# value: "100.64.0.3"
#
# # you can also put it in one line
# - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" }
# Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/).
# Only works if there is at least a nameserver defined.
magic_dns: true
# Defines the base domain to create the hostnames for MagicDNS.
# `base_domain` must be a FQDNs, without the trailing dot.
# The FQDN of the hosts will be
# `hostname.user.base_domain` (e.g., _myhost.myuser.example.com_).
base_domain: example.com
# Unix socket used for the CLI to connect without authentication
# Note: for production you will want to set this to something like:
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
#
# headscale supports experimental OpenID connect support,
# it is still being tested and might have some bugs, please
# help us test it.
# OpenID Connect
# oidc:
# only_start_if_oidc_is_available: true
# issuer: "https://your-oidc.issuer.com/path"
# client_id: "your-oidc-client-id"
# client_secret: "your-oidc-client-secret"
# # Alternatively, set `client_secret_path` to read the secret from the file.
# # It resolves environment variables, making integration to systemd's
# # `LoadCredential` straightforward:
# client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"
# # client_secret and client_secret_path are mutually exclusive.
#
# # The amount of time from a node is authenticated with OpenID until it
# # expires and needs to reauthenticate.
# # Setting the value to "0" will mean no expiry.
# expiry: 180d
#
# # Use the expiry from the token received from OpenID when the user logged
# # in, this will typically lead to frequent need to reauthenticate and should
# # only been enabled if you know what you are doing.
# # Note: enabling this will cause `oidc.expiry` to be ignored.
# use_expiry_from_token: false
#
# # Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query
# # parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email".
#
# scope: ["openid", "profile", "email", "custom"]
# extra_params:
# domain_hint: example.com
#
# # List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the
# # authentication request will be rejected.
#
# allowed_domains:
# - example.com
# # Note: Groups from keycloak have a leading '/'
# allowed_groups:
# - /headscale
# allowed_users:
# - alice@example.com
#
# # If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed.
# # This will transform `first-name.last-name@example.com` to the user `first-name.last-name`
# # If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following
# user: `first-name.last-name.example.com`
#
# strip_email_domain: true
# Logtail configuration
# Logtail is Tailscales logging and auditing infrastructure, it allows the control panel
# to instruct tailscale nodes to log their activity to a remote server.
logtail:
# Enable logtail for this headscales clients.
# As there is currently no support for overriding the log server in headscale, this is
# disabled by default. Enabling this will make your clients send logs to Tailscale Inc.
enabled: false
# Enabling this option makes devices prefer a random port for WireGuard traffic over the
# default static port 41641. This option is intended as a workaround for some buggy
# firewall devices. See https://tailscale.com/kb/1181/firewalls/ for more information.
randomize_client_port: true10.1.1 docker-compose启动
cd /data/headscale/
vim docker-compose.yml
version: "3.4"
services:
headscale:
image: headscale/headscale:0.22.3
container_name: headscale
restart: unless-stopped
entrypoint: headscale serve
volumes:
- /data/headscale/config:/etc/headscale/
- /data/headscale/data:/var/lib/headscale/
- /data/certs:/certs
ports:
- "53450:53450"
- "9090:9090"
#启动docker服务
docker-compose -f docker-compose.yml up -d --force-recreate10.1.3 配置caddyfile
vim Caddyfile
#增加这条,域名和证书自己准备好
https://tailscale.xxx域名: {
tls /etc/caddy/fullchain.pem /etc/caddy/privkey.pem
header {
Access-Control-Allow-Origin *.xxx.com
Strict-Transport-Security "max-age=31536000;"
X-XSS-Protection "1; mode=block"
X-Frame-Options "SAMEORIGIN"
X-Robots-Tag "none"
-Server
}
reverse_proxy http://headscale.这里域名为headscale配置文件里的域名和端口:52014
}10.1.4 注意
然后把你的代理caddy的https端口开放,用https://tailscale.xxx域名:端口,就可以访问你自己的headscale服务了
采用https后手机端设置自己服务器点登录是会一直转圈圈的,命令:docker logs -f headscale 后台看headscale日志,会有弹出手机端发来的请求注册密钥,手动注册就行了。windows就没这个问题,linux也是。
日志如下:
#!/bin/sh
echo "======== start clean docker containers logs ========"
logs=$(find /var/lib/docker/containers/ -name *-json.log)
for log in $logs
do
echo "clean logs : $log"
cat /dev/null > $log
done
echo "======== end clean docker containers logs ========"
# chmod +x clean_docker_log.sh
# ./clean_docker_log.sh
tmp_names=$(docker ps | grep headscale| awk '{print $1}')
tmp_logs=$(find /var/lib/docker/containers/ -name $tmp_names*-json.log)
tail -f $tmp_logs
2023-08-24T13:24:08Z INF go/src/headscale/hscontrol/protocol_common.go:574 > Successfully sent auth url AuthURL=http://headscale.xxx.com:52014/register/nodekey:70bed72eb610435e9c4cd361224f419d1f0ba7533a338b801bd434002a3acb52 machine="Xiaomi 13Pro" noise=true命令:
#default是用户
手动注册命令:
headscale --user default nodes register --key nodekey:70bed72eb610435e9c4cd361224f419d1f0ba7533a338b801bd434002a3acb52不停的报错误日志:
#从系统日志可以看到tailscaled服务一直会报这个错误,是因为国内被墙了,是访问不到的
Aug 27 14:19:58 localhost tailscaled[338784]: logtail: dial "log.tailscale.io:443" failed: dial tcp 54.161.152.147:443: i/o timeout (in 30.001s), trying bootstrap...
#解决思路,在有安装tailscale客户端的机器上加上log.tailscale.io,把解析指向本地就好了,但derp服务端要开启443端口的服务caddy,或者nginx,httpd。先把第一台客户端加入headscale里面去就是derp服务端了