Files
dock/自动部署并配置 cloudflared 隧道服务

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 "$@"