refactor: 简化Docker部署,使用环境变量替代.env文件映射

- 移除 docker-compose.yml 中的 .env 文件映射
- 添加所有必要的环境变量到 docker-compose.yml
- 简化 docker-entrypoint.sh,直接使用环境变量
- 更新 README,说明通过环境变量配置的方式
- 删除不再需要的初始化脚本
- 解决了 sed -i 在某些 Docker 环境下的 'Resource busy' 错误
This commit is contained in:
shaw
2025-07-24 15:50:33 +08:00
parent 232c276c8c
commit 2e511fa6f8
5 changed files with 112 additions and 210 deletions

View File

@@ -224,18 +224,6 @@ npm run service:status
## 🐳 Docker 部署(推荐) ## 🐳 Docker 部署(推荐)
### ⚠️ 首次部署必须执行
```bash
# 创建空的 .env 文件(非常重要!)
touch .env
```
> 🔴 **为什么必须先创建 .env 文件?**
> - Docker 在映射不存在的文件时会创建成**目录**而非文件
> - .env 文件用于存储加密密钥,必须持久化保存
> - 如果变成目录,容器将无法启动
### 使用 Docker Hub 镜像(最简单) ### 使用 Docker Hub 镜像(最简单)
> 🚀 推荐使用官方镜像,自动构建,始终保持最新版本 > 🚀 推荐使用官方镜像,自动构建,始终保持最新版本
@@ -244,18 +232,31 @@ touch .env
# 拉取镜像(支持 amd64 和 arm64 # 拉取镜像(支持 amd64 和 arm64
docker pull weishaw/claude-relay-service:latest docker pull weishaw/claude-relay-service:latest
# 使用 docker run 运行 # 使用 docker run 运行(注意设置必需的环境变量)
docker run -d \ docker run -d \
--name claude-relay \ --name claude-relay \
-p 3000:3000 \ -p 3000:3000 \
-v $(pwd)/data:/app/data \ -v $(pwd)/data:/app/data \
-v $(pwd)/logs:/app/logs \ -v $(pwd)/logs:/app/logs \
-v $(pwd)/.env:/app/.env \ -e JWT_SECRET=your-random-secret-key-at-least-32-chars \
-e ENCRYPTION_KEY=your-32-character-encryption-key \
-e REDIS_HOST=redis \
-e ADMIN_USERNAME=my_admin \ -e ADMIN_USERNAME=my_admin \
-e ADMIN_PASSWORD=my_secure_password \ -e ADMIN_PASSWORD=my_secure_password \
weishaw/claude-relay-service:latest weishaw/claude-relay-service:latest
# 或使用 docker-compose推荐 # 或使用 docker-compose推荐
# 创建 .env 文件用于 docker-compose 的环境变量:
cat > .env << 'EOF'
# 必填:安全密钥(请修改为随机值)
JWT_SECRET=your-random-secret-key-at-least-32-chars
ENCRYPTION_KEY=your-32-character-encryption-key
# 可选:管理员凭据
ADMIN_USERNAME=cr_admin
ADMIN_PASSWORD=your-secure-password
EOF
# 创建 docker-compose.yml 文件: # 创建 docker-compose.yml 文件:
cat > docker-compose.yml << 'EOF' cat > docker-compose.yml << 'EOF'
version: '3.8' version: '3.8'
@@ -267,13 +268,14 @@ services:
ports: ports:
- "3000:3000" - "3000:3000"
environment: environment:
- JWT_SECRET=${JWT_SECRET}
- ENCRYPTION_KEY=${ENCRYPTION_KEY}
- REDIS_HOST=redis - REDIS_HOST=redis
- ADMIN_USERNAME=${ADMIN_USERNAME:-} - ADMIN_USERNAME=${ADMIN_USERNAME:-}
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-} - ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
volumes: volumes:
- ./logs:/app/logs - ./logs:/app/logs
- ./data:/app/data - ./data:/app/data
- ./.env:/app/.env # 重要:持久化加密密钥
depends_on: depends_on:
- redis - redis
@@ -299,19 +301,18 @@ docker-compose up -d
git clone https://github.com/Wei-Shaw//claude-relay-service.git git clone https://github.com/Wei-Shaw//claude-relay-service.git
cd claude-relay-service cd claude-relay-service
# 2. 初始化环境(重要!首次部署必须执行) # 2. 创建环境变量文件
touch .env # 创建空文件,防止 Docker 创建成目录 cat > .env << 'EOF'
# 必填:安全密钥(请修改为随机值)
JWT_SECRET=your-random-secret-key-at-least-32-chars
ENCRYPTION_KEY=your-32-character-encryption-key
# 如果 .env 已经错误地变成了目录,先删除: # 可选:管理员凭据
# rm -rf .env && touch .env ADMIN_USERNAME=cr_admin_custom
ADMIN_PASSWORD=your-secure-password
EOF
# 3. 设置管理员账号密码(可选) # 3. 启动服务
# 方式一:自动生成(查看容器日志获取)
docker-compose up -d
# 方式二:预设账号密码
export ADMIN_USERNAME=cr_admin_custom
export ADMIN_PASSWORD=your-secure-password
docker-compose up -d docker-compose up -d
# 4. 查看管理员凭据 # 4. 查看管理员凭据
@@ -326,12 +327,24 @@ cat ./data/init.json
docker-compose.yml 已包含: docker-compose.yml 已包含:
- ✅ 自动初始化管理员账号 - ✅ 自动初始化管理员账号
- ✅ 数据持久化logsdata目录和.env文件自动挂载) - ✅ 数据持久化logsdata目录自动挂载
- ✅ Redis数据库 - ✅ Redis数据库
- ✅ 健康检查 - ✅ 健康检查
- ✅ 自动重启 - ✅ 自动重启
- ✅ 所有配置通过环境变量管理
> ⚠️ **重要提示**:从 v1.1.15 版本开始,`.env` 文件必须映射到本地以持久化加密密钥。如果不映射,每次重建容器都会生成新的加密密钥,导致之前加密的数据无法解密! ### 环境变量说明
#### 必填项
- `JWT_SECRET`: JWT密钥至少32个字符
- `ENCRYPTION_KEY`: 加密密钥必须是32个字符
#### 可选项
- `ADMIN_USERNAME`: 管理员用户名(不设置则自动生成)
- `ADMIN_PASSWORD`: 管理员密码(不设置则自动生成)
- `LOG_LEVEL`: 日志级别默认info
- `DEFAULT_TOKEN_LIMIT`: 默认Token限制默认1000000
- 更多配置项请参考 `.env.example` 文件
### 管理员凭据获取方式 ### 管理员凭据获取方式

