259 lines
7.9 KiB
Bash
259 lines
7.9 KiB
Bash
#!/bin/bash
|
|
|
|
# cloudflared Docker 容器化一键部署脚本
|
|
# 功能:自动部署并配置 cloudflared 隧道服务
|
|
|
|
set -e # 遇到任何错误立即退出脚本
|
|
|
|
# 颜色定义用于输出美化
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # 无颜色
|
|
|
|
# 定义两个不同的密钥和服务器类型
|
|
CF_TOKEN_1="eyJhIjoiYmI2OTg1ZGU4N2ZiMDEyYjNjNjI2YWExM2VkYTY3OTciLCJ0IjoiNGYyMjNhM2UtNWNjYy00ZmMwLWI1N2MtNjQzZGY5ZmI1ZWZmIiwicyI6Ik1qTmxOR1U0WmpndE5ERXlPQzAwTjJKaExUazNaVFl0WVRWaU5tUmtObVkxTkdSaSJ9"
|
|
SERVER_1="国内服务器"
|
|
|
|
CF_TOKEN_2="eyJhIjoiYmI2OTg1ZGU4N2ZiMDEyYjNjNjI2YWExM2VkYTY3OTciLCJ0IjoiOWRhNTU2YmMtMWZhNC00Njg2LTg1YTQtZTczOTQ1YmEwMGNmIiwicyI6Ik5XWTNPV05tTkRjdFltVTBOQzAwTkRkaExXRm1ZVEF0T1daaE9XRTVaVFUyTWpRMSJ9"
|
|
SERVER_2="香港服务器"
|
|
|
|
# 输出带颜色的信息函数
|
|
log_info() {
|
|
echo -e "${GREEN}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
log_step() {
|
|
echo -e "${BLUE}[STEP]${NC} $1"
|
|
}
|
|
|
|
# 检查 Docker 是否可用
|
|
check_docker() {
|
|
log_step "检查 Docker 服务状态..."
|
|
if ! command -v docker &> /dev/null; then
|
|
log_error "Docker 未安装,请先安装 Docker"
|
|
exit 1
|
|
fi
|
|
|
|
if ! docker info &> /dev/null; then
|
|
log_error "Docker 服务未运行,请启动 Docker 服务"
|
|
exit 1
|
|
fi
|
|
log_info "Docker 服务状态正常"
|
|
}
|
|
|
|
# 准备数据目录和配置文件
|
|
prepare_directories() {
|
|
log_step "准备数据目录和配置文件..."
|
|
|
|
# 创建 /data 目录(如果不存在)
|
|
if [ ! -d "/data" ]; then
|
|
log_info "创建 /data 目录"
|
|
sudo mkdir -p /data
|
|
sudo chmod 755 /data
|
|
fi
|
|
|
|
# 切换到工作目录
|
|
cd /data
|
|
|
|
# 创建 cloudflared 相关目录
|
|
mkdir -p cloudflared/{config,logs,cert}
|
|
chmod -R 755 cloudflared
|
|
|
|
# 创建配置文件
|
|
cat > /data/cloudflared/config/config.yml << EOF
|
|
# Cloudflare Tunnel 配置文件
|
|
tunnel: $(echo $CF_TUNNEL_TOKEN | cut -d'.' -f2 | base64 -d 2>/dev/null | grep '"t"' | cut -d'"' -f4 || echo "tunnel-id")
|
|
credentials-file: /etc/cloudflared/credentials.json
|
|
logfile: /var/log/cloudflared/cloudflared.log
|
|
loglevel: info
|
|
|
|
# 服务配置(示例,请根据实际需求调整)
|
|
ingress:
|
|
- hostname: example.your-domain.com
|
|
service: http://localhost:80
|
|
originRequest:
|
|
connectTimeout: 30s
|
|
noTLSVerify: false
|
|
- service: http_status:404
|
|
EOF
|
|
|
|
# 创建凭证文件
|
|
cat > /data/cloudflared/config/credentials.json << EOF
|
|
{"AccountTag":"$(echo $CF_TUNNEL_TOKEN | cut -d'.' -f2 | base64 -d 2>/dev/null | grep '"a"' | cut -d'"' -f4 || echo "account-tag")","TunnelSecret":"$(echo $CF_TUNNEL_TOKEN | cut -d'.' -f2 | base64 -d 2>/dev/null | grep '"s"' | cut -d'"' -f4 || echo "tunnel-secret")","TunnelID":"$(echo $CF_TUNNEL_TOKEN | cut -d'.' -f2 | base64 -d 2>/dev/null | grep '"t"' | cut -d'"' -f4 || echo "tunnel-id")","TunnelName":"docker-tunnel"}
|
|
EOF
|
|
|
|
log_info "数据目录和配置文件准备完成"
|
|
}
|
|
|
|
# 验证 Cloudflare Token 格式
|
|
validate_token() {
|
|
log_step "验证 Cloudflare Tunnel Token..."
|
|
|
|
if [ -z "$CF_TUNNEL_TOKEN" ]; then
|
|
log_error "Cloudflare Tunnel Token 不能为空"
|
|
exit 1
|
|
fi
|
|
|
|
# 简单的 token 格式验证
|
|
if [[ ! "$CF_TUNNEL_TOKEN" =~ ^eyJ ]]; then
|
|
log_warning "Token 格式可能不正确,但将继续部署"
|
|
else
|
|
log_info "Token 格式验证通过"
|
|
fi
|
|
}
|
|
|
|
# 部署 cloudflared 容器
|
|
deploy_cloudflared() {
|
|
log_step "开始部署 cloudflared 容器..."
|
|
|
|
local container_name="cloudflared-tunnel"
|
|
|
|
# 检查容器是否已存在
|
|
if docker ps -a --format "{{.Names}}" | grep -q "^${container_name}$"; then
|
|
log_info "发现已存在的 ${container_name} 容器,正在清理..."
|
|
docker stop ${container_name} >/dev/null 2>&1 || true
|
|
docker rm ${container_name} >/dev/null 2>&1 || true
|
|
fi
|
|
|
|
# 运行 cloudflared 容器
|
|
log_info "启动 cloudflared 隧道服务..."
|
|
docker run -d \
|
|
--name ${container_name} \
|
|
--restart=unless-stopped \
|
|
--network host \
|
|
-v /data/cloudflared/config:/etc/cloudflared \
|
|
-v /data/cloudflared/logs:/var/log/cloudflared \
|
|
-v /data/cloudflared/cert:/home/nonroot/.cloudflared \
|
|
-e TUNNEL_TOKEN="${CF_TUNNEL_TOKEN}" \
|
|
cloudflare/cloudflared:latest \
|
|
tunnel --config /etc/cloudflared/config.yml run
|
|
|
|
log_info "cloudflared 容器部署完成"
|
|
}
|
|
|
|
# 验证容器状态
|
|
verify_deployment() {
|
|
log_step "验证容器运行状态..."
|
|
|
|
local container_name="cloudflared-tunnel"
|
|
local max_retries=10
|
|
local retry_interval=5
|
|
|
|
for i in $(seq 1 $max_retries); do
|
|
if docker ps --format "{{.Names}}" | grep -q "^${container_name}$"; then
|
|
local status=$(docker inspect -f '{{.State.Status}}' ${container_name} 2>/dev/null || echo "unknown")
|
|
|
|
if [ "$status" = "running" ]; then
|
|
log_info "✅ cloudflared 容器正在正常运行"
|
|
|
|
# 显示容器信息
|
|
echo ""
|
|
log_info "容器名称: ${container_name}"
|
|
log_info "运行状态: ${status}"
|
|
log_info "数据目录: /data/cloudflared/"
|
|
log_info "配置目录: /data/cloudflared/config"
|
|
log_info "日志目录: /data/cloudflared/logs"
|
|
log_info "证书目录: /data/cloudflared/cert"
|
|
echo ""
|
|
|
|
# 显示最近日志
|
|
log_info "容器启动日志:"
|
|
docker logs ${container_name} --tail 10
|
|
|
|
return 0
|
|
else
|
|
log_warning "容器状态: ${status},等待中... (尝试 $i/$max_retries)"
|
|
fi
|
|
else
|
|
log_warning "容器未运行,等待中... (尝试 $i/$max_retries)"
|
|
fi
|
|
sleep $retry_interval
|
|
done
|
|
|
|
log_error "❌ 容器启动失败或超时"
|
|
docker logs ${container_name} --tail 50
|
|
exit 1
|
|
}
|
|
|
|
# 显示使用说明
|
|
show_usage() {
|
|
echo ""
|
|
log_info "🔧 使用说明:"
|
|
log_info "查看日志: docker logs cloudflared-tunnel -f"
|
|
log_info "重启服务: docker restart cloudflared-tunnel"
|
|
log_info "停止服务: docker stop cloudflared-tunnel"
|
|
log_info "查看状态: docker ps -f name=cloudflared-tunnel"
|
|
echo ""
|
|
log_info "📁 配置文件路径: /data/cloudflared/config/config.yml"
|
|
log_info "请根据实际需求修改配置文件中的域名和服务设置"
|
|
echo ""
|
|
}
|
|
|
|
# 选择密钥和服务器
|
|
select_token() {
|
|
echo ""
|
|
log_step "请选择要使用的隧道配置:"
|
|
echo "1) 使用默认密钥 ($SERVER_1)"
|
|
echo "2) 使用备用密钥 ($SERVER_2)"
|
|
echo ""
|
|
|
|
while true; do
|
|
read -p "请输入选择 (1 或 2): " choice
|
|
case $choice in
|
|
1)
|
|
CF_TUNNEL_TOKEN=$CF_TOKEN_1
|
|
SERVER_TYPE=$SERVER_1
|
|
break
|
|
;;
|
|
2)
|
|
CF_TUNNEL_TOKEN=$CF_TOKEN_2
|
|
SERVER_TYPE=$SERVER_2
|
|
break
|
|
;;
|
|
*)
|
|
echo "无效选择,请重新输入"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
log_info "已选择: $SERVER_TYPE"
|
|
}
|
|
|
|
# 主执行函数
|
|
main() {
|
|
echo ""
|
|
log_info "🚀 开始部署 Cloudflare Tunnel Docker 容器..."
|
|
log_info "=========================================="
|
|
|
|
# 让用户选择密钥
|
|
select_token
|
|
|
|
validate_token
|
|
check_docker
|
|
prepare_directories
|
|
deploy_cloudflared
|
|
verify_deployment
|
|
|
|
log_info "=========================================="
|
|
log_info "✅ Cloudflare Tunnel 部署完成!"
|
|
log_info "隧道已使用 $SERVER_TYPE 的 Token 进行认证"
|
|
|
|
show_usage
|
|
}
|
|
|
|
# 异常处理
|
|
trap 'log_error "脚本执行被中断"; exit 1' INT TERM
|
|
|
|
# 执行主函数
|
|
main "$@"
|