clash-linux commited on
Commit
de637f1
·
verified ·
1 Parent(s): aa5326c

Upload 17 files

Browse files
Files changed (4) hide show
  1. Dockerfile +12 -7
  2. app/sub_manager.py +48 -41
  3. entrypoint.sh +68 -67
  4. requirements.txt +4 -3
Dockerfile CHANGED
@@ -84,6 +84,8 @@ RUN pip install --upgrade pip
84
  # 安装剩余的Python依赖 (PyYAML 已通过 apk 安装)
85
  RUN echo "Installing Python dependencies..." && \
86
  pip install --no-cache-dir -r requirements.txt
 
 
87
  RUN pip install --no-cache-dir pyyaml
88
 
89
  # 可选:删除构建依赖以减小镜像体积
@@ -93,7 +95,11 @@ RUN pip install --no-cache-dir pyyaml
93
  ENV PYTHONDONTWRITEBYTECODE=1 \
94
  PYTHONUNBUFFERED=1 \
95
  FLASK_APP=app.main \
96
- FLASK_ENV=production
 
 
 
 
97
 
98
  # 复制应用代码
99
  COPY app/ ./app/
@@ -102,13 +108,12 @@ COPY app/ ./app/
102
  COPY entrypoint.sh ./
103
  RUN chmod +x ./entrypoint.sh
104
 
 
 
 
 
105
  # 暴露端口
106
- # 7860: Web界面和API服务 (Hugging Face Spaces默认端口)
107
- # 7890: Clash代理服务 (仅在本地/自托管部署时直接暴露)
108
- # 9090: Clash内部API端口 (仅供内部服务通信使用)
109
- EXPOSE 7860
110
- EXPOSE 7890
111
- # 注意:9090端口仅供内部使用,不对外暴露
112
 
113
  # 使用entrypoint脚本启动应用
114
  ENTRYPOINT ["/app/entrypoint.sh"]
 
84
  # 安装剩余的Python依赖 (PyYAML 已通过 apk 安装)
85
  RUN echo "Installing Python dependencies..." && \
86
  pip install --no-cache-dir -r requirements.txt
87
+
88
+ # 确保安装PyYAML
89
  RUN pip install --no-cache-dir pyyaml
90
 
91
  # 可选:删除构建依赖以减小镜像体积
 
95
  ENV PYTHONDONTWRITEBYTECODE=1 \
96
  PYTHONUNBUFFERED=1 \
97
  FLASK_APP=app.main \
98
+ FLASK_ENV=production \
99
+ FLASK_PORT=7860 \
100
+ CLASH_PROXY_PORT=7890 \
101
+ CLASH_API_PORT=9090 \
102
+ PORT=7860
103
 
104
  # 复制应用代码
105
  COPY app/ ./app/
 
108
  COPY entrypoint.sh ./
109
  RUN chmod +x ./entrypoint.sh
110
 
111
+ # 给脚本和二进制文件执行权限
112
+ RUN chmod +x ./clash_core/clash.meta-linux-amd64 ./clash_core/clash.meta-linux-amd64-v1.14.5 || true
113
+ RUN chmod +x ./subconverter/subconverter || true
114
+
115
  # 暴露端口
116
+ EXPOSE $FLASK_PORT $CLASH_PROXY_PORT $CLASH_API_PORT
 
 
 
 
 
117
 
118
  # 使用entrypoint脚本启动应用
119
  ENTRYPOINT ["/app/entrypoint.sh"]
app/sub_manager.py CHANGED
@@ -304,10 +304,9 @@ secret: ""
304
  has_patch = True
305
 
306
  # 尝试解析YAML并修复代理组引用问题
307
- yaml_available = False
308
  try:
309
  import yaml
310
- yaml_available = True
311
 
312
  # 解析配置
313
  config_yaml = yaml.safe_load(config_content)
@@ -396,54 +395,62 @@ secret: ""
396
 
397
  # 更新配置内容
398
  config_content = yaml.dump(config_yaml, sort_keys=False, allow_unicode=True)
