This commit is contained in:
wnlen
2026-01-15 00:14:27 +08:00
5 changed files with 94 additions and 10 deletions

6
.env
View File

@ -31,6 +31,12 @@ export CLASH_SUBSCRIPTION=''
# 留空时:脚本可自动生成随机值(若你的启动脚本支持)
export CLASH_SECRET=''
# 是否在启动输出中显示完整 Secret不推荐
CLASH_SHOW_SECRET=true
# 是否显示脱敏 Secret推荐
CLASH_SHOW_SECRET_MASKED=true
# External ControllerClash RESTful API
# ⚠️ 安全建议:
# - 默认仅监听本机127.0.0.1:9090 (推荐)

View File

@ -1,9 +1,20 @@
mixed-port: 7890
allow-lan: false
bind-address: '*'
mode: rule
log-level: info
ipv6: true
udp: true
external-controller: 127.0.0.1:9090
external-ui: /opt/clash-for-linux/dashboard/public
secret: ""
proxies: []
proxy-groups: []
rules:
- MATCH,DIRECT

View File

@ -1,9 +1,17 @@
mixed-port: 7890
allow-lan: false
bind-address: '*'
mode: rule
log-level: info
ipv6: true
udp: true
external-controller: 127.0.0.1:9090
external-ui: /opt/clash-for-linux/dashboard/public
secret: ""
proxies: []
proxy-groups: []
rules:
- MATCH,DIRECT

View File

@ -239,13 +239,29 @@ api_host="${EXTERNAL_CONTROLLER%:*}"
if [ -z "$api_host" ] || [ "$api_host" = "$EXTERNAL_CONTROLLER" ]; then
api_host="127.0.0.1"
fi
echo -e "🌐 Dashboardhttp://${api_host}:${api_port}/ui"
# secret 可能在 .env 里是 CLASH_SECRET
if [ -n "${CLASH_SECRET:-}" ]; then
echo -e "🔐 Secret${CLASH_SECRET}"
# ---- Secret 展示(脱敏)----
CONF_DIR="${CLASH_INSTALL_DIR:-/opt/clash-for-linux}/conf"
CONF_FILE="$CONF_DIR/config.yaml"
# 读取 secret如果 clash 还没生成 config就先不显示
SECRET_VAL=""
if [ -f "$CONF_FILE" ]; then
SECRET_VAL="$(awk -F': *' '/^secret:/{print $2; exit}' "$CONF_FILE" | tr -d '"' | tr -d "'" )"
fi
if [ -n "$SECRET_VAL" ]; then
# 脱敏显示前4后4
MASKED="${SECRET_VAL:0:4}****${SECRET_VAL: -4}"
echo ""
echo -e "🌐 Dashboardhttp://${api_host}:${api_port}/ui"
echo "🔐 Secret${MASKED}"
echo " 查看完整 Secretsudo awk -F': *' '/^secret:/{print \$2; exit}' $CONF_FILE"
else
echo -e "🔐 Secret请查看 .env 或启动日志输出"
echo ""
echo -e "🌐 Dashboardhttp://${api_host}:${api_port}/ui"
echo "🔐 Secret未配置当前为无鉴权模式仅限本机访问可用以下命令查看"
echo " sudo awk -F': *' '/^secret:/{print \$2; exit}' $CONF_FILE"
fi
echo

View File