View File

@@ -1,62 +0,0 @@
#!/bin/bash
# Docker Compose 初始化脚本 - 用于 Docker Hub 镜像部署
echo "🚀 Claude Relay Service Docker 初始化脚本"
echo "============================================"
# 检查是否在正确的目录
if [ -f "docker-compose.yml" ]; then
echo "✅ 检测到 docker-compose.yml继续初始化..."
else
echo "⚠️ 未检测到 docker-compose.yml 文件"
echo " 请确保在包含 docker-compose.yml 的目录下运行此脚本"
echo ""
echo "如果您是从 Docker Hub 部署,请先创建 docker-compose.yml"
echo " 参考文档https://github.com/Wei-Shaw/claude-relay-service#docker-部署推荐"
exit 1
fi
# 确保 .env 文件正确创建
echo ""
echo "📋 检查 .env 文件..."
if [ -d ".env" ]; then
echo "❌ 检测到 .env 是目录Docker 创建错误)"
echo " 正在修复..."
rm -rf .env
touch .env
echo "✅ 已删除目录并创建正确的 .env 文件"
elif [ ! -f ".env" ]; then
echo "📝 创建 .env 文件..."
touch .env
echo "✅ .env 文件已创建"
else
echo "✅ .env 文件已存在"
fi
# 创建必要的目录
echo ""
echo "📁 创建必要的目录..."
mkdir -p data logs redis_data
echo "✅ 目录创建完成"
# 显示文件状态
echo ""
echo "📊 当前文件状态:"
echo " .env: $([ -f .env ] && echo "✅ 文件" || echo "❌ 不存在")"
echo " data/: $([ -d data ] && echo "✅ 目录" || echo "❌ 不存在")"
echo " logs/: $([ -d logs ] && echo "✅ 目录" || echo "❌ 不存在")"
echo " redis_data/: $([ -d redis_data ] && echo "✅ 目录" || echo "❌ 不存在")"
echo ""
echo "🎉 初始化完成!"
echo ""
echo "下一步操作:"
echo "1. 启动服务:"
echo " docker-compose up -d"
echo ""
echo "2. 查看日志获取管理员密码:"
echo " docker-compose logs claude-relay | grep '管理员'"
echo ""
echo "3. 访问管理界面:"
echo " http://your-server:3000/web"

