Files
cellular-proxy/scripts/install.sh
T
Hermes 91939c7cc2 feat: UI/CLI 配置代理账密;armv7 仅保留整包
- 面板可设置 7890 账号密码(管理 API :9091)
- cpxy auth --user/--pass/--clear/--show
- Release armv7 整包已验证,已删除分片资产
2026-07-21 12:29:57 +00:00

249 lines
9.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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" "$@"
;;
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 # 清除鉴权
cpxy auth --show # 查看状态
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
# 管理 APIUI 配置代理账密)
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