feat: 一条 curl 自动装/升(未装安装、已装升级)
This commit is contained in:
Executable
+260
@@ -0,0 +1,260 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
# shellcheck source=lib.sh
|
||||
source "$ROOT_DIR/scripts/lib.sh"
|
||||
|
||||
AUTO_DETECT="${AUTO_DETECT:-true}"
|
||||
AUTO_VERIFY="${AUTO_VERIFY:-true}"
|
||||
SKIP_START="${SKIP_START:-false}"
|
||||
|
||||
if [[ ! -f "$ROOT_DIR/config/settings.conf" ]]; then
|
||||
cp "$ROOT_DIR/config/settings.conf.example" "$ROOT_DIR/config/settings.conf"
|
||||
warn "已创建 config/settings.conf(将自动探测数据网卡并生成密钥)"
|
||||
fi
|
||||
|
||||
load_config
|
||||
need_root
|
||||
|
||||
info "1/6 自动探测并绑定数据网卡"
|
||||
"$ROOT_DIR/scripts/detect.sh" || true
|
||||
|
||||
cell=""
|
||||
if [[ -n "${CELLULAR_IFACE:-}" ]] && iface_exists "$CELLULAR_IFACE"; then
|
||||
cell="$CELLULAR_IFACE"
|
||||
info "使用配置的数据网卡: $cell"
|
||||
elif [[ "$AUTO_DETECT" == "true" ]]; then
|
||||
cell="$(detect_cellular_iface "" || true)"
|
||||
fi
|
||||
|
||||
if [[ -z "$cell" ]]; then
|
||||
die "未能自动探测数据网卡。
|
||||
请插入/拨通数据模块后重试,或手动:
|
||||
1) ./scripts/detect.sh
|
||||
2) 编辑 config/settings.conf 设置 CELLULAR_IFACE=网卡名
|
||||
3) sudo ./scripts/install.sh"
|
||||
fi
|
||||
|
||||
src_ip="$(detect_source_ip "$cell" || true)"
|
||||
persist_cellular_to_settings "$ROOT_DIR/config/settings.conf" "$cell" "$src_ip"
|
||||
# 重新加载
|
||||
CELLULAR_IFACE="$cell"
|
||||
CELLULAR_SOURCE_IP="$src_ip"
|
||||
info "已绑定 CELLULAR_IFACE=$cell source_ip=${src_ip:-auto}"
|
||||
|
||||
# 随机面板密钥(若仍是默认)
|
||||
if [[ "$PANEL_SECRET" == "please-change-me" || "$PANEL_SECRET" == "change-this-secret" || -z "$PANEL_SECRET" ]]; then
|
||||
gen="$(openssl rand -hex 12 2>/dev/null || head -c 16 /dev/urandom | xxd -p | tr -d '\n')"
|
||||
tmp="$(mktemp)"
|
||||
awk -v k="PANEL_SECRET" -v v="$gen" '
|
||||
BEGIN { done=0 }
|
||||
index($0, k "=")==1 { print k "=" v; done=1; next }
|
||||
{ print }
|
||||
END { if (!done) print k "=" v }
|
||||
' "$ROOT_DIR/config/settings.conf" > "$tmp"
|
||||
mv "$tmp" "$ROOT_DIR/config/settings.conf"
|
||||
PANEL_SECRET="$gen"
|
||||
warn "已自动生成 PANEL_SECRET(见 settings.conf)"
|
||||
fi
|
||||
|
||||
# 再 load 一次保证变量一致
|
||||
load_config
|
||||
CELLULAR_IFACE="$cell"
|
||||
CELLULAR_SOURCE_IP="${src_ip:-$CELLULAR_SOURCE_IP}"
|
||||
|
||||
info "2/6 下载/安装 sing-box + UI"
|
||||
"$ROOT_DIR/scripts/fetch-binaries.sh"
|
||||
|
||||
info "3/6 生成配置(代理出口 bind = $cell)"
|
||||
"$ROOT_DIR/scripts/generate.sh" "$ROOT_DIR/generated"
|
||||
ensure_dirs
|
||||
mkdir -p /var/lib/cellular-proxy
|
||||
install -m 0644 "$ROOT_DIR/generated/config.json" "$INSTALL_DIR/etc/config.json"
|
||||
install -m 0644 "$ROOT_DIR/generated/runtime.env" "$INSTALL_DIR/etc/runtime.env"
|
||||
install -m 0644 "$ROOT_DIR/config/settings.conf" "$INSTALL_DIR/etc/settings.conf"
|
||||
cp -a "$ROOT_DIR/scripts" "$INSTALL_DIR/"
|
||||
cp -a "$ROOT_DIR/ui" "$INSTALL_DIR/" 2>/dev/null || true
|
||||
if ! "$INSTALL_DIR/bin/sing-box" check -c "$INSTALL_DIR/etc/config.json"; then
|
||||
die "sing-box 配置校验失败"
|
||||
fi
|
||||
|
||||
# 确认 bind_interface 写进配置
|
||||
if ! grep -q "\"bind_interface\": \"$cell\"" "$INSTALL_DIR/etc/config.json" \
|
||||
&& ! grep -q "\"bind_interface\": \"$cell\"" "$INSTALL_DIR/etc/config.json" 2>/dev/null; then
|
||||
# JSON 可能无空格差异
|
||||
if ! python3 - "$INSTALL_DIR/etc/config.json" "$cell" <<'PY'
|
||||
import json,sys
|
||||
c=json.load(open(sys.argv[1]))
|
||||
cell=sys.argv[2]
|
||||
ok=any(o.get("tag")=="cellular" and o.get("bind_interface")==cell for o in c.get("outbounds",[]))
|
||||
sys.exit(0 if ok else 1)
|
||||
PY
|
||||
then
|
||||
die "配置未正确绑定数据网卡 $cell"
|
||||
fi
|
||||
fi
|
||||
info "配置已确认 bind_interface=$cell"
|
||||
|
||||
install -m 0755 /dev/stdin "$INSTALL_DIR/bin/cpxy" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
BASE="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
export CONFIG_FILE="${CONFIG_FILE:-$BASE/etc/settings.conf}"
|
||||
cmd="${1:-help}"
|
||||
shift || true
|
||||
case "$cmd" in
|
||||
detect) exec "$BASE/scripts/detect.sh" "$@" ;;
|
||||
generate)
|
||||
# 重新探测:若 settings 里网卡丢失则自动补
|
||||
# shellcheck source=/dev/null
|
||||
source "$BASE/scripts/lib.sh"
|
||||
load_config
|
||||
if [[ -z "${CELLULAR_IFACE:-}" ]] || ! iface_exists "${CELLULAR_IFACE:-}"; then
|
||||
cell="$(detect_cellular_iface "" || true)"
|
||||
if [[ -n "$cell" ]]; then
|
||||
src="$(detect_source_ip "$cell" || true)"
|
||||
persist_cellular_to_settings "$CONFIG_FILE" "$cell" "$src"
|
||||
CELLULAR_IFACE="$cell"
|
||||
fi
|
||||
fi
|
||||
"$BASE/scripts/generate.sh" "$BASE/generated"
|
||||
install -m 0644 "$BASE/generated/config.json" "$BASE/etc/config.json"
|
||||
install -m 0644 "$BASE/generated/runtime.env" "$BASE/etc/runtime.env"
|
||||
install -m 0644 "$CONFIG_FILE" "$BASE/etc/settings.conf" 2>/dev/null || true
|
||||
"$BASE/bin/sing-box" check -c "$BASE/etc/config.json"
|
||||
systemctl restart cellular-proxy 2>/dev/null || true
|
||||
;;
|
||||
rebind)
|
||||
# shellcheck source=/dev/null
|
||||
source "$BASE/scripts/lib.sh"
|
||||
load_config
|
||||
cell="$(detect_cellular_iface "" || true)"
|
||||
[[ -n "$cell" ]] || die "未能探测数据网卡"
|
||||
src="$(detect_source_ip "$cell" || true)"
|
||||
persist_cellular_to_settings "$CONFIG_FILE" "$cell" "$src"
|
||||
info "已重新绑定 $cell"
|
||||
exec "$0" generate
|
||||
;;
|
||||
start) systemctl start cellular-proxy ;;
|
||||
stop) systemctl stop cellular-proxy ;;
|
||||
restart) systemctl restart cellular-proxy ;;
|
||||
status) systemctl status cellular-proxy --no-pager || true ;;
|
||||
verify) exec "$BASE/scripts/verify.sh" "$@" ;;
|
||||
auth)
|
||||
exec "$BASE/scripts/apply-proxy-auth.sh" "$@"
|
||||
;;
|
||||
upgrade)
|
||||
# 一条命令在线增量升级(保留密钥/网卡)
|
||||
if [[ -x "$BASE/scripts/online-upgrade.sh" ]]; then
|
||||
exec "$BASE/scripts/online-upgrade.sh" "$@"
|
||||
fi
|
||||
# 兜底:直接 curl 入口
|
||||
url="${CELLULAR_PROXY_INSTALL_URL:-https://gitea.chickliu.fun/Hermes/cellular-proxy/raw/branch/main/install.sh}"
|
||||
exec bash -c 'curl -fsSL "$1" | bash -s -- --upgrade --install-dir "$2" "${@:3}"' _ "$url" "$BASE" "$@"
|
||||
;;
|
||||
logs) journalctl -u cellular-proxy -n "${1:-80}" -f ;;
|
||||
help|*)
|
||||
cat <<H
|
||||
cpxy — cellular-proxy
|
||||
语义: 走代理的连接一律从数据网卡出口
|
||||
cpxy detect | rebind | generate | start | stop | restart | status
|
||||
cpxy verify | logs [N]
|
||||
cpxy auth --user U --pass P # 设置 7890 代理账号密码
|
||||
cpxy auth --clear | --show
|
||||
cpxy upgrade # 一条命令在线增量升级
|
||||
cpxy upgrade --ui-only # 只更新面板
|
||||
cpxy upgrade --force-binary # 强制重下 sing-box
|
||||
cpxy upgrade --verify # 升级后验证出口
|
||||
H
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$INSTALL_DIR/scripts/"*.sh "$INSTALL_DIR/scripts/"*.py 2>/dev/null || true
|
||||
ln -sfn "$INSTALL_DIR/bin/cpxy" /usr/local/bin/cpxy
|
||||
|
||||
info "4/6 安装 systemd"
|
||||
MEM="${MEMORY_MAX_MB:-96}"
|
||||
install -m 0644 "$ROOT_DIR/systemd/cellular-proxy.service" /etc/systemd/system/cellular-proxy.service
|
||||
sed -i "s|@INSTALL_DIR@|$INSTALL_DIR|g" /etc/systemd/system/cellular-proxy.service
|
||||
sed -i "s|@LOG_DIR@|$LOG_DIR|g" /etc/systemd/system/cellular-proxy.service
|
||||
if [[ "$MEM" != "0" && -n "$MEM" ]]; then
|
||||
sed -i "s|@MEMORY_MAX@|${MEM}M|g" /etc/systemd/system/cellular-proxy.service
|
||||
else
|
||||
sed -i '/MemoryMax=@MEMORY_MAX@/d' /etc/systemd/system/cellular-proxy.service
|
||||
fi
|
||||
# 管理 API(UI 配置代理账密)
|
||||
if [[ -f "$ROOT_DIR/systemd/cellular-proxy-admin.service" ]]; then
|
||||
install -m 0644 "$ROOT_DIR/systemd/cellular-proxy-admin.service" /etc/systemd/system/cellular-proxy-admin.service
|
||||
sed -i "s|@INSTALL_DIR@|$INSTALL_DIR|g" /etc/systemd/system/cellular-proxy-admin.service
|
||||
fi
|
||||
systemctl daemon-reload
|
||||
|
||||
info "5/6 启动服务"
|
||||
export SYSTEMD_PAGER=cat
|
||||
export SYSTEMD_COLORS=0
|
||||
if [[ "$SKIP_START" == "true" ]]; then
|
||||
systemctl enable cellular-proxy.service
|
||||
systemctl enable cellular-proxy-admin.service 2>/dev/null || true
|
||||
systemctl stop cellular-proxy.service 2>/dev/null || true
|
||||
systemctl stop cellular-proxy-admin.service 2>/dev/null || true
|
||||
info "已按 SKIP_START 跳过启动"
|
||||
else
|
||||
systemctl enable cellular-proxy.service
|
||||
systemctl enable cellular-proxy-admin.service 2>/dev/null || true
|
||||
systemctl restart cellular-proxy.service
|
||||
systemctl restart cellular-proxy-admin.service 2>/dev/null || true
|
||||
# 等待 active,最多约 8 秒(避免 status 卡住)
|
||||
ok=0
|
||||
for _ in 1 2 3 4 5 6 7 8; do
|
||||
if systemctl is-active --quiet cellular-proxy.service; then
|
||||
ok=1
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
active_state="$(systemctl is-active cellular-proxy.service 2>/dev/null || echo unknown)"
|
||||
info "服务状态: $active_state"
|
||||
if [[ "$ok" -ne 1 ]]; then
|
||||
err "服务未处于 active"
|
||||
systemctl show cellular-proxy.service -p ActiveState -p SubState -p Result -p ExecMainStatus --no-pager 2>/dev/null || true
|
||||
journalctl -u cellular-proxy -n 40 --no-pager 2>/dev/null || true
|
||||
die "启动失败,请检查数据网卡 $cell 是否 up 且有 IP"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "6/6 自动验证出口(短超时,失败不阻塞安装结束)"
|
||||
if [[ "$SKIP_START" != "true" && "$AUTO_VERIFY" == "true" ]]; then
|
||||
set +e
|
||||
# 安装阶段用短超时;VERIFY_QUICK=1 跳过 detect 长输出
|
||||
VERIFY_QUICK=1 EGRESS_TIMEOUT="${EGRESS_TIMEOUT:-8}" \
|
||||
"$ROOT_DIR/scripts/verify.sh"
|
||||
vr=$?
|
||||
set -e
|
||||
if [[ "$vr" -eq 0 ]]; then
|
||||
info "出口验证通过:代理已从数据网卡出"
|
||||
else
|
||||
warn "自动验证未通过(exit=$vr)。安装仍算完成,稍后可: cpxy verify"
|
||||
warn "当前绑定: CELLULAR_IFACE=$cell ip=${src_ip:-}"
|
||||
fi
|
||||
else
|
||||
info "已跳过自动验证"
|
||||
fi
|
||||
|
||||
echo
|
||||
info "安装完成(全自动探测 + 绑定)"
|
||||
echo " 数据网卡: $cell (${src_ip:-no-ipv4})"
|
||||
echo " 语义: 不走代理 → 系统默认(WiFi);走代理 → 数据流量"
|
||||
echo " 代理: HTTP/SOCKS ${PROXY_LISTEN_HOST}:${PROXY_MIXED_PORT}"
|
||||
if [[ -n "${PROXY_USER:-}" ]]; then
|
||||
echo " 代理鉴权: 用户 ${PROXY_USER}(密码已设置)"
|
||||
else
|
||||
echo " 代理鉴权: 无(建议: cpxy auth --user u --pass p 或面板配置)"
|
||||
fi
|
||||
echo " 面板: http://<LAN-IP>:${PANEL_PORT}/ui/ 密钥: $PANEL_SECRET"
|
||||
echo " 管理API: http://<LAN-IP>:9091 (UI 里改代理账密用,密钥同上)"
|
||||
echo " 配置: $INSTALL_DIR/etc/settings.conf"
|
||||
echo " 管理: cpxy rebind | verify | logs | status"
|
||||
echo " 账密: cpxy auth --user U --pass P | --clear | --show"
|
||||
echo " 若刚才像卡住:多半在测公网出口,现已改为短超时并保证退出"
|
||||
# 安装脚本始终以 0 结束(服务已 active);验证失败只告警
|
||||
exit 0
|
||||
Reference in New Issue
Block a user