Files
linux-bash/frp/install_frp.sh
2026-02-17 17:28:37 +08:00

193 lines
4.5 KiB
Bash
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
# FRP 一键安装脚本
# 用法示例curl -fsSL "https://pan.shumengya.top/d/scripts/frp/install_frp.sh" | sudo bash
# 包含 frps (服务端) 和 frpc (客户端) 的安装
# 目录结构假设:
# BASE_URL/linux_amd64/frps
# BASE_URL/linux_amd64/frpc
# BASE_URL/frps.toml
# BASE_URL/frpc.toml
# BASE_URL/smy-frps.service (模板)
# BASE_URL/smy-frpc.service (模板)
BASE_URL="https://pan.shumengya.top/d/scripts/frp/frp"
INSTALL_DIR="/shumengya/bin/frp"
SERVICE_PREFIX="smy-frp"
log() { printf '[frp-安装] %s\n' "$*" >&2; }
fail() { log "错误: $*" >&2; exit 1; }
# 进度条函数
show_progress() {
local pid=$1
local text=$2
local delay=0.1
local spin='-\|/'
printf "[frp-安装] %s... " "$text" >&2
while ps -p "$pid" > /dev/null 2>&1; do
local temp=${spin#?}
printf "\b%c" "$spin" >&2
local spin=$temp${spin%"$temp"}
sleep $delay
done
printf "\b完成\n" >&2
}
require_root() {
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
fail "请使用 root 权限运行 (sudo bash install_frp.sh)"
fi
}
detect_arch() {
local machine
machine=$(uname -m)
case "$machine" in
x86_64|amd64) echo "linux_amd64" ;;
aarch64|arm64) echo "linux_arm64" ;;
*) fail "不支持的架构: $machine" ;;
esac
}
select_mode() {
echo "请选择安装模式:" >&2
echo "1) 安装客户端 (frpc)" >&2
echo "2) 安装服务端 (frps)" >&2
echo "3) 同时安装" >&2
read -p "请输入选项 [1-3]: " choice < /dev/tty
case "$choice" in
1) echo "client" ;;
2) echo "server" ;;
3) echo "both" ;;
*) fail "无效选项" ;;
esac
}
download_and_install() {
local mode=$1
local arch=$2
local tmp_dir
tmp_dir=$(mktemp -d)
trap 'if [ -n "${tmp_dir:-}" ] && [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi' EXIT
mkdir -p "$INSTALL_DIR"
if [ "$mode" = "client" ] || [ "$mode" = "both" ]; then
install_component "frpc" "$arch" "$tmp_dir"
fi
if [ "$mode" = "server" ] || [ "$mode" = "both" ]; then
install_component "frps" "$arch" "$tmp_dir"
fi
}
install_component() {
local name=$1 # frpc or frps
local arch=$2
local tmp_dir=$3
local bin_url="${BASE_URL}/${arch}/${name}"
local conf_url="${BASE_URL}/${name}.toml"
local service_name="${SERVICE_PREFIX}${name:3}" # smy-frpc or smy-frps
log "正在处理 $name ..."
# 停止旧服务
systemctl stop "${service_name}.service" 2>/dev/null || true
# 强制清理可能残留的进程 (避免 Text file busy)
pids=$(pgrep -x "$name" || true)
if [ -n "$pids" ]; then
log "清理 $name 残留进程..."
kill -9 $pids 2>/dev/null || true
fi
# 下载二进制
curl -fsSL "$bin_url" -o "$tmp_dir/$name" &
show_progress $! "下载 $name 二进制文件"
[ -f "$tmp_dir/$name" ] || fail "下载 $name 失败"
# 下载配置
curl -fsSL "$conf_url" -o "$tmp_dir/${name}.toml" &
show_progress $! "下载 $name 配置文件"
[ -f "$tmp_dir/${name}.toml" ] || fail "下载配置文件失败"
# 安装文件
cp "$tmp_dir/$name" "$INSTALL_DIR/$name"
chmod +x "$INSTALL_DIR/$name"
if [ ! -f "$INSTALL_DIR/${name}.toml" ]; then
cp "$tmp_dir/${name}.toml" "$INSTALL_DIR/${name}.toml"
else
log "保留现有配置文件: $INSTALL_DIR/${name}.toml"
fi
# 配置服务
write_service "$name"
# 启动服务
systemctl daemon-reload
systemctl enable "${service_name}.service"
systemctl restart "${service_name}.service"
sleep 2
if systemctl is-active --quiet "${service_name}.service"; then
log "$name 服务启动成功"
else
log "警告: $name 服务启动失败,查看日志:"
journalctl -u "${service_name}.service" --no-pager -n 10
fi
}
write_service() {
local name=$1
local service_name="${SERVICE_PREFIX}${name:3}"
local service_file="/etc/systemd/system/${service_name}.service"
cat > "$service_file" <<EOF
[Unit]
Description=${service_name}
After=network.target
[Service]
Type=simple
WorkingDirectory=$INSTALL_DIR
ExecStart=$INSTALL_DIR/$name -c $INSTALL_DIR/${name}.toml
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
}
main() {
require_root
local arch
arch=$(detect_arch)
log "检测到架构: $arch"
local mode
if [ $# -gt 0 ]; then
case "$1" in
client|frpc) mode="client" ;;
server|frps) mode="server" ;;
both) mode="both" ;;
*) fail "无效参数: $1 (可用: client, server, both)" ;;
esac
else
mode=$(select_mode)
fi
download_and_install "$mode" "$arch"
log "=========================================="
log "安装任务完成!"
log "安装目录: $INSTALL_DIR"
log "=========================================="
}
main "$@"