#!/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 "$@"