399
- except ImportError as yaml_err:
400
- logger.error(f"解析YAML时出错: {str(yaml_err)}")
401
- except Exception as yaml_err:
402
- logger.error(f"解析YAML时出错: {str(yaml_err)}")
403
-
404
- # 如果yaml模块不可用,使用简单的文本处理方式
405
- if not yaml_available:
406
- # 检查配置中是否已经有GLOBAL组
407
- global_exists = "name: GLOBAL" in config_content or "GLOBAL" in config_content
408
- proxy_groups_exists = "proxy-groups:" in config_content
409
-
410
- # 只有在没有GLOBAL组且需要添加时才添加
411
- if not global_exists:
412
- if proxy_groups_exists:
413
- # 如果已经有proxy-groups部分,不要重复添加proxy-groups键
414
- # 尝试在proxy-groups部分添加GLOBAL组
415
- try:
416
- # 寻找proxy-groups部分
417
- groups_index = config_content.find("proxy-groups:")
418
- if groups_index != -1:
419
- # 找到插入点 - 在proxy-groups行之后
420
- lines = config_content.split("\n")
421
- for i, line in enumerate(lines):
422
- if line.strip().startswith("proxy-groups:"):
423
- # 在proxy-groups后面直接添加GLOBAL组
424
- global_group = """ - name: GLOBAL
425
  type: select
426
  proxies:
427
- - DIRECT"""
428
- lines.insert(i + 1, global_group)
429
- config_content = "\n".join(lines)
430
- has_patch = True
431
- logger.info("在现有proxy-groups中添加了GLOBAL策略组")
432
- break
433
- except Exception as e:
434
- logger.error(f"尝试添加GLOBAL组时出错: {str(e)}")
435
  else:
436
- # 如果没有proxy-groups部分,添加完整的部分
437
- global_section = """
 
 
 
 
 
 
 
 
 
438
  proxy-groups:
439
  - name: GLOBAL
440
  type: select
441
  proxies:
442
  - DIRECT
443
  """
444
- config_content += global_section
445
- has_patch = True
446
- logger.info("添加了基本的GLOBAL策略组")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
 
448
  # 如果我们修改了配置,保存回文件
449
  if has_patch:
 
304
  has_patch = True
305
 
306
  # 尝试解析YAML并修复代理组引用问题
 
307
  try:
308
  import yaml
309
+ logger.info("正在使用PyYAML解析和修复配置")
310
 
311
  # 解析配置
312
  config_yaml = yaml.safe_load(config_content)
 
395
 
396
  # 更新配置内容
397
  config_content = yaml.dump(config_yaml, sort_keys=False, allow_unicode=True)
398
+ else:
399
+ # 配置为空或无效,添加基本配置
400
+ logger.warning("配置为空或无效,添加基本配置结构")
401
+ # 使用简单的文本分析,避免添加重复的配置
402
+ has_proxy_groups = "proxy-groups:" in config_content
403
+ has_global_group = "GLOBAL" in config_content or "- name: GLOBAL" in config_content
404
+
405
+ if not has_proxy_groups and not has_global_group:
406
+ logger.info("未检测到proxy-groups或GLOBAL策略组,添加基本的GLOBAL策略组")
407
+ config_content += """
408
+ proxy-groups:
409
+ - name: GLOBAL
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  type: select
411
  proxies:
412
+ - DIRECT
413
+ """
414
+ has_patch = True
 
 
 
 
 
415
  else:
416
+ logger.info("检测到已有proxy-groups或GLOBAL配置,跳过添加")
417
+
418
+ except ImportError as e:
419
+ logger.error(f"导入PyYAML模块失败: {str(e)}")
420
+ # 使用简单的文本分析,避免添加重复的配置
421
+ has_proxy_groups = "proxy-groups:" in config_content
422
+ has_global_group = "GLOBAL" in config_content or "- name: GLOBAL" in config_content
423
+
424
+ if not has_proxy_groups and not has_global_group:
425
+ logger.info("未检测到proxy-groups或GLOBAL策略组,添加基本的GLOBAL策略组")
426
+ config_content += """
427
  proxy-groups:
428
  - name: GLOBAL
429
  type: select
430
  proxies:
431
  - DIRECT
432
  """
433
+ has_patch = True
434
+ else:
435
+ logger.info("检测到已有proxy-groups或GLOBAL配置,跳过添加")
436
+ except Exception as yaml_err:
437
+ logger.error(f"处理YAML配置时出错: {str(yaml_err)}")
438
+ # 使用简单的文本分析,避免添加重复的配置
439
+ has_proxy_groups = "proxy-groups:" in config_content
440
+ has_global_group = "GLOBAL" in config_content or "- name: GLOBAL" in config_content
441
+
442
+ if not has_proxy_groups and not has_global_group:
443
+ logger.info("未检测到proxy-groups或GLOBAL策略组,添加基本的GLOBAL策略组")
444
+ config_content += """
445
+ proxy-groups:
446
+ - name: GLOBAL
447
+ type: select
448
+ proxies:
449
+ - DIRECT
450
+ """
451
+ has_patch = True
452
+ else:
453
+ logger.info("检测到已有proxy-groups或GLOBAL配置,跳过添加")
454
 
455
  # 如果我们修改了配置,保存回文件
456
  if has_patch:
entrypoint.sh CHANGED
@@ -1,100 +1,101 @@
1
- #!/bin/bash
 
 
2
 
3
- # 彩色输出函数
4
- function log_info() {
5
- echo -e "\033[0;32m$1\033[0m"
6
- }
 
7
 
8
- function log_warning() {
9
- echo -e "\033[1;33m$1\033[0m"
10
- }
11
 
