From 8a8832e4c92efce3088c0411a6b2355848e3db33 Mon Sep 17 00:00:00 2001 From: eddy Date: Tue, 27 Oct 2026 16:33:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20frpc2.sh=EF=BC=8C?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E5=AE=89=E8=A3=85=E7=8B=AC=E7=AB=8B=E7=9A=84?= =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E4=B8=AA=20frpc=20=E5=AE=9E=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 SERVICE_NAME=frpc2,安装到 /root/data/docker_data/frpc2, 可与现有 frpc(Docker 或 systemd)同时运行而不冲突 - systemd 服务文件及所有 systemctl/journalctl 调用统一使用 ${SERVICE_NAME} - 启动前提示编辑 frpc.toml,并提醒代理名、远程端口不能与其它实例重复 - 安装时使用 systemctl restart,确保修改后的配置生效 - 卸载时若仍存在其它 frpc*.service,则保留共享的 frp 用户 - 优先用 setfacl 为 frp 用户授予目录访问权限,失败时回退到 chmod 755 - 修复 set -e 导致菜单意外退出:systemctl/cat 调用加保护, 取消卸载后返回菜单,查看日志时 Ctrl+C 只结束日志而不退出脚本 --- frpc2.sh | 690 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 690 insertions(+) create mode 100644 frpc2.sh diff --git a/frpc2.sh b/frpc2.sh new file mode 100644 index 0000000..de6c89e --- /dev/null +++ b/frpc2.sh @@ -0,0 +1,690 @@ +#!/bin/bash + +# FRP Client 第二实例 (frpc2) 自动安装/卸载脚本 +# 可与 frpc.sh 安装的 frpc 实例同时运行,目录和服务名互相独立 +# 支持自动检测架构(amd64/arm64)并下载对应安装包 +# +# 使用方法: +# chmod +x frpc2.sh && ./frpc2.sh # 交互式主菜单 +# ./frpc2.sh manage # 进入服务管理界面 +# +# 快速安装: +# curl -sS -O https://gitea.tohub.top/Share/script/raw/branch/main/frpc2.sh && chmod +x frpc2.sh && ./frpc2.sh +# +# 注意: 两个实例的 frpc.toml 中代理名(name)、remotePort、webServer 端口不能重复 +# +# 功能说明: +# 1. 自动检测系统架构(amd64/arm64) +# 2. 自动下载对应架构的安装包 +# 3. 验证安装包完整性 +# 4. 安装并配置 frpc2 服务 +# 5. 提供完整的服务管理功能 + +# 彩色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# 配置变量 +SERVICE_NAME="frpc2" +INSTALL_DIR="/root/data/docker_data/frpc2" +BASE_URL="https://gitea.tohub.top/Share/script/raw/branch/main/frpc" +FRPC_VERSION="0.65.0" + + +set -e + + +# 日志函数 +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 兼容旧函数名 +log_info() { + print_info "$1" +} + +log_warn() { + print_warning "$1" +} + +log_error() { + print_error "$1" +} + +# 检查是否为root用户 +check_root() { + if [[ $EUID -ne 0 ]]; then + print_error "此脚本需要root权限运行" + print_info "请使用: sudo $0" + exit 1 + fi +} + +# 检测系统架构 +detect_arch() { + local arch=$(uname -m) + case "$arch" in + x86_64) + echo "amd64" + ;; + aarch64) + echo "arm64" + ;; + *) + print_error "不支持的系统架构: $arch" + print_info "仅支持 x86_64(amd64) 和 aarch64(arm64)" + exit 1 + ;; + esac +} + +# 创建安装目录 +create_install_dir() { + if [[ ! -d "$INSTALL_DIR" ]]; then + print_info "创建安装目录: $INSTALL_DIR" + mkdir -p "$INSTALL_DIR" + if [[ $? -ne 0 ]]; then + print_error "创建目录失败" + exit 1 + fi + fi +} + +# 下载文件 +download_file() { + local url=$1 + local output=$2 + + print_info "正在下载: $url" + + # 如果存在旧的不完整文件,先删除 + if [[ -f "$output" ]]; then + rm -f "$output" + fi + + if command -v wget &> /dev/null; then + wget -q --show-progress "$url" -O "$output" + elif command -v curl &> /dev/null; then + curl -# -L "$url" -o "$output" + else + print_error "未找到 wget 或 curl,请先安装" + exit 1 + fi + + # 检查下载是否成功 + if [[ $? -eq 0 ]] && [[ -f "$output" ]] && [[ -s "$output" ]]; then + print_success "下载完成: $output" + return 0 + else + print_error "下载失败: $url" + rm -f "$output" + return 1 + fi +} + +# 验证tar.gz文件是否有效 +verify_tar_file() { + local file=$1 + + if [[ ! -f "$file" ]]; then + return 1 + fi + + if [[ ! -s "$file" ]]; then + print_warning "文件为空: $file" + return 1 + fi + + # 尝试列出tar文件内容来验证完整性 + if ! tar -tzf "$file" >/dev/null 2>&1; then + print_warning "文件不是有效的 tar.gz 包: $file" + return 1 + fi + + return 0 +} + +# 下载安装包 +download_packages() { + local arch=$(detect_arch) + print_info "检测到系统架构: $arch" + + create_install_dir + + local frp_file="frp_${FRPC_VERSION}_linux_${arch}.tar.gz" + local download_failed=0 + + # 下载 FRP + if [[ ! -f "$INSTALL_DIR/$frp_file" ]]; then + if ! download_file "$BASE_URL/$frp_file" "$INSTALL_DIR/$frp_file"; then + download_failed=1 + fi + else + print_warning "文件已存在,跳过下载: $frp_file" + fi + + # 下载配置文件(如果不存在) + if [[ ! -f "$INSTALL_DIR/frpc.toml" ]]; then + print_info "下载配置文件模板..." + if ! download_file "$BASE_URL/frpc.toml" "$INSTALL_DIR/frpc.toml"; then + print_warning "配置文件下载失败,需要手动创建" + fi + fi + + return $download_failed +} + +# 创建frp用户 +create_frp_user() { + if ! id "frp" &>/dev/null; then + log_info "创建 frp 用户..." + useradd -r -s /bin/false frp + else + log_info "frp 用户已存在" + fi +} + +# 解压安装包 +extract_archive() { + local arch=$(detect_arch) + local frp_file="$INSTALL_DIR/frp_${FRPC_VERSION}_linux_${arch}.tar.gz" + + # 检查文件是否存在 + if [[ ! -f "$frp_file" ]]; then + print_warning "安装包不存在,开始下载..." + if ! download_packages; then + print_error "下载失败,无法继续安装" + return 1 + fi + fi + + # 验证文件完整性 + print_info "验证安装包完整性..." + if ! verify_tar_file "$frp_file"; then + print_error "安装包验证失败,请重新下载" + rm -f "$frp_file" + return 1 + fi + print_success "安装包验证通过" + + print_info "解压 frp_${FRPC_VERSION}_linux_${arch}.tar.gz..." + + # 创建临时目录 + TEMP_DIR=$(mktemp -d) + + # 解压到临时目录 + tar -xzf "$frp_file" -C "$TEMP_DIR" + + # 复制文件到安装目录 + cp "$TEMP_DIR"/frp_${FRPC_VERSION}_linux_${arch}/frpc "$INSTALL_DIR/" + + # 清理临时目录 + rm -rf "$TEMP_DIR" + + # 设置权限 - 确保 frp 用户可以访问和执行 + # 优先用 ACL 只给 frp 用户进入权限,避免把 /root 开放给所有用户 + if command -v setfacl &>/dev/null && setfacl -m u:frp:x /root /root/data /root/data/docker_data; then + print_info "已通过 ACL 授予 frp 用户目录访问权限" + else + print_warning "setfacl 不可用或失败,改用 chmod 755 开放上级目录(建议安装 acl 包)" + chmod 755 /root + chmod 755 /root/data + chmod 755 /root/data/docker_data + fi + chmod 755 "$INSTALL_DIR" + + # 设置文件所有者和权限 + chown root:frp "$INSTALL_DIR/frpc" + chmod 755 "$INSTALL_DIR/frpc" + + # 删除压缩包 + print_info "清理下载的压缩包..." + rm -f "$frp_file" + print_success "已删除压缩包" + + print_success "frpc 已安装到 $INSTALL_DIR/" +} + +# 配置frpc +configure_frpc() { + print_info "配置 frpc..." + + # 检查配置文件是否已存在 + if [[ -f "$INSTALL_DIR/frpc.toml" ]]; then + print_success "配置文件已存在: $INSTALL_DIR/frpc.toml" + elif [[ -f "frpc.toml" ]]; then + # 如果当前目录有配置文件,复制它 + print_warning "将复制当前目录的 frpc.toml,请确认它不是其它 frpc 实例正在使用的配置" + cp frpc.toml "$INSTALL_DIR/" + print_success "配置文件已复制到 $INSTALL_DIR/frpc.toml" + else + print_error "找不到配置文件 frpc.toml" + print_info "请手动创建配置文件: $INSTALL_DIR/frpc.toml" + return 1 + fi + + chown root:frp "$INSTALL_DIR/frpc.toml" + chmod 640 "$INSTALL_DIR/frpc.toml" + + # 启动前确认配置,避免与其它 frpc 实例的代理名/远程端口冲突 + print_warning "请确认 ${SERVICE_NAME} 的代理名、remote_port/remotePort 与其它 frpc 实例不重复" + read -p "是否现在编辑配置文件? [Y/n]: " edit_choice + if [[ ! $edit_choice =~ ^[Nn]$ ]]; then + edit_config + fi +} + +# 编辑配置文件 +edit_config() { + if command -v nano >/dev/null 2>&1; then + nano "$INSTALL_DIR/frpc.toml" + elif command -v vi >/dev/null 2>&1; then + vi "$INSTALL_DIR/frpc.toml" + else + print_error "未找到文本编辑器,请手动编辑: $INSTALL_DIR/frpc.toml" + fi +} + +# 创建systemd服务 +create_service() { + print_info "创建 systemd 服务..." + + cat > /etc/systemd/system/${SERVICE_NAME}.service << EOF +[Unit] +Description=Frp Client Service (${SERVICE_NAME}) +After=network.target + +[Service] +Type=simple +User=frp +Restart=on-failure +RestartSec=5s +ExecStart=${INSTALL_DIR}/frpc -c ${INSTALL_DIR}/frpc.toml +ExecReload=/bin/kill -s HUP \$MAINPID +KillMode=mixed +TimeoutStopSec=5s + +[Install] +WantedBy=multi-user.target +EOF + + # 重新加载systemd + systemctl daemon-reload + + print_success "systemd 服务已创建" +} + +# 启动服务 +start_service() { + print_info "启动 ${SERVICE_NAME} 服务..." + + # 启用开机自启 + systemctl enable ${SERVICE_NAME} + + # 启动服务(已运行时重启以加载新配置) + systemctl restart ${SERVICE_NAME} + + # 检查服务状态 + if systemctl is-active --quiet ${SERVICE_NAME}; then + print_success "${SERVICE_NAME} 服务启动成功" + else + print_error "${SERVICE_NAME} 服务启动失败" + print_error "请检查日志: journalctl -u ${SERVICE_NAME} -f" + return 1 + fi +} + +# 显示状态信息 +show_status() { + echo "" + print_success "============================================" + print_success "FRP Client (${SERVICE_NAME}) 安装完成!" + print_success "============================================" + echo "" + echo "服务状态:" + systemctl status ${SERVICE_NAME} --no-pager + echo "" + print_info "常用命令:" + echo " 启动服务: systemctl start ${SERVICE_NAME}" + echo " 停止服务: systemctl stop ${SERVICE_NAME}" + echo " 重启服务: systemctl restart ${SERVICE_NAME}" + echo " 查看状态: systemctl status ${SERVICE_NAME}" + echo " 查看日志: journalctl -u ${SERVICE_NAME} -f" + echo "" + print_info "配置文件位置: $INSTALL_DIR/frpc.toml" + print_info "程序位置: $INSTALL_DIR/frpc" + print_success "============================================" + echo "" +} + +# 安装frpc主函数 +install_frpc() { + print_info "开始安装 FRP Client..." + + create_frp_user + extract_archive || return 1 + configure_frpc || return 1 + create_service + start_service || return 1 + show_status + + print_success "FRP Client (${SERVICE_NAME}) 安装完成!" +} + +# 卸载frpc +uninstall_frpc() { + print_warning "即将卸载 FRP Client (${SERVICE_NAME})" + read -p "是否继续?[y/N] " -n 1 -r + echo + + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "已取消卸载" + return 1 + fi + + # 停止服务 + print_info "停止 ${SERVICE_NAME} 服务..." + systemctl stop ${SERVICE_NAME} 2>/dev/null || true + + # 禁用开机自启 + print_info "禁用开机自启..." + systemctl disable ${SERVICE_NAME} 2>/dev/null || true + + # 删除服务文件 + print_info "删除服务文件..." + rm -f /etc/systemd/system/${SERVICE_NAME}.service + systemctl daemon-reload + + # 删除程序文件 + print_info "删除程序文件..." + rm -rf "$INSTALL_DIR" + + # 删除frp用户(其它 frpc 实例仍在使用时保留) + if ls /etc/systemd/system/frpc*.service &>/dev/null; then + print_warning "检测到其它 frpc 实例仍在使用 frp 用户,保留该用户" + else + print_info "删除 frp 用户..." + userdel frp 2>/dev/null || true + fi + + echo "" + print_success "FRP Client (${SERVICE_NAME}) 已完全卸载" +} + +# 检查安装状态 +check_status() { + local arch=$(detect_arch) + local frp_file="$INSTALL_DIR/frp_${FRPC_VERSION}_linux_${arch}.tar.gz" + + echo "" + print_info "============================================" + print_info "检查 FRP Client 状态" + print_info "============================================" + + # 检查程序是否安装 + if [[ -f "$INSTALL_DIR/frpc" ]]; then + print_success "FRP Client 已安装" + print_info " 程序位置: $INSTALL_DIR/frpc" + + # 获取程序版本 + if [[ -x "$INSTALL_DIR/frpc" ]]; then + local version=$("$INSTALL_DIR/frpc" --version 2>/dev/null | head -n 1 || echo "未知") + print_info " 版本信息: $version" + fi + + # 检查服务状态 + if systemctl is-active --quiet ${SERVICE_NAME}; then + print_success "${SERVICE_NAME} 服务运行中" + else + print_warning "${SERVICE_NAME} 服务未运行" + fi + + if systemctl is-enabled --quiet ${SERVICE_NAME}; then + print_success "开机自启已启用" + else + print_warning "开机自启未启用" + fi + + # 检查配置文件 + if [[ -f "$INSTALL_DIR/frpc.toml" ]]; then + print_success "配置文件存在" + else + print_warning "配置文件不存在" + fi + else + print_warning "FRP Client 未安装" + fi + + # 检查frp用户 + if id "frp" &>/dev/null; then + print_success "frp 用户存在" + else + print_warning "frp 用户不存在" + fi + + # 检查安装包状态 + echo "" + print_info "安装包状态:" + if [[ -f "$frp_file" ]]; then + local size=$(du -h "$frp_file" 2>/dev/null | cut -f1) + print_info " FRP 压缩包: ${CYAN}已下载${NC} (${size})" + else + print_warning " FRP 压缩包: 未下载" + fi + + if [[ -f "$INSTALL_DIR/frpc.toml" ]]; then + print_info " 配置文件: ${CYAN}存在${NC}" + else + print_warning " 配置文件: 不存在" + fi + + print_info "============================================" + echo "" +} + +# 交互式服务管理菜单 +interactive_menu() { + while true; do + echo "" + echo "===============================================" + echo " FRP Client 服务管理 (${SERVICE_NAME})" + echo "===============================================" + echo "1. 启动服务 (start)" + echo "2. 停止服务 (stop)" + echo "3. 重启服务 (restart)" + echo "4. 查看状态 (status)" + echo "5. 查看日志 (logs)" + echo "6. 查看配置文件 (config)" + echo "7. 编辑配置文件 (edit)" + echo "8. 卸载服务 (uninstall)" + echo "0. 退出 (exit)" + echo "===============================================" + + read -p "请选择操作 [0-8]: " choice + + case $choice in + 1|start) + log_info "启动 ${SERVICE_NAME} 服务..." + systemctl start ${SERVICE_NAME} || true + if systemctl is-active --quiet ${SERVICE_NAME}; then + log_info "服务启动成功" + else + log_error "服务启动失败" + fi + systemctl status ${SERVICE_NAME} --no-pager || true + ;; + 2|stop) + log_info "停止 ${SERVICE_NAME} 服务..." + if systemctl stop ${SERVICE_NAME}; then + log_info "服务已停止" + else + log_error "服务停止失败" + fi + ;; + 3|restart) + log_info "重启 ${SERVICE_NAME} 服务..." + systemctl restart ${SERVICE_NAME} || true + if systemctl is-active --quiet ${SERVICE_NAME}; then + log_info "服务重启成功" + else + log_error "服务重启失败" + fi + systemctl status ${SERVICE_NAME} --no-pager || true + ;; + 4|status) + echo "服务状态:" + systemctl status ${SERVICE_NAME} --no-pager || true + ;; + 5|logs) + log_info "查看服务日志 (按 Ctrl+C 退出):" + sleep 1 + # 临时忽略 Ctrl+C,只结束 journalctl 而不退出脚本 + trap 'true' INT + journalctl -u ${SERVICE_NAME} -f || true + trap - INT + ;; + 6|config) + echo "配置文件内容:" + echo "----------------------------------------" + cat "$INSTALL_DIR/frpc.toml" || true + echo "----------------------------------------" + ;; + 7|edit) + print_info "编辑配置文件..." + edit_config + + read -p "是否重启服务使配置生效? [y/N]: " restart_choice + if [[ $restart_choice =~ ^[Yy]$ ]]; then + if systemctl restart ${SERVICE_NAME}; then + print_info "服务已重启" + else + log_error "服务重启失败,请检查日志: journalctl -u ${SERVICE_NAME} -f" + fi + fi + ;; + 8|uninstall) + if uninstall_frpc; then + exit 0 + fi + ;; + 0|exit|quit|q) + log_info "退出管理界面" + exit 0 + ;; + *) + log_error "无效选择,请输入 0-8 或对应命令" + ;; + esac + + read -p "按回车键继续..." + done +} + +# 主菜单 +show_main_menu() { + clear + echo -e "${CYAN}" + echo "============================================" + echo " FRP Client 自动安装/卸载脚本 (${SERVICE_NAME})" + echo "============================================" + echo -e "${NC}" + echo -e "${GREEN}1.${NC} 安装 FRP Client" + echo -e "${GREEN}2.${NC} 卸载 FRP Client" + echo -e "${GREEN}3.${NC} 检查状态" + echo -e "${GREEN}4.${NC} 下载安装包" + echo -e "${GREEN}5.${NC} 服务管理" + echo -e "${GREEN}0.${NC} 退出" + echo "" + echo -e "${CYAN}============================================${NC}" +} + +# 主函数 +main() { + check_root + + # 检查是否为管理模式 + if [[ "$1" == "manage" || "$1" == "menu" || "$1" == "-m" ]]; then + interactive_menu + return + fi + + # 如果没有参数,显示交互式主菜单 + if [[ $# -eq 0 ]]; then + while true; do + show_main_menu + read -p "请选择操作 [0-5]: " choice + + case $choice in + 1) + install_frpc + read -p "按任意键继续..." -n 1 + ;; + 2) + uninstall_frpc || true + read -p "按任意键继续..." -n 1 + ;; + 3) + check_status + read -p "按任意键继续..." -n 1 + ;; + 4) + print_info "开始下载安装包..." + if download_packages; then + print_success "下载完成!" + else + print_error "下载失败" + fi + read -p "按任意键继续..." -n 1 + ;; + 5) + interactive_menu + ;; + 0) + print_info "退出脚本" + exit 0 + ;; + *) + print_error "无效的选择,请重新输入" + sleep 2 + ;; + esac + done + else + # 兼容旧的直接安装模式(如果有参数的话) + print_info "开始安装 FRP Client..." + install_frpc + + echo "" + # 询问是否进入交互管理界面 + read -p "是否进入服务管理界面? [y/N]: " enter_menu + if [[ $enter_menu =~ ^[Yy]$ ]]; then + interactive_menu + else + echo "" + print_info "可使用以下命令:" + echo " $0 # 进入主菜单" + echo " $0 manage # 进入服务管理界面" + echo " systemctl [start|stop|restart|status] ${SERVICE_NAME}" + fi + fi +} + +# 运行主函数 +main "$@" \ No newline at end of file