forked from yuehen7/headscale-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.sh
433 lines (376 loc) · 9.66 KB
/
main.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
#!/bin/bash
plain='\033[0m'
red='\033[0;31m'
blue='\033[1;34m'
pink='\033[1;35m'
green='\033[0;32m'
yellow='\033[0;33m'
OS_ARCH=''
HOME_PATH='/etc/headscale'
DATA_PATH='/var/lib/headscale'
TEMP_PATH='/var/run/headscale'
BINARY_FILE_PATH='/usr/local/bin/headscale'
SERVICE_FILE_PATH='/etc/systemd/system/headscale.service'
declare -r STATUS_RUNNING=1
declare -r STATUS_NOT_RUNNING=0
declare -r STATUS_NOT_INSTALL=255
function LOGE() {
echo -e "${red}[ERR] $* ${plain}"
}
function LOGI() {
echo -e "${green}[INF] $* ${plain}"
}
function LOGD() {
echo -e "${yellow}[DEG] $* ${plain}"
}
arch_check() {
LOGI "检测当前系统架构中..."
OS_ARCH=$(arch)
LOGI "当前系统架构为 ${OS_ARCH}"
if [[ ${OS_ARCH} == "x86_64" || ${OS_ARCH} == "x64" || ${OS_ARCH} == "amd64" ]]; then
OS_ARCH="amd64"
elif [[ ${OS_ARCH} == "aarch64" || ${OS_ARCH} == "arm64" ]]; then
OS_ARCH="arm64"
else
OS_ARCH="amd64"
LOGE "检测系统架构失败,使用默认架构: ${OS_ARCH}"
fi
LOGI "系统架构检测完毕,当前系统架构为:${OS_ARCH}"
}
create_or_delete_path() {
if [[ $# -ne 1 ]]; then
LOGE "invalid input,should be one paremete,and can be 0 or 1"
exit 1
fi
if [[ "$1" == "1" ]]; then
LOGI "Will create ${HOME_PATH} and ${DATA_PATH} and ${TEMP_PATH} for headscale..."
rm -rf ${HOME_PATH} ${DATA_PATH} ${TEMP_PATH} /home/headscale
mkdir -p ${HOME_PATH} ${DATA_PATH} ${TEMP_PATH} /home/headscale
if [[ $? -ne 0 ]]; then
LOGE "create ${HOME_PATH} and ${DATA_PATH} and ${TEMP_PATH} for headscale failed"
exit 1
else
LOGI "create ${HOME_PATH} adn ${DATA_PATH} and ${TEMP_PATH} for headscale success"
fi
elif [[ "$1" == "0" ]]; then
LOGI "Will delete ${HOME_PATH} and ${DATA_PATH} and ${TEMP_PATH}..."
rm -rf ${HOME_PATH} ${DATA_PATH} ${TEMP_PATH} /home/headscale
if [[ $? -ne 0 ]]; then
LOGE "delete ${HOME_PATH} and ${DATA_PATH} and ${TEMP_PATH} failed"
exit 1
else
LOGI "delete ${HOME_PATH} and ${DATA_PATH} and ${TEMP_PATH} success"
fi
fi
}
download_headscale() {
LOGD "开始下载headscale..."
arch_check
local headscale_version_temp=$(curl -Ls "https://api.github.com/repos/juanfont/headscale/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
headscale_version=${headscale_version_temp:1}
LOGI "将选择使用版本:${headscale_version}"
local DOWANLOAD_URL="https://github.com/juanfont/headscale/releases/download/${headscale_version_temp}/headscale_${headscale_version}_linux_${OS_ARCH}"
create_or_delete_path 1
wget --output-document=${BINARY_FILE_PATH} ${DOWANLOAD_URL}
chmod +x ${BINARY_FILE_PATH}
if [[ $? -ne 0 ]]; then
LOGE "Download headscale failed,plz be sure that your network work properly and can access github"
create_or_delete_path 0
exit 1
else
LOGI "下载headscale成功"
fi
}
install_service() {
LOGD "开始安装headscale systemd服务..."
if [ -f "${SERVICE_FILE_PATH}" ]; then
rm -rf ${SERVICE_FILE_PATH}
fi
touch ${SERVICE_FILE_PATH}
if [ $? -ne 0 ]; then
LOGE "create service file failed,exit"
exit 1
else
LOGI "create service file success..."
fi
cat >${SERVICE_FILE_PATH} <<EOF
[Unit]
Description=headscale controller
After=syslog.target
After=network.target
[Service]
Type=simple
User=headscale
Group=headscale
ExecStart=${BINARY_FILE_PATH} serve
Restart=on-failure
RestartSec=30s
RestartPreventExitStatus=23
LimitNPROC=10000
LimitNOFILE=1000000
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=${DATA_PATH} ${TEMP_PATH}
AmbientCapabilities=CAP_NET_BIND_SERVICE
RuntimeDirectory=headscale
[Install]
WantedBy=multi-user.target
EOF
chmod 644 ${SERVICE_FILE_PATH}
systemctl daemon-reload
LOGD "安装headscale systemd服务成功"
}
config_headscale() {
touch ${DATA_PATH}/db.sqlite
useradd headscale -d /home/headscale -m
chown -R headscale:headscale ${DATA_PATH}
touch ${HOME_PATH}/config.yaml
if [ $? -ne 0 ]; then
LOGE "create config.yaml file failed,exit"
exit 1
else
LOGI "create config.yaml file success..."
fi
ip=`curl -sL -4 ip.sb`
echo ""
read -p " 请输入服务端口[100-65535的一个数字,默认8080]:" port
[[ -z "${port}" ]] && port=8080
if [[ "${port:0:1}" = "0" ]]; then
LOGE "端口不能以0开头${plain}"
exit 1
fi
LOGI " 服务地址为:http://${ip}:${port}"
cat >${HOME_PATH}/config.yaml <<EOF
server_url: http://${ip}:${port}
listen_addr: 0.0.0.0:${port}
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 0.0.0.0:50443
grpc_allow_insecure: false
private_key_path: ${DATA_PATH}/private.key
noise:
private_key_path: ${DATA_PATH}/noise_private.key
ip_prefixes:
- fd7a:115c:a1e0::/48
- 172.16.0.0/16
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: ${DATA_PATH}/db.sqlite
acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: ""
tls_letsencrypt_hostname: ""
tls_client_auth_mode: relaxed
tls_letsencrypt_cache_dir: ${DATA_PATH}/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:
- 8.8.8.8
domains: []
magic_dns: false
base_domain: example.com
unix_socket: ${TEMP_PATH}/headscale.sock
unix_socket_permission: "0770"
logtail:
enabled: false
randomize_client_port: false
EOF
}
enable_headscale() {
systemctl enable headscale
if [[ $? == 0 ]]; then
LOGI "设置headscale开机自启成功"
else
LOGE "设置headscale开机自启失败"
fi
}
start_headscale() {
if [ -f "${SERVICE_FILE_PATH}" ]; then
systemctl start headscale
sleep 1s
status_check
if [ $? == ${STATUS_NOT_RUNNING} ]; then
LOGE "start headscale service failed,exit"
exit 1
elif [ $? == ${STATUS_RUNNING} ]; then
LOGI "start headscale service success"
fi
else
LOGE "${SERVICE_FILE_PATH} does not exist,can not start service"
exit 1
fi
}
restart_headscale() {
if [ -f "${SERVICE_FILE_PATH}" ]; then
systemctl restart headscale
sleep 1s
status_check
if [ $? == 0 ]; then
LOGE "restart headscale service failed,exit"
exit 1
elif [ $? == 1 ]; then
LOGI "restart headscale service success"
fi
else
LOGE "${SERVICE_FILE_PATH} does not exist,can not restart service"
exit 1
fi
}
stop_headscale() {
LOGD "开始停止headscale服务..."
status_check
if [ $? == ${STATUS_NOT_INSTALL} ]; then
LOGE "headscale did not install,can not stop it"
exit 1
elif [ $? == ${STATUS_NOT_RUNNING} ]; then
LOGI "headscale already stoped,no need to stop it again"
exit 1
elif [ $? == ${STATUS_RUNNING} ]; then
if ! systemctl stop headscale; then
LOGE "stop headscale service failed,plz check logs"
exit 1
fi
fi
LOGD "停止headscale服务成功"
}
install_headscale() {
LOGD "开始安装headscale..."
if [[ $# -ne 0 ]]; then
download_headscale $1
else
download_headscale
fi
config_headscale
install_service
enable_headscale && start_headscale
headscale namespaces create default
LOGI "安装headscale成功,已启动成功"
}
uninstall_headscale() {
echo ""
LOGD "开始卸载headscale..."
pidOfheadscale=$(pidof headscale)
if [ -n ${pidOfheadscale} ]; then
stop_headscale
fi
create_or_delete_path 0 && rm -rf ${SERVICE_FILE_PATH} && rm -rf ${BINARY_FILE_PATH}
userdel -r headscale
groupdel headscale
if [ $? -ne 0 ]; then
LOGE "卸载headscale失败,请检查日志"
exit 1
else
LOGI "卸载headscale成功"
fi
}
register_node() {
echo ""
while true
do
read -p "请输入key:" key
if [[ -z "${key}" ]]; then
LOGE "输入错误,请重新输入!${plain}"
else
break
fi
done
LOGI "输入的key为:$key"
headscale -n default nodes register --key $key
headscale nodes list
}
status_check() {
if [[ ! -f "${SERVICE_FILE_PATH}" ]]; then
return ${STATUS_NOT_INSTALL}
fi
temp=$(systemctl status headscale | grep Active | awk '{print $3}' | cut -d "(" -f2 | cut -d ")" -f1)
if [[ x"${temp}" == x"running" ]]; then
return ${STATUS_RUNNING}
else
return ${STATUS_NOT_RUNNING}
fi
}
show_status() {
status_check
case $? in
0)
echo -e "[INF] headscale状态: ${yellow}未运行${plain}"
;;
1)
echo -e "[INF] headscale状态: ${green}已运行${plain}"
;;
255)
echo -e "[INF] headscale状态: ${red}未安装${plain}"
;;
esac
}
show_menu() {
echo -e "
${green}headscale管理脚本${plain}
${green}0.${plain} 退出脚本
${green}1.${plain} 安装服务
${green}2.${plain} 卸载服务
${green}3.${plain} 启动服务
${green}4.${plain} 停止服务
${green}5.${plain} 重启服务
${green}6.${plain} 查看节点
${green}7.${plain} 添加节点
"
show_status
echo && read -p "请输入选择[0-7]:" num
case "${num}" in
0)
exit 0
;;
1)
install_headscale && show_menu
;;
2)
uninstall_headscale && show_menu
;;
3)
start_headscale && show_menu
;;
4)
stop_headscale && show_menu
;;
5)
restart_headscale && show_menu
;;
6)
headscale nodes list && show_menu
;;
7)
register_node && show_menu
;;
*)
LOGE "请输入正确的选项 [0-7]"
;;
esac
}
start_to_run() {
clear
show_menu
}
start_to_run