12
- function log_error() {
13
- echo -e "\033[0;31m$1\033[0m"
14
- }
15
-
16
- # 打印启动标题
17
- DATE=$(date "+%Y-%m-%d %H:%M:%S")
18
- echo "===== Application Startup at $DATE ====="
19
- echo ""
20
- log_info "Starting Simple Clash Relay..."
21
-
22
- # 打印系统信息
23
- log_warning "System information:"
24
  uname -a
25
- log_warning "Running as user:"
26
  id
27
 
28
- # 检查可执行文件
29
- log_warning "Checking executables:"
30
  file /app/clash_core/clash.meta-linux-amd64
31
  ls -la /app/clash_core/clash.meta-linux-amd64
32
 
33
- # 确保数据目录存在
34
- mkdir -p /app/data
35
- if [ $? -ne 0 ]; then
36
- log_warning "Warning: Failed to create /app/data, continuing anyway"
37
- else
38
- # 尝试设置权限
39
- chmod -R 777 /app/data 2>/dev/null || log_warning "Warning: Failed to set permissions for /app/data, continuing anyway"
40
- fi
41
-
42
- # 检查是否需要清理配置
43
- if [ "$CLEAN_CONFIG" = "true" ]; then
44
- log_info "Cleaning old configuration files..."
45
  rm -f /app/data/config.yaml /app/data/config.yaml.raw
46
- if [ $? -eq 0 ]; then
47
- log_info "Old configuration files cleaned successfully"
48
- else
49
- log_warning "Failed to clean old configuration files"
50
- fi
51
  fi
52
 
53
- # 尝试给二进制文件设置可执行权限
54
- chmod +x /app/subconverter/subconverter 2>/dev/null || log_warning "Warning: Failed to set executable permission for subconverter"
55
- chmod +x /app/clash_core/clash.meta-linux-amd64 2>/dev/null || log_warning "Warning: Failed to set executable permission for Clash Meta"
 
 
 
 
 
 
 
56
 
57
- # 检查Clash Core是否存在
58
- if [ -f /app/clash_core/clash.meta-linux-amd64 ]; then
59
- log_info "Clash Meta found"
 
60
  else
61
- log_error "Clash Meta binary not found!"
62
  exit 1
63
  fi
64
 
65
  # 加载环境变量
66
- if [ -f .env ]; then
67
- source .env
 
68
  fi
69
 
70
  # 检查必要的环境变量
71
- echo -e "\033[0;32mFlask will listen on port $FLASK_PORT\033[0m"
 
 
 
 
 
 
 
 
 
72
  echo "=========================="
73
  echo " Simple Clash Relay"
74
  echo "=========================="
75
  echo "Starting services..."
 
 
76
  echo "Environment:"
77
- echo "FLASK_PORT: $FLASK_PORT"
78
- echo "CLASH_PROXY_PORT: $CLASH_PROXY_PORT"
79
- echo "CLASH_API_PORT: $CLASH_API_PORT"
80
  echo "SUB_URL: [hidden]"
81
  echo "API_KEY: [hidden]"
82
 
83
- # 检查API密钥
84
- if [ -z "$API_KEY" ] || [ "$API_KEY" = "changeme" ]; then
85
  echo "WARNING: API_KEY is not set. Using default value (insecure)!"
86
- fi
87
-
88
- # 检查订阅链接
89
- if [ -z "$SUB_URL" ]; then
90
- echo "WARNING: SUB_URL is not set. Proxy functionality will not work properly."
91
  fi
92
 
93
  # 启动Flask应用
94
- log_info "Starting Flask application..."
95
- WORKERS=$(nproc)
96
- if [ $WORKERS -gt 16 ]; then
97
- WORKERS=16 # 限制最大工作进程数
98
- fi
99
- echo "Using $WORKERS workers"
100
- exec gunicorn app.main:app -b 0.0.0.0:$FLASK_PORT -w $WORKERS
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ # 不再使用set -e,避免因chmod失败而中止脚本
3
+ # set -e
4
 
5
+ # 设置颜色输出
6
+ RED='\033[0;31m'
7
+ GREEN='\033[0;32m'
8
+ YELLOW='\033[1;33m'
9
+ NC='\033[0m' # No Color
10
 
11
+ echo "${GREEN}Starting Simple Clash Relay...${NC}"
 
 
12
 
13
+ # 添加诊断信息
14
+ echo "${YELLOW}System information:${NC}"
 
 
 
 
 
 
 
 
 
 
15
  uname -a
16
+ echo "${YELLOW}Running as user:${NC}"
17
  id
18
 
19
+ echo "${YELLOW}Checking executables:${NC}"
 
20
  file /app/clash_core/clash.meta-linux-amd64
21
  ls -la /app/clash_core/clash.meta-linux-amd64
22
 