View File

@@ -1,10 +1,7 @@
version: '3.8' version: '3.8'
# ⚠️ 重要提示:首次运行前必须执行以下命令 # Claude Relay Service Docker Compose 配置
# touch .env # 所有配置通过环境变量设置,无需映射 .env 文件
#
# 说明:如果不先创建 .env 文件Docker 会将其创建为目录而非文件,
# 导致容器无法正常启动。该文件用于存储加密密钥,必须持久化。
services: services:
# 🚀 Claude Relay Service # 🚀 Claude Relay Service
@@ -15,16 +12,64 @@ services:
ports: ports:
- "${PORT:-3000}:3000" - "${PORT:-3000}:3000"
environment: environment:
# 🌐 服务器配置
- NODE_ENV=production - NODE_ENV=production
- PORT=3000 - PORT=3000
- HOST=0.0.0.0
# 🔐 安全配置(必填)
- JWT_SECRET=${JWT_SECRET} # 必填至少32字符的随机字符串
- ENCRYPTION_KEY=${ENCRYPTION_KEY} # 必填32字符的加密密钥
- ADMIN_SESSION_TIMEOUT=${ADMIN_SESSION_TIMEOUT:-86400000}
- API_KEY_PREFIX=${API_KEY_PREFIX:-cr_}
# 👤 管理员凭据(可选)
- ADMIN_USERNAME=${ADMIN_USERNAME:-}
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
# 📊 Redis 配置
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- ADMIN_USERNAME=${ADMIN_USERNAME:-} # 可选:预设管理员用户名 - REDIS_PASSWORD=${REDIS_PASSWORD:-}
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-} # 可选:预设管理员密码 - REDIS_DB=${REDIS_DB:-0}
- REDIS_ENABLE_TLS=${REDIS_ENABLE_TLS:-}
# 🎯 Claude API 配置
- CLAUDE_API_URL=${CLAUDE_API_URL:-https://api.anthropic.com/v1/messages}
- CLAUDE_API_VERSION=${CLAUDE_API_VERSION:-2023-06-01}
- CLAUDE_BETA_HEADER=${CLAUDE_BETA_HEADER:-claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14}
# 🌐 代理配置
- DEFAULT_PROXY_TIMEOUT=${DEFAULT_PROXY_TIMEOUT:-60000}
- MAX_PROXY_RETRIES=${MAX_PROXY_RETRIES:-3}
# 📈 使用限制
- DEFAULT_TOKEN_LIMIT=${DEFAULT_TOKEN_LIMIT:-1000000}
# 📝 日志配置
- LOG_LEVEL=${LOG_LEVEL:-info}
- LOG_MAX_SIZE=${LOG_MAX_SIZE:-10m}
- LOG_MAX_FILES=${LOG_MAX_FILES:-5}
# 🔧 系统配置
- CLEANUP_INTERVAL=${CLEANUP_INTERVAL:-3600000}
- TOKEN_USAGE_RETENTION=${TOKEN_USAGE_RETENTION:-2592000000}
- HEALTH_CHECK_INTERVAL=${HEALTH_CHECK_INTERVAL:-60000}
- SYSTEM_TIMEZONE=${SYSTEM_TIMEZONE:-Asia/Shanghai}
- TIMEZONE_OFFSET=${TIMEZONE_OFFSET:-8}
# 🎨 Web 界面配置
- WEB_TITLE=${WEB_TITLE:-Claude Relay Service}
- WEB_DESCRIPTION=${WEB_DESCRIPTION:-Multi-account Claude API relay service}
- WEB_LOGO_URL=${WEB_LOGO_URL:-/assets/logo.png}
# 🛠️ 开发配置
- DEBUG=${DEBUG:-false}
- ENABLE_CORS=${ENABLE_CORS:-true}
- TRUST_PROXY=${TRUST_PROXY:-true}
volumes: volumes:
- ./logs:/app/logs - ./logs:/app/logs
- ./data:/app/data - ./data:/app/data
- ./.env:/app/.env # 必须映射,用于持久化加密密钥
depends_on: depends_on:
- redis - redis
networks: networks:

View File

@@ -3,25 +3,20 @@ set -e
echo "🚀 Claude Relay Service 启动中..." echo "🚀 Claude Relay Service 启动中..."
# 检查 .env 文件 # 检查关键环境变量
if [ ! -f "/app/.env" ]; then if [ -z "$JWT_SECRET" ]; then
echo "📋 检测到 .env 不存在,从模板创建..." echo "❌ 错误: JWT_SECRET 环境变量未设置"
if [ -f "/app/.env.example" ]; then echo " 请在 docker-compose.yml 中设置 JWT_SECRET"
cp /app/.env.example /app/.env echo " 例如: JWT_SECRET=your-random-secret-key-at-least-32-chars"
echo "✅ .env 已从模板创建"
echo "⚠️ 注意:.env 文件将在容器内生成,请确保已映射到宿主机以持久化"
else
echo "❌ 错误: .env.example 不存在"
exit 1 exit 1
fi
fi fi
# 生成随机字符串的函数 if [ -z "$ENCRYPTION_KEY" ]; then
generate_random_string() { echo "❌ 错误: ENCRYPTION_KEY 环境变量未设置"
length=$1 echo " 请在 docker-compose.yml 中设置 ENCRYPTION_KEY"
# 使用 /dev/urandom 生成随机字符串 echo " 例如: ENCRYPTION_KEY=your-32-character-encryption-key"
tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c $length exit 1
} fi
# 检查并复制配置文件 # 检查并复制配置文件
if [ ! -f "/app/config/config.js" ]; then if [ ! -f "/app/config/config.js" ]; then
@@ -35,54 +30,17 @@ if [ ! -f "/app/config/config.js" ]; then
fi fi
fi fi
# 检查并配置 .env 文件(文件已在构建时创建) # 显示配置信息
if [ -f "/app/.env" ]; then echo "✅ 环境配置已就绪"
echo "📋 配置 .env 文件..." echo " JWT_SECRET: [已设置]"
echo " ENCRYPTION_KEY: [已设置]"
# 生成随机的 JWT_SECRET (64字符) echo " REDIS_HOST: ${REDIS_HOST:-localhost}"
if [ -z "$JWT_SECRET" ]; then echo " PORT: ${PORT:-3000}"
JWT_SECRET=$(grep "^JWT_SECRET=" /app/.env | cut -d'=' -f2)
if [ -z "$JWT_SECRET" ] || [ "$JWT_SECRET" = "your-jwt-secret-here" ]; then
JWT_SECRET=$(generate_random_string 64)
echo "🔑 生成新的 JWT_SECRET"
# 更新 .env 文件
sed -i "s/JWT_SECRET=.*/JWT_SECRET=${JWT_SECRET}/" /app/.env
else
echo "✅ 使用现有的 JWT_SECRET"
fi
fi
# 生成随机的 ENCRYPTION_KEY (32字符)
if [ -z "$ENCRYPTION_KEY" ]; then
ENCRYPTION_KEY=$(grep "^ENCRYPTION_KEY=" /app/.env | cut -d'=' -f2)
if [ -z "$ENCRYPTION_KEY" ] || [ "$ENCRYPTION_KEY" = "your-encryption-key-here" ]; then
ENCRYPTION_KEY=$(generate_random_string 32)
echo "🔑 生成新的 ENCRYPTION_KEY"
# 更新 .env 文件
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=${ENCRYPTION_KEY}/" /app/.env
else
echo "✅ 使用现有的 ENCRYPTION_KEY"
fi
fi
# 更新 Redis 主机配置
sed -i "s/REDIS_HOST=.*/REDIS_HOST=redis/" /app/.env
echo "✅ .env 已配置"
else
echo "❌ 错误: .env 文件处理失败"
exit 1
fi
# 导出环境变量
export JWT_SECRET
export ENCRYPTION_KEY
# 检查是否需要初始化 # 检查是否需要初始化
if [ ! -f "/app/data/init.json" ]; then if [ ! -f "/app/data/init.json" ]; then
echo "📋 首次启动,执行初始化设置..." echo "📋 首次启动,执行初始化设置..."
# 如果设置了环境变量,显示提示 # 如果设置了环境变量,显示提示
if [ -n "$ADMIN_USERNAME" ] || [ -n "$ADMIN_PASSWORD" ]; then if [ -n "$ADMIN_USERNAME" ] || [ -n "$ADMIN_PASSWORD" ]; then
echo "📌 检测到预设的管理员凭据" echo "📌 检测到预设的管理员凭据"

View File

@@ -1,52 +0,0 @@
#!/bin/bash
# Docker 初始化脚本 - 在宿主机上运行
echo "🚀 Claude Relay Service Docker 初始化"
# 检查 .env 文件
if [ ! -f ".env" ]; then
echo "📋 检测到 .env 文件不存在,从模板创建..."
if [ -f ".env.example" ]; then
cp .env.example .env
echo "✅ .env 文件已创建"
# 生成随机密钥
echo "🔑 生成安全密钥..."
# 生成64字符的JWT_SECRET
JWT_SECRET=$(openssl rand -base64 48 | tr -d "=+/" | cut -c1-64)
# 生成32字符的ENCRYPTION_KEY
ENCRYPTION_KEY=$(openssl rand -base64 24 | tr -d "=+/" | cut -c1-32)
# 替换默认值
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
sed -i '' "s/JWT_SECRET=.*/JWT_SECRET=$JWT_SECRET/" .env
sed -i '' "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=$ENCRYPTION_KEY/" .env
else
# Linux
sed -i "s/JWT_SECRET=.*/JWT_SECRET=$JWT_SECRET/" .env
sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=$ENCRYPTION_KEY/" .env
fi
echo "✅ 密钥已生成并保存到 .env 文件"
echo ""
echo "📌 请妥善保管 .env 文件,它包含重要的加密密钥!"
else
echo "❌ 错误:.env.example 文件不存在"
echo "请确保在项目根目录下运行此脚本"
exit 1
fi
else
echo "✅ .env 文件已存在,跳过创建"
fi
# 创建必要的目录
echo "📁 创建必要的目录..."
mkdir -p data logs redis_data
echo "✅ 目录创建完成"
echo ""
echo "🎉 初始化完成!现在可以运行:"
echo " docker-compose up -d"