571 lines
15 KiB
Bash
571 lines
15 KiB
Bash
#!/bin/bash
|
||
|
||
# Tailscale DERP 服务器一键安装脚本 (支持自签名IP证书)
|
||
# 本脚本适用于 Ubuntu/Debian 系统
|
||
|
||
set -e
|
||
|
||
# 颜色定义
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# 日志函数
|
||
log_info() {
|
||
echo -e "${GREEN}[INFO]${NC} $1"
|
||
}
|
||
|
||
log_warn() {
|
||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||
}
|
||
|
||
log_error() {
|
||
echo -e "${RED}[ERROR]${NC} $1"
|
||
}
|
||
|
||
# 检查是否为root用户
|
||
check_root() {
|
||
if [[ $EUID -ne 0 ]]; then
|
||
log_error "此脚本需要以root权限运行"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 检查系统类型
|
||
check_system() {
|
||
if [[ ! -f /etc/os-release ]]; then
|
||
log_error "无法检测系统类型"
|
||
exit 1
|
||
fi
|
||
|
||
source /etc/os-release
|
||
case $ID in
|
||
ubuntu|debian)
|
||
PACKAGE_MANAGER="apt"
|
||
;;
|
||
centos|rhel|fedora)
|
||
PACKAGE_MANAGER="yum"
|
||
;;
|
||
*)
|
||
log_error "不支持的系统类型: $ID"
|
||
exit 1
|
||
;;
|
||
esac
|
||
|
||
log_info "检测到系统: $PRETTY_NAME"
|
||
}
|
||
|
||
# 安装依赖
|
||
install_dependencies() {
|
||
log_info "安装依赖包..."
|
||
|
||
case $PACKAGE_MANAGER in
|
||
apt)
|
||
apt update
|
||
apt install -y curl wget git build-essential openssl nginx
|
||
;;
|
||
yum)
|
||
yum update -y
|
||
yum install -y curl wget git gcc make openssl nginx
|
||
;;
|
||
esac
|
||
|
||
log_info "依赖包安装完成"
|
||
}
|
||
|
||
# 启用BBR优化
|
||
enable_bbr() {
|
||
log_info "启用BBR网络优化..."
|
||
|
||
# 检查内核版本
|
||
KERNEL_VERSION=$(uname -r | cut -d. -f1-2)
|
||
KERNEL_MAJOR=$(echo $KERNEL_VERSION | cut -d. -f1)
|
||
KERNEL_MINOR=$(echo $KERNEL_VERSION | cut -d. -f2)
|
||
|
||
if [[ $KERNEL_MAJOR -lt 4 ]] || [[ $KERNEL_MAJOR -eq 4 && $KERNEL_MINOR -lt 9 ]]; then
|
||
log_warn "内核版本过低 ($KERNEL_VERSION),BBR需要4.9+版本"
|
||
return
|
||
fi
|
||
|
||
# 检查BBR是否已启用
|
||
if sysctl net.ipv4.tcp_congestion_control | grep -q bbr; then
|
||
log_info "BBR已经启用"
|
||
return
|
||
fi
|
||
|
||
# 备份原始配置
|
||
cp /etc/sysctl.conf /etc/sysctl.conf.backup.$(date +%Y%m%d_%H%M%S)
|
||
|
||
# 添加BBR配置
|
||
cat >> /etc/sysctl.conf << EOF
|
||
|
||
# BBR网络优化配置
|
||
net.core.default_qdisc = fq
|
||
net.ipv4.tcp_congestion_control = bbr
|
||
|
||
# 其他网络优化参数
|
||
net.ipv4.tcp_rmem = 8192 262144 536870912
|
||
net.ipv4.tcp_wmem = 4096 16384 536870912
|
||
net.core.rmem_max = 536870912
|
||
net.core.wmem_max = 536870912
|
||
net.core.netdev_max_backlog = 30000
|
||
net.ipv4.tcp_slow_start_after_idle = 0
|
||
EOF
|
||
|
||
# 应用配置
|
||
sysctl -p
|
||
|
||
# 验证BBR是否启用成功
|
||
if sysctl net.ipv4.tcp_congestion_control | grep -q bbr; then
|
||
log_info "BBR启用成功"
|
||
else
|
||
log_error "BBR启用失败"
|
||
fi
|
||
|
||
# 显示当前拥塞控制算法
|
||
log_info "当前拥塞控制算法: $(sysctl -n net.ipv4.tcp_congestion_control)"
|
||
}
|
||
|
||
# 安装Go环境
|
||
install_go() {
|
||
log_info "安装Go环境..."
|
||
|
||
# 检查Go是否已安装
|
||
if command -v go &> /dev/null; then
|
||
log_info "Go已经安装,版本: $(go version)"
|
||
# 设置Go代理
|
||
export GOPROXY=https://goproxy.cn,direct
|
||
echo 'export GOPROXY=https://goproxy.cn,direct' >> /etc/profile
|
||
return
|
||
fi
|
||
|
||
# 下载并安装Go
|
||
GO_VERSION="1.23.3"
|
||
wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz
|
||
tar -zxvf go${GO_VERSION}.linux-amd64.tar.gz
|
||
rm go${GO_VERSION}.linux-amd64.tar.gz
|
||
|
||
# 移动到正确位置
|
||
mv go /usr/local/
|
||
|
||
# 设置环境变量
|
||
export PATH=$PATH:/usr/local/go/bin
|
||
echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile
|
||
|
||
# 设置Go代理
|
||
export GOPROXY=https://goproxy.cn,direct
|
||
echo 'export GOPROXY=https://goproxy.cn,direct' >> /etc/profile
|
||
|
||
log_info "Go环境安装完成"
|
||
}
|
||
|
||
# 编译DERP服务器
|
||
compile_derp() {
|
||
log_info "编译DERP服务器..."
|
||
|
||
# 创建工作目录
|
||
mkdir -p /home/derp
|
||
cd /home/derp
|
||
|
||
# 设置Go代理
|
||
export GOPROXY=https://goproxy.cn,direct
|
||
|
||
# 直接从源码构建derper二进制文件
|
||
log_info "从源码构建derper二进制文件..."
|
||
/usr/local/go/bin/go install tailscale.com/cmd/derper@main
|
||
|
||
# 查找编译后的二进制文件
|
||
GOPATH=$(go env GOPATH)
|
||
if [[ -z "$GOPATH" ]]; then
|
||
GOPATH="$HOME/go"
|
||
fi
|
||
|
||
# 复制到工作目录
|
||
if [[ -f "$GOPATH/bin/derper" ]]; then
|
||
cp "$GOPATH/bin/derper" /home/derp/
|
||
else
|
||
log_error "未找到编译后的derper二进制文件"
|
||
exit 1
|
||
fi
|
||
|
||
# 验证编译结果
|
||
if [[ ! -f /home/derp/derper ]]; then
|
||
log_error "DERP服务器编译失败"
|
||
exit 1
|
||
fi
|
||
|
||
log_info "DERP服务器编译完成"
|
||
}
|
||
|
||
# 配置用户提供的证书
|
||
configure_user_cert() {
|
||
log_info "配置用户提供的证书..."
|
||
|
||
# 获取服务器IP地址
|
||
read -p "请输入服务器IP地址: " SERVER_IP
|
||
|
||
if [[ -z "$SERVER_IP" ]]; then
|
||
log_error "IP地址不能为空"
|
||
exit 1
|
||
fi
|
||
|
||
# 获取证书文件路径
|
||
read -p "请输入证书文件路径 (.crt/.pem文件): " CERT_PATH
|
||
|
||
if [[ -z "$CERT_PATH" ]]; then
|
||
log_error "证书文件路径不能为空"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ ! -f "$CERT_PATH" ]]; then
|
||
log_error "证书文件不存在: $CERT_PATH"
|
||
exit 1
|
||
fi
|
||
|
||
# 获取私钥文件路径
|
||
read -p "请输入私钥文件路径 (.key文件): " KEY_PATH
|
||
|
||
if [[ -z "$KEY_PATH" ]]; then
|
||
log_error "私钥文件路径不能为空"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ ! -f "$KEY_PATH" ]]; then
|
||
log_error "私钥文件不存在: $KEY_PATH"
|
||
exit 1
|
||
fi
|
||
|
||
# 创建证书目录
|
||
mkdir -p /etc/derper/certs
|
||
|
||
# 复制证书文件
|
||
cp "$CERT_PATH" /etc/derper/certs/server.crt
|
||
cp "$KEY_PATH" /etc/derper/certs/server.key
|
||
|
||
# 设置证书权限
|
||
chmod 600 /etc/derper/certs/server.key
|
||
chmod 644 /etc/derper/certs/server.crt
|
||
|
||
# 验证证书
|
||
if ! openssl x509 -in /etc/derper/certs/server.crt -noout -text > /dev/null 2>&1; then
|
||
log_error "证书文件格式无效"
|
||
exit 1
|
||
fi
|
||
|
||
# 验证私钥
|
||
if ! openssl rsa -in /etc/derper/certs/server.key -check -noout > /dev/null 2>&1; then
|
||
log_error "私钥文件格式无效"
|
||
exit 1
|
||
fi
|
||
|
||
# 计算证书哈希
|
||
CERT_HASH=$(openssl x509 -in /etc/derper/certs/server.crt -noout -fingerprint -sha256 | cut -d= -f2 | tr -d : | tr '[:upper:]' '[:lower:]')
|
||
|
||
log_info "证书配置完成"
|
||
log_info "证书SHA256哈希: $CERT_HASH"
|
||
|
||
# 保存配置信息
|
||
echo "SERVER_IP=$SERVER_IP" > /etc/derper/config
|
||
echo "CERT_HASH=$CERT_HASH" >> /etc/derper/config
|
||
echo "CERT_PATH=$CERT_PATH" >> /etc/derper/config
|
||
echo "KEY_PATH=$KEY_PATH" >> /etc/derper/config
|
||
}
|
||
|
||
# 安装Tailscale客户端
|
||
install_tailscale() {
|
||
log_info "安装Tailscale客户端..."
|
||
|
||
# 使用xEdge镜像安装Tailscale (国内优化)
|
||
log_info "使用xEdge镜像安装Tailscale..."
|
||
curl -fsSL https://ts-mirror.xedge.cc/install.sh | sh
|
||
|
||
# 如果xEdge镜像失败,回退到官方安装
|
||
if ! command -v tailscale &> /dev/null; then
|
||
log_warn "xEdge镜像安装失败,尝试官方镜像..."
|
||
curl -fsSL https://tailscale.com/install.sh | sh
|
||
fi
|
||
|
||
log_info "Tailscale客户端安装完成"
|
||
log_warn "请运行 'tailscale up' 来连接到您的Tailnet网络"
|
||
}
|
||
|
||
# 创建systemd服务
|
||
create_systemd_service() {
|
||
log_info "创建systemd服务..."
|
||
|
||
# 读取配置
|
||
source /etc/derper/config
|
||
|
||
# 显示运行模式选择
|
||
echo "请选择DERP服务器运行模式:"
|
||
echo "1. 直接使用自签名证书的HTTPS模式 (推荐)"
|
||
echo "2. Nginx反向代理模式"
|
||
echo "3. 自定义配置"
|
||
read -p "请输入选择 (1-3): " DERP_MODE
|
||
|
||
case $DERP_MODE in
|
||
1)
|
||
# 直接HTTPS模式,使用自签名证书
|
||
DERP_CMD="/home/derp/derper -hostname $SERVER_IP -certmode manual -certdir /etc/derper/certs -a :443 -http-port 80 -stun-port 3478 -verify-clients"
|
||
;;
|
||
2)
|
||
# Nginx反向代理模式
|
||
DERP_CMD="/home/derp/derper -hostname $SERVER_IP -a :8080 -stun-port 3478 -verify-clients"
|
||
;;
|
||
3)
|
||
# 自定义配置
|
||
read -p "请输入自定义命令参数: " CUSTOM_ARGS
|
||
DERP_CMD="/home/derp/derper -hostname $SERVER_IP $CUSTOM_ARGS"
|
||
;;
|
||
*)
|
||
log_warn "无效选择,使用默认配置"
|
||
DERP_CMD="/home/derp/derper -hostname $SERVER_IP -a :8080 -stun-port 3478 -verify-clients"
|
||
;;
|
||
esac
|
||
|
||
cat > /etc/systemd/system/derper.service << EOF
|
||
[Unit]
|
||
Description=Tailscale DERP Server
|
||
After=network.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
User=root
|
||
WorkingDirectory=/home/derp
|
||
ExecStart=$DERP_CMD
|
||
Restart=always
|
||
RestartSec=5
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
|
||
# 保存运行模式到配置文件
|
||
echo "DERP_MODE=$DERP_MODE" >> /etc/derper/config
|
||
echo "DERP_CMD='$DERP_CMD'" >> /etc/derper/config
|
||
|
||
# 重载systemd并启动服务
|
||
systemctl daemon-reload
|
||
systemctl enable derper
|
||
|
||
log_info "systemd服务创建完成"
|
||
}
|
||
|
||
# 配置Nginx反向代理
|
||
configure_nginx() {
|
||
# 读取配置
|
||
source /etc/derper/config
|
||
|
||
# 只有在Nginx反向代理模式下才配置Nginx
|
||
if [[ "$DERP_MODE" != "2" ]]; then
|
||
log_info "跳过Nginx配置(不需要反向代理)"
|
||
return
|
||
fi
|
||
|
||
log_info "配置Nginx反向代理..."
|
||
|
||
# 创建Nginx配置
|
||
cat > /etc/nginx/sites-available/derper << EOF
|
||
server {
|
||
listen 80;
|
||
server_name $SERVER_IP;
|
||
|
||
location /derp {
|
||
proxy_pass http://127.0.0.1:8080;
|
||
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;
|
||
|
||
# WebSocket支持
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade \$http_upgrade;
|
||
proxy_set_header Connection "upgrade";
|
||
}
|
||
}
|
||
|
||
server {
|
||
listen 443 ssl;
|
||
server_name $SERVER_IP;
|
||
|
||
ssl_certificate /etc/derper/certs/server.crt;
|
||
ssl_certificate_key /etc/derper/certs/server.key;
|
||
|
||
location /derp {
|
||
proxy_pass http://127.0.0.1:8080;
|
||
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;
|
||
|
||
# WebSocket支持
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade \$http_upgrade;
|
||
proxy_set_header Connection "upgrade";
|
||
}
|
||
}
|
||
EOF
|
||
|
||
# 启用站点
|
||
ln -sf /etc/nginx/sites-available/derper /etc/nginx/sites-enabled/
|
||
|
||
# 测试配置并重启Nginx
|
||
nginx -t && systemctl restart nginx
|
||
|
||
log_info "Nginx配置完成"
|
||
}
|
||
|
||
# 生成官方Tailscale配置信息
|
||
generate_tailscale_config() {
|
||
log_info "生成官方Tailscale配置信息..."
|
||
|
||
# 读取配置
|
||
source /etc/derper/config
|
||
|
||
# 创建配置信息文件
|
||
mkdir -p /etc/derper
|
||
|
||
# 生成官方Tailscale ACL配置示例
|
||
# 读取运行模式
|
||
DERP_PORT=443
|
||
if [[ "$DERP_MODE" == "2" ]]; then
|
||
DERP_PORT=443 # Nginx反向代理会处理HTTPS
|
||
fi
|
||
cat > /etc/derper/tailscale_acl.json << EOF
|
||
{
|
||
"derpMap": {
|
||
"Regions": {
|
||
"900": {
|
||
"RegionID": 900,
|
||
"RegionCode": "custom",
|
||
"RegionName": "Custom DERP Server",
|
||
"Nodes": [
|
||
{
|
||
"Name": "derp-$SERVER_IP",
|
||
"RegionID": 900,
|
||
"HostName": "$SERVER_IP",
|
||
"IPv4": "$SERVER_IP",
|
||
"CertName": "sha256:$CERT_HASH",
|
||
"DERPPort": $DERP_PORT,
|
||
"STUNPort": 3478
|
||
}
|
||
]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
EOF
|
||
|
||
log_info "官方Tailscale配置信息已生成: /etc/derper/tailscale_acl.json"
|
||
}
|
||
|
||
# 启动服务
|
||
start_services() {
|
||
log_info "启动服务..."
|
||
|
||
# 启动DERP服务
|
||
systemctl start derper
|
||
|
||
# 检查服务状态
|
||
if systemctl is-active --quiet derper; then
|
||
log_info "DERP服务启动成功"
|
||
else
|
||
log_error "DERP服务启动失败"
|
||
systemctl status derper
|
||
exit 1
|
||
fi
|
||
|
||
# 只有在Nginx反向代理模式下才启动Nginx
|
||
if [[ "$DERP_MODE" == "2" ]]; then
|
||
systemctl enable nginx
|
||
systemctl start nginx
|
||
log_info "Nginx服务启动完成"
|
||
fi
|
||
|
||
log_info "所有服务启动完成"
|
||
}
|
||
|
||
# 显示配置信息
|
||
show_config_info() {
|
||
log_info "安装完成!"
|
||
|
||
# 读取配置
|
||
source /etc/derper/config
|
||
|
||
echo
|
||
echo "================================="
|
||
echo "DERP服务器配置信息"
|
||
echo "================================="
|
||
echo "服务器IP: $SERVER_IP"
|
||
echo "证书SHA256: $CERT_HASH"
|
||
echo "运行模式: $DERP_MODE"
|
||
|
||
case $DERP_MODE in
|
||
1)
|
||
echo "访问方式: 直接HTTPS访问"
|
||
echo "DERP端口: 443 (HTTPS)"
|
||
echo "HTTP端口: 80 (自动跳转到HTTPS)"
|
||
echo "STUN端口: 3478"
|
||
;;
|
||
2)
|
||
echo "访问方式: Nginx反向代理"
|
||
echo "DERP端口: 443 (HTTPS, 通过Nginx)"
|
||
echo "内部端口: 8080 (HTTP)"
|
||
echo "STUN端口: 3478"
|
||
;;
|
||
3)
|
||
echo "访问方式: 自定义配置"
|
||
echo "命令参数: $DERP_CMD"
|
||
;;
|
||
esac
|
||
|
||
echo "配置文件: /etc/derper/tailscale_acl.json"
|
||
echo
|
||
echo "服务管理命令:"
|
||
echo " 启动: systemctl start derper"
|
||
echo " 停止: systemctl stop derper"
|
||
echo " 重启: systemctl restart derper"
|
||
echo " 状态: systemctl status derper"
|
||
echo
|
||
echo "测试连接:"
|
||
echo " curl https://$SERVER_IP/derp"
|
||
echo
|
||
echo "官方Tailscale配置:"
|
||
echo " 配置文件: /etc/derper/tailscale_acl.json"
|
||
echo " 在Tailscale Admin Console中添加自定DERP服务器"
|
||
echo " 访问: https://login.tailscale.com/admin/dns"
|
||
echo
|
||
echo "重要提示:"
|
||
echo " 1. 请确保防火墙开放443端口"
|
||
echo " 2. 运行 'tailscale up' 连接到Tailnet"
|
||
echo " 3. 在Tailscale Admin Console中添加DERP服务器"
|
||
echo " 4. 使用自签名证书需要在ACL中指定证书哈希"
|
||
echo "================================="
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
log_info "开始安装Tailscale DERP服务器..."
|
||
|
||
check_root
|
||
check_system
|
||
install_dependencies
|
||
enable_bbr
|
||
install_go
|
||
compile_derp
|
||
configure_user_cert
|
||
install_tailscale
|
||
create_systemd_service
|
||
configure_nginx
|
||
generate_tailscale_config
|
||
start_services
|
||
show_config_info
|
||
|
||
log_info "安装完成!"
|
||
}
|
||
|
||
# 运行主函数
|
||
main "$@"
|