23
+ # 可选清理旧配置(如果指定CLEAN_CONFIG=true)
24
+ if [ "${CLEAN_CONFIG}" = "true" ]; then
25
+ echo "${YELLOW}Cleaning old config files...${NC}"
 
 
 
 
 
 
 
 
 
26
  rm -f /app/data/config.yaml /app/data/config.yaml.raw
27
+ echo "${GREEN}Old config files cleaned${NC}"
 
 
 
 
28
  fi
29
 
30
+ # 确保数据目录存在
31
+ mkdir -p /app/data || echo "${YELLOW}Warning: Failed to create /app/data directory${NC}"
32
+
33
+ # 尝试设置权限,但允许失败
34
+ chmod -R 777 /app/data 2>/dev/null || echo "${YELLOW}Warning: Failed to set permissions for /app/data, continuing anyway${NC}"
35
+
36
+ # 尝试设置subconverter执行权限,但允许失败
37
+ if [ -f "/app/subconverter/subconverter" ]; then
38
+ chmod +x /app/subconverter/subconverter 2>/dev/null || echo "${YELLOW}Warning: Failed to set executable permission for subconverter${NC}"
39
+ fi
40
 
41
+ # 尝试设置Clash Core执行权限,但允许失败
42
+ if [ -f "/app/clash_core/clash.meta-linux-amd64" ]; then
43
+ chmod +x /app/clash_core/clash.meta-linux-amd64 2>/dev/null || echo "${YELLOW}Warning: Failed to set executable permission for Clash Meta${NC}"
44
+ echo "${GREEN}Clash Meta found${NC}"
45
  else
46
+ echo "${RED}Error: Clash Core executable not found!${NC}"
47
  exit 1
48
  fi
49
 
50
  # 加载环境变量
51
+ if [ -f ".env" ]; then
52
+ echo "${GREEN}Loading environment variables from .env file...${NC}"
53
+ export $(grep -v '^#' .env | xargs -d '\n')
54
  fi
55
 
56
  # 检查必要的环境变量
57
+ if [ -z "$SUB_URL" ]; then
58
+ echo "${RED}Error: SUB_URL environment variable is not set!${NC}"
59
+ exit 1
60
+ fi
61
+
62
+ # 设置默认端口
63
+ export FLASK_PORT=${FLASK_PORT:-7860}
64
+ echo "${GREEN}Flask will listen on port ${FLASK_PORT}${NC}"
65
+
66
+ # 输出基本信息
67
  echo "=========================="
68
  echo " Simple Clash Relay"
69
  echo "=========================="
70
  echo "Starting services..."
71
+
72
+ # 打印环境变量(隐藏敏感信息)
73
  echo "Environment:"
74
+ echo "FLASK_PORT: ${FLASK_PORT:-7860}"
75
+ echo "CLASH_PROXY_PORT: ${CLASH_PROXY_PORT:-7890}"
76
+ echo "CLASH_API_PORT: ${CLASH_API_PORT:-9090}"
77
  echo "SUB_URL: [hidden]"
78
  echo "API_KEY: [hidden]"
79
 
80
+ # 检查必要的环境变量
81
+ if [ -z "$API_KEY" ]; then
82
  echo "WARNING: API_KEY is not set. Using default value (insecure)!"
83
+ export API_KEY="changeme"
 
 
 
 
84
  fi
85
 
86
  # 启动Flask应用
87
+ echo "${GREEN}Starting Flask application...${NC}"
88
+
89
+ # 使用gunicorn启动Flask应用(生产环境推荐)
90
+ # 如果WORKER_COUNT未设置,使用CPU核心数+1的worker数量
91
+ WORKER_COUNT=${WORKER_COUNT:-$(( $(nproc) + 1 ))}
92
+ echo "Using $WORKER_COUNT workers"
93
+
94
+ # 确保所有参数在一行或使用清晰的续行符
95
+ exec gunicorn \
96
+ --workers $WORKER_COUNT \
97
+ --bind 0.0.0.0:${FLASK_PORT:-7860} \
98
+ --log-level info \
99
+ --access-logfile - \
100
+ --error-logfile - \
101
+ app.main:app
requirements.txt CHANGED
@@ -1,6 +1,7 @@
1
- Flask==2.2.3
2
  gunicorn==20.1.0
3
- requests==2.28.2
4
  pyyaml==6.0
 
5
  # pyyaml==6.0 # 已通过 apk 安装
6
- Werkzeug==2.0.3 # 添加与 Flask==2.0.1 兼容的版本
 
1
+ flask==2.0.1
2
  gunicorn==20.1.0
3
+ requests==2.28.1
4
  pyyaml==6.0
5
+ Werkzeug==2.0.1
6
  # pyyaml==6.0 # 已通过 apk 安装
7
+ # 添加与 Flask==2.0.1 兼容的版本