215 lines
5.2 KiB
Bash
215 lines
5.2 KiB
Bash
#!/bin/bash
|
||
set -euo pipefail
|
||
|
||
echo "=============================="
|
||
echo " FRPC 安装程序"
|
||
echo "=============================="
|
||
|
||
# ==========================================
|
||
# 0. 工具函数
|
||
# ==========================================
|
||
die() { echo "❌ $*" >&2; exit 1; }
|
||
info() { echo "✔ $*"; }
|
||
step() { echo "➡ $*"; }
|
||
|
||
need_cmd() {
|
||
command -v "$1" >/dev/null 2>&1
|
||
}
|
||
|
||
# 统一下载:优先 wget,其次 curl(断点续传)
|
||
download() {
|
||
local url="$1"
|
||
local out="$2"
|
||
|
||
if need_cmd wget; then
|
||
# -c: 断点续传
|
||
# -T: 超时
|
||
# -t: 重试次数
|
||
info "使用 wget 下载(支持断点续传)"
|
||
wget -c \
|
||
--timeout=20 \
|
||
--read-timeout=20 \
|
||
-t 0 \
|
||
"$url" -O "$out"
|
||
|
||
elif need_cmd curl; then
|
||
# -C - : 断点续传
|
||
# -f : HTTP 非 2xx 失败
|
||
# -L : 跟随重定向
|
||
# --retry-* : 抗抖动
|
||
info "使用 curl 下载(断点续传)"
|
||
curl -fL -C - \
|
||
--connect-timeout 20 \
|
||
--retry 0 \
|
||
--retry-delay 3 \
|
||
--retry-all-errors \
|
||
"$url" -o "$out"
|
||
|
||
else
|
||
die "系统中既没有 wget 也没有 curl,无法下载:$url"
|
||
fi
|
||
}
|
||
|
||
# ==========================================
|
||
# 1. 确保 sudo 权限
|
||
# ==========================================
|
||
if ! need_cmd sudo; then
|
||
die "系统未安装 sudo,请用 root 执行该脚本"
|
||
fi
|
||
sudo -v
|
||
|
||
# ==========================================
|
||
# 2. 输入设备名
|
||
# ==========================================
|
||
read -r -p "请输入设备名称(deviceName,例如 z200_01): " deviceName
|
||
[ -n "${deviceName}" ] || die "设备名不能为空"
|
||
|
||
# 简单合法性校验:只允许字母数字下划线中划线
|
||
if ! [[ "$deviceName" =~ ^[A-Za-z0-9_-]+$ ]]; then
|
||
die "设备名不合法:仅允许字母/数字/_/-"
|
||
fi
|
||
|
||
echo ""
|
||
info "设备名:$deviceName"
|
||
echo ""
|
||
|
||
# ==========================================
|
||
# 3. 检测架构
|
||
# ==========================================
|
||
ARCH="$(uname -m)"
|
||
info "检测到架构:$ARCH"
|
||
|
||
case "$ARCH" in
|
||
aarch64) PKG="frp_0.65.0_linux_arm64.tar.gz" ;;
|
||
armv7l|armv7*) PKG="frp_0.65.0_linux_arm.tar.gz" ;;
|
||
x86_64|amd64) PKG="frp_0.65.0_linux_amd64.tar.gz" ;;
|
||
*) die "不支持架构:$ARCH" ;;
|
||
esac
|
||
|
||
BASE="http://36.153.162.171:20080/frp"
|
||
URL="$BASE/$PKG"
|
||
|
||
# ==========================================
|
||
# 4. 下载 / 解压(断电可恢复)
|
||
# ==========================================
|
||
FRP_DIR="/usr/local/frp"
|
||
FRPC_BIN="$FRP_DIR/frpc"
|
||
|
||
CACHE_DIR="/var/cache/frp"
|
||
PKG_PATH="$CACHE_DIR/$PKG"
|
||
|
||
if sudo test -x "$FRPC_BIN"; then
|
||
info "检测到本地已有 FRPC:$FRPC_BIN(跳过下载)"
|
||
else
|
||
step "准备缓存目录:$CACHE_DIR"
|
||
sudo mkdir -p "$CACHE_DIR"
|
||
sudo chown "$(id -u):$(id -g)" "$CACHE_DIR"
|
||
|
||
if [ -f "$PKG_PATH" ]; then
|
||
info "检测到缓存文件,继续断点续传:$PKG_PATH"
|
||
else
|
||
info "缓存中不存在安装包,将开始下载"
|
||
fi
|
||
|
||
step "下载:$URL"
|
||
download "$URL" "$PKG_PATH"
|
||
info "下载完成:$PKG_PATH"
|
||
|
||
step "解压到:$FRP_DIR"
|
||
sudo mkdir -p "$FRP_DIR"
|
||
sudo tar -xzf "$PKG_PATH" -C "$FRP_DIR" --strip-components=1
|
||
sudo chmod +x "$FRPC_BIN" || true
|
||
|
||
sudo test -x "$FRPC_BIN" || die "解压后未找到可执行 frpc:$FRPC_BIN"
|
||
info "解压完成"
|
||
|
||
# 可选:如果你希望节省空间,确认安装成功后再删
|
||
# sudo rm -f "$PKG_PATH"
|
||
fi
|
||
|
||
# ==========================================
|
||
# 5. 生成 frpc.toml
|
||
# ==========================================
|
||
PROXY_NAME="${deviceName}_stcp"
|
||
SECRET_KEY="${deviceName}_key"
|
||
|
||
step "生成配置 /etc/frp/frpc.toml"
|
||
sudo mkdir -p /etc/frp
|
||
|
||
sudo tee /etc/frp/frpc.toml >/dev/null <<EOF
|
||
serverAddr = "36.153.162.171"
|
||
serverPort = 7001
|
||
|
||
[auth]
|
||
method = "token"
|
||
token = "token123456"
|
||
|
||
[transport]
|
||
protocol = "kcp"
|
||
|
||
[[proxies]]
|
||
name = "$PROXY_NAME"
|
||
type = "stcp"
|
||
localIP = "127.0.0.1"
|
||
localPort = 22
|
||
secretKey = "$SECRET_KEY"
|
||
|
||
# visitor 由服务器 callback 自动追加
|
||
EOF
|
||
|
||
info "已生成 /etc/frp/frpc.toml"
|
||
|
||
# ==========================================
|
||
# 6. 回调注册(一定要在重启 frpc 之前)
|
||
# ==========================================
|
||
CALLBACK_URL="$BASE/callback?device=$deviceName"
|
||
step "回调注册(在重启 frpc 之前):$CALLBACK_URL"
|
||
|
||
# 用 download 抓取返回文本(落到临时文件)
|
||
tmp_cb="$(mktemp)"
|
||
trap 'rm -f "$tmp_cb"' EXIT
|
||
|
||
download "$CALLBACK_URL" "$tmp_cb" || die "回调请求失败"
|
||
RESULT="$(cat "$tmp_cb" 2>/dev/null || true)"
|
||
info "服务器返回:$RESULT"
|
||
|
||
# ==========================================
|
||
# 7. systemd 服务
|
||
# ==========================================
|
||
step "写入 systemd 服务 /etc/systemd/system/frpc.service"
|
||
|
||
sudo tee /etc/systemd/system/frpc.service >/dev/null <<EOF
|
||
[Unit]
|
||
Description=FRPC Client
|
||
After=network-online.target
|
||
Wants=network-online.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
ExecStart=$FRPC_BIN -c /etc/frp/frpc.toml
|
||
Restart=always
|
||
RestartSec=5
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl enable frpc
|
||
|
||
info "即将重启 frpc,当前 SSH 连接可能会断开"
|
||
sudo systemctl restart frpc
|
||
|
||
# 给 1 秒让它起起来再检查
|
||
sleep 1
|
||
sudo systemctl --no-pager -l status frpc || die "frpc 服务启动失败,请看上面的日志"
|
||
|
||
info "FRPC 已重新启动(新配置已生效)"
|
||
|
||
|
||
echo "=============================="
|
||
echo " 安装完成!"
|
||
echo " 设备名:$deviceName"
|
||
echo "=============================="
|
||
|