@ -53,15 +53,38 @@ else
fi
fi
# 获取 CLASH_SECRET 值:优先 .env否则尝试读取旧 config否则生成随机
# 获取 CLASH_SECRET 值:优先 .env其次读取旧 config占位符视为无效;最后生成随机
Secret="${CLASH_SECRET:-}"
# 尝试从旧 config.yaml 读取(仅当 .env 未提供)
if [ -z "$Secret" ] && [ -f "$Conf_Dir/config.yaml" ]; then
Secret="$(awk -F': ' '/^secret:/{print $2; exit}' "$Conf_Dir/config.yaml" || true)"
Secret="$(awk -F': *' '/^secret:/{gsub(/"/,"",$2); print $2; exit}' "$Conf_Dir/config.yaml" || true)"
fi
# 若读取到的是占位符(如 ${CLASH_SECRET}),视为无效
if [[ "$Secret" =~ ^\$\{.*\}$ ]]; then
Secret=""
fi
# 兜底生成随机 secret
if [ -z "$Secret" ]; then
Secret="$(openssl rand -hex 32)"
fi
# 强制写入 secret 到指定配置文件(存在则替换,不存在则追加)
force_write_secret() {
local file="$1"
[ -f "$file" ] || return 0
if grep -qE '^[[:space:]]*secret:' "$file"; then
# 替换整行 secret无论原来是啥包括 SECRET_PLACEHOLDER / "${CLASH_SECRET}"
sed -i -E "s|^[[:space:]]*secret:.*$|secret: ${Secret}|g" "$file"
else
# 没有 secret 行就追加到文件末尾
printf "\nsecret: %s\n" "$Secret" >> "$file"
fi
}
# 设置默认值
CLASH_HTTP_PORT="${CLASH_HTTP_PORT:-7890}"
CLASH_SOCKS_PORT="${CLASH_SOCKS_PORT:-7891}"
@ -155,6 +178,8 @@ ensure_fallback_config() {
exit 1
fi
fi
# 强制写入真实 secret
force_write_secret "$Conf_Dir/config.yaml"
}
SKIP_CONFIG_REBUILD=false
@ -319,11 +344,11 @@ if [ "$SKIP_CONFIG_REBUILD" != "true" ]; then
fi
# 写入 secret
sed -r -i "/^secret: /s@(secret: ).*@\1${Secret}@g" "$Conf_Dir/config.yaml" || true
force_write_secret "$Conf_Dir/config.yaml"
else
# 兜底路径:尽量也写入 secret若 config 里有 secret: 行就替换;没有就追加)
if grep -qE '^secret:\s*' "$Conf_Dir/config.yaml" 2>/dev/null; then
sed -r -i "/^secret: /s@(secret: ).*@\1${Secret}@g" "$Conf_Dir/config.yaml" || true
force_write_secret "$Conf_Dir/config.yaml"
else
echo "secret: ${Secret}" >> "$Conf_Dir/config.yaml" || true
fi
@ -337,6 +362,12 @@ if [ ! -s "$Conf_Dir/config.yaml" ]; then
exit 1
fi
# 最终护栏:禁止未渲染的占位符进入运行态
if grep -q '\${' "$Conf_Dir/config.yaml"; then
echo "[ERROR] config.yaml contains unresolved placeholders (\${...}). Please check template rendering." >&2
exit 1
fi
echo -e '\n正在启动Clash服务...'
Text5="服务启动成功!"
Text6="服务启动失败!"
@ -360,7 +391,19 @@ if_success "$Text5" "$Text6" "$ReturnStatus"
echo ''
if [ "$EXTERNAL_CONTROLLER_ENABLED" = "true" ]; then
echo -e "Clash Dashboard 访问地址: http://${EXTERNAL_CONTROLLER}/ui"
echo -e "Secret: ${Secret}"
SHOW_SECRET="${CLASH_SHOW_SECRET:-false}"
SHOW_SECRET_MASKED="${CLASH_SHOW_SECRET_MASKED:-true}"
if [ "$SHOW_SECRET" = "true" ]; then
echo -e "Secret: ${Secret}"
elif [ "$SHOW_SECRET_MASKED" = "true" ]; then
# 脱敏前4后4
masked="${Secret:0:4}****${Secret: -4}"
echo -e "Secret: ${masked} (set CLASH_SHOW_SECRET=true to show full)"
else
echo -e "Secret: 已生成(未显示)。查看:/opt/clash-for-linux/conf/config.yaml 或 .env"
fi
else
echo -e "External Controller (Dashboard) 已禁用"
fi