├── Config ├── Docker │ ├── Installs │ │ ├── _action.sh │ │ ├── alist.sh │ │ ├── gitea.sh │ │ ├── nginx-proxy-manager.sh │ │ ├── safeline.sh │ │ ├── siyuan.sh │ │ ├── typecho.sh │ │ ├── vaultwarden.sh │ │ └── xboard.sh │ ├── _init.sh │ ├── image.sh │ ├── manage.sh │ └── source.sh ├── Manage │ ├── install.sh │ └── unInstall.sh ├── System │ ├── Basic │ │ ├── bbr_open.sh │ │ ├── info.sh │ │ ├── language.sh │ │ └── reinstall.sh │ └── User │ │ ├── _init.sh │ │ ├── account.sh │ │ ├── key.sh │ │ └── ssh.sh ├── Task │ ├── Installs │ │ ├── _action.sh │ │ ├── acme_update.sh │ │ ├── backup.sh │ │ ├── up-docker_compose.sh │ │ └── update.sh │ └── manage.sh ├── Web │ ├── acme │ │ ├── _init.sh │ │ ├── apply.sh │ │ └── manage.sh │ └── nginx │ │ ├── _init.sh │ │ ├── install.sh │ │ └── manage.sh ├── software.sh ├── sources.sh └── vpn.sh ├── README.md └── run.sh /Config/Docker/Installs/_action.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 接收参数 3 | local_path=$1 4 | selected_script=$2 5 | 6 | # 配置存储路径 7 | declare storage_path 8 | read -p "请输入软件存储位置,默认 /var/www/${selected_script} :" storage_path 9 | if [[ -z ${storage_path} ]]; then 10 | storage_path="/var/www/${selected_script}" 11 | fi 12 | 13 | # 检查并创建目录 14 | if [[ ! -d "$storage_path" ]]; then 15 | mkdir -p "$storage_path" || { 16 | echo "目录创建失败" 17 | exit 1 18 | } 19 | elif [[ ! -z "$(find "$storage_path" -mindepth 1 -print -quit)" ]]; then 20 | echo "该目录存有文件" 21 | read -p "是否继续?(y/n): " continue_choice 22 | if [[ ! $continue_choice =~ [Yy] ]]; then 23 | echo "安装已取消" 24 | exit 25 | fi 26 | fi 27 | 28 | # 生成随机端口 29 | declare random_port=$(($RANDOM % 9000 + 1000)) 30 | 31 | while ss -tuln | grep $random_port &>/dev/null; do 32 | random_port=$(($RANDOM % 9000 + 1000)) 33 | done 34 | 35 | # 配置访问端口 36 | declare access_port 37 | read -p "请输入访问端口,默认 $random_port :" access_port 38 | 39 | if [[ -z $access_port ]]; then 40 | access_port=$random_port 41 | fi 42 | 43 | # 检查端口是否被占用 44 | if ss -tuln | grep $access_port &>/dev/null; then 45 | echo "端口已被占用" 46 | read -p "是否使用其他端口?(y/n): " port_choice 47 | if [[ $port_choice =~ [Yy] ]]; then 48 | read -p "请输入新的端口: " access_port 49 | else 50 | echo "安装已取消" 51 | exit 52 | fi 53 | fi 54 | 55 | # 执行原始安装脚本 56 | bash "${local_path}/${selected_script}.sh" "$storage_path" "$access_port" 57 | echo "${selected_script} 安装完成,访问端口 ${access_port}" -------------------------------------------------------------------------------- /Config/Docker/Installs/alist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare install_path=$1 3 | declare service_port=$2 4 | cd $install_path 5 | cat > "docker-compose.yml" << EOF 6 | version: '3.8' 7 | services: 8 | alist: 9 | image: xhofe/alist:latest 10 | container_name: alist 11 | restart: always 12 | volumes: 13 | - ./:/opt/alist/data 14 | ports: 15 | - "${service_port}:5244" 16 | EOF 17 | docker compose up -d || echo "安装失败" && exit 18 | declare admin_password=$( docker exec -it alist ./alist admin random | grep password | awk '{print $4}') 19 | echo "账号:admin" 20 | echo "密码:${admin_password}" 21 | -------------------------------------------------------------------------------- /Config/Docker/Installs/gitea.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | declare install_path=$1 4 | declare service_port=$2 5 | 6 | useradd -m git 7 | 8 | su - git -c "ssh-keygen -t rsa -b 4096 -C \"Gitea Host Key\" -f /home/git/.ssh/id_rsa -N \"\"" 9 | su - git -c "cat /home/git/.ssh/id_rsa.pub >> /home/git/.ssh/authorized_keys" 10 | echo "ssh -p $(( service_port+22 )) -o StrictHostKeyChecking=no git@127.0.0.1 \"SSH_ORIGINAL_COMMAND=\\\"\$SSH_ORIGINAL_COMMAND\\\" \$0 \$@\"" > /usr/local/bin/gitea 11 | chown git:git /usr/local/bin/gitea 12 | su - git -c "chmod a+x /usr/local/bin/gitea" 13 | 14 | declare user_id=$( id git | awk -F'[=() ]+' '{print $2}' ) 15 | declare group_id=$( id git | awk -F'[=() ]+' '{print $5}' ) 16 | 17 | cd $install_path 18 | cat > "docker-compose.yml" << EOF 19 | networks: 20 | gitea: 21 | external: false 22 | services: 23 | server: 24 | image: gitea/gitea:latest 25 | container_name: gitea 26 | environment: 27 | - USER_UID=${user_id} 28 | - USER_GID=${group_id} 29 | - GITEA__database__DB_TYPE=mysql 30 | - GITEA__database__HOST=db:3306 31 | - GITEA__database__NAME=gitea 32 | - GITEA__database__USER=gitea 33 | - GITEA__database__PASSWD=gitea 34 | restart: always 35 | networks: 36 | - gitea 37 | volumes: 38 | - ./data:/data 39 | - /etc/timezone:/etc/timezone:ro 40 | - /etc/localtime:/etc/localtime:ro 41 | - /home/git/.ssh/:/data/git/.ssh 42 | ports: 43 | - "${service_port}:3000" 44 | - "$(( service_port+22 )):22" 45 | depends_on: 46 | - db 47 | db: 48 | image: mysql:8 49 | restart: always 50 | environment: 51 | - MYSQL_ROOT_PASSWORD=gitea 52 | - MYSQL_USER=gitea 53 | - MYSQL_PASSWORD=gitea 54 | - MYSQL_DATABASE=gitea 55 | networks: 56 | - gitea 57 | volumes: 58 | - ./mysql:/var/lib/mysql 59 | EOF 60 | chown -R git:git $install_path 61 | docker compose up -d -------------------------------------------------------------------------------- /Config/Docker/Installs/nginx-proxy-manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare install_path=$1 3 | declare service_port=$2 4 | 5 | cd $install_path 6 | cat > docker-compose.yml << EOF 7 | services: 8 | app: 9 | image: 'jc21/nginx-proxy-manager:latest' 10 | restart: unless-stopped 11 | ports: 12 | - '80:80' 13 | - '443:443' 14 | - '${service_port}:81' 15 | volumes: 16 | - ./data:/data 17 | - ./letsencrypt:/etc/letsencrypt 18 | EOF 19 | docker compose up -d 20 | echo "Email: admin@example.com" 21 | echo "Password: changeme" 22 | -------------------------------------------------------------------------------- /Config/Docker/Installs/safeline.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare installation_directory=$1 3 | declare management_port=$2 4 | cd $installation_directory 5 | wget "https://waf-ce.chaitin.cn/release/latest/compose.yaml" 6 | 7 | cat > ".env" << EOF 8 | SAFELINE_DIR=$installation_directory 9 | IMAGE_TAG=latest 10 | MGT_PORT=$management_port 11 | POSTGRES_PASSWORD="safeline" 12 | SUBNET_PREFIX=172.22.222 13 | IMAGE_PREFIX=swr.cn-east-3.myhuaweicloud.com/chaitin-safeline 14 | EOF 15 | docker compose up -d || echo "安装失败" && exit 16 | declare admin_password=$( docker exec safeline-mgt resetadmin &> /dev/null | grep password | awk -F ":" '{print $2}' ) 17 | echo "账号:admin" 18 | echo "密码:${admin_password}" 19 | -------------------------------------------------------------------------------- /Config/Docker/Installs/siyuan.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare installation_directory=$1 3 | declare web_service_port=$2 4 | declare access_password 5 | read -p "请输入思源访问密码(默认:Siyuan):" access_password 6 | 7 | if [[ -z $access_password ]];then 8 | access_password="Siyuan" 9 | fi 10 | 11 | chown -R 1000:1000 $installation_directory 12 | cd $installation_directory 13 | cat > "docker-compose.yml" << EOF 14 | version: "3.9" 15 | services: 16 | siyuan: 17 | image: b3log/siyuan 18 | container_name: siyuan 19 | user: '1000:1000' 20 | restart: always 21 | ports: 22 | - $web_service_port:6806 23 | volumes: 24 | - ./:/siyuan/workspace 25 | command: 26 | - "--workspace=/siyuan/workspace/" 27 | - "--lang=zh_CN" 28 | - "--accessAuthCode=$access_password" 29 | EOF 30 | docker compose up -d || echo "安装失败" && exit 31 | echo "访问密码:$access_password" 32 | -------------------------------------------------------------------------------- /Config/Docker/Installs/typecho.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare installation_directory=$1 3 | declare web_service_port=$2 4 | 5 | if ! command -v zip &> /dev/null; then 6 | echo "zip 未安装" 7 | exit 1 8 | fi 9 | 10 | 11 | cd $installation_directory 12 | 13 | mkdir data 14 | mkdir php 15 | mkdir -p nginx/conf 16 | 17 | cat > "./php/Dockerfile" << 'EOF' 18 | FROM php:8.2-fpm 19 | 20 | # 更新包列表并安装 pdo_mysql 扩展 21 | RUN apt-get update && \ 22 | apt-get install -y libpq-dev && \ 23 | docker-php-ext-install pdo_mysql && \ 24 | rm -rf /var/lib/apt/lists/* 25 | 26 | # 设置 PHP 配置 27 | RUN { \ 28 | echo "output_buffering = 4096"; \ 29 | echo "date.timezone = PRC"; \ 30 | } > /usr/local/etc/php/conf.d/custom.ini 31 | EOF 32 | 33 | cat > "./nginx/conf/default.conf" << 'EOF' 34 | server { 35 | listen 80 default_server; # 监听 80 端口 36 | root /var/www/html; # 网站根目录 37 | index index.php index.html index.htm; 38 | 39 | access_log /var/log/nginx/typecho_access.log main; # 访问日志 40 | if (!-e $request_filename) { 41 | rewrite ^(.*)$ /index.php$1 last; # 重写 URL 到 index.php 42 | } 43 | 44 | location / { 45 | if (!-e $request_filename) { 46 | rewrite . /index.php last; # 如果文件不存在,重写到 index.php 47 | } 48 | } 49 | 50 | location ~ \.php(.*)$ { 51 | fastcgi_pass php:9000; # 转发 PHP 请求到 php-fpm 服务 52 | fastcgi_index index.php; 53 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # 设置脚本文件名参数 54 | include fastcgi_params; # 包含 fastcgi 参数 55 | } 56 | } 57 | EOF 58 | 59 | cat > docker-compose.yml << EOF 60 | services: # 定义多个服务 61 | 62 | nginx: # 服务名称 63 | image: nginx # 使用的镜像 64 | ports: # 映射的端口 65 | - "${web_service_port}:80" # 宿主机端口 ${web_service_port} 映射到容器端口 80 66 | restart: always # 容器重启策略 67 | volumes: # 映射文件 68 | - ./data:/var/www/html # 网站源代码 69 | - ./nginx/conf:/etc/nginx/conf.d # nginx 站点配置文件 70 | - ./nginx/logs:/var/log/nginx # nginx 日志文件 71 | depends_on: # 定义依赖关系 72 | - php # 依赖 php 服务 73 | networks: # 要加入的网络 74 | - typecho # 加入 typecho 网络 75 | 76 | php: # 服务名称 77 | build: ./php # 构建文件的目录 78 | restart: always # 容器重启策略 79 | volumes: # 映射文件 80 | - ./data:/var/www/html # 网站源代码 81 | depends_on: # 定义依赖关系 82 | - mysql # 依赖 mysql 服务 83 | networks: # 要加入的网络 84 | - typecho # 加入 typecho 网络 85 | 86 | mysql: # 服务名称 87 | image: mysql:5.7 # 指定 5.7 版本的 mysql 镜像 88 | restart: always # 容器重启策略 89 | volumes: # 要映射的文件 90 | - ./mysql/data:/var/lib/mysql # mysql 数据 91 | - ./mysql/logs:/var/log/mysql # mysql 日志 92 | - ./mysql/conf:/etc/mysql/conf.d # mysql 配置文件 93 | environment: # 环境变量 94 | MYSQL_ROOT_PASSWORD: typecho # MySQL root 用户的密码 95 | MYSQL_DATABASE: typecho # 创建的数据库名称 96 | networks: # 要加入的网络 97 | - typecho # 加入 typecho 网络 98 | 99 | networks: # 定义的内部网络 100 | typecho: # 网络名称 101 | 102 | EOF 103 | 104 | cd data 105 | wget https://github.com/typecho/typecho/releases/latest/download/typecho.zip -O typecho.zip 106 | unzip typecho.zip 107 | rm typecho.zip 108 | 109 | cd $installation_directory 110 | 111 | chown -R 1000:1000 $installation_directory 112 | 113 | chmod -R 777 data 114 | 115 | docker compose up -d 116 | 117 | echo "数据库地址:mysql" 118 | echo "数据库用户名:root" 119 | echo "数据库密码:typecho" 120 | echo "数据库名:typecho" 121 | 122 | echo "安装完成,请在${installation_directory}/data/config.inc.php末尾添加,防止排版错误" 123 | echo "define('__TYPECHO_SECURE__',true);" 124 | 125 | -------------------------------------------------------------------------------- /Config/Docker/Installs/vaultwarden.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare installation_directory=$1 3 | declare web_service_port=$2 4 | 5 | declare admin_password 6 | read -p "请输入管理员密码(不输入则关闭管理员功能):" admin_password 7 | 8 | cd $installation_directory 9 | cat > "docker-compose.yml" << EOF 10 | version: '3.8' 11 | services: 12 | bitwarden: 13 | image: vaultwarden/server:latest 14 | container_name: vaultwarden 15 | restart: always 16 | environment: 17 | - SIGNUPS_ALLOWED=true 18 | - WEBSOCKET_ENABLED=true 19 | - TZ=Asia/Shanghai 20 | - ADMIN_TOKEN="$admin_password" 21 | volumes: 22 | - ./:/data/ 23 | ports: 24 | - "${web_service_port}:80" 25 | EOF 26 | 27 | if [[ -z $admin_password ]];then 28 | sed -i '/.*ADMIN_TOKEN=.*/d' "docker-compose.yml" 29 | fi 30 | 31 | mkdir templates 32 | cd templates 33 | wget https://github.com/wcjxixi/vaultwarden-lang-zhcn/archive/refs/heads/main.zip 34 | unzip main.zip 35 | rm main.zip 36 | cd vaultwarden-lang-zhcn-main 37 | declare admin_file=$( ls | grep "admin" | tac | head -n 1 ) 38 | declare email_file=$( ls | grep "email" | tac | head -n 1 ) 39 | mv "$admin_file" "../admin" 40 | mv "$email_file" "../email" 41 | cd .. 42 | rm -rf vaultwarden-lang-zhcn-main 43 | docker compose up -d || echo "安装失败" && exit 44 | echo "需要反向代理,使用HTTPS才能正常使用" 45 | -------------------------------------------------------------------------------- /Config/Docker/Installs/xboard.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare install_path=$1 3 | declare service_port=$2 4 | cd $install_path 5 | 6 | declare project_name=$(basename $install_path) 7 | cd .. 8 | rm -rf "$project_name" 9 | 10 | git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard 11 | 12 | if [[ "$project_name" != Xboard ]];then 13 | mv Xboard "$project_name" 14 | fi 15 | 16 | cd "$install_path" 17 | 18 | docker compose run -it --rm xboard php artisan xboard:install 19 | 20 | docker compose up -d > /dev/null 21 | 22 | sleep 5 23 | echo "网站端口默认7001,记得防火墙放行" -------------------------------------------------------------------------------- /Config/Docker/_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if ! command -v docker &> /dev/null; then 3 | echo "Docker 未安装" 4 | exit 1 5 | fi -------------------------------------------------------------------------------- /Config/Docker/image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "1. 查看当前运行中的镜像" 3 | echo "2. 停止镜像" 4 | echo "3. 删除未使用的镜像" 5 | 6 | declare user_choice 7 | read -p "请输入选项:" user_choice 8 | 9 | case $user_choice in 10 | '1') 11 | docker ps --format "{{.Names}}" 12 | ;; 13 | '2') 14 | declare -a running_images=($(docker ps --format "{{.Names}}")) 15 | declare image_count=0 16 | for image in "${running_images[@]}" ; do 17 | image_count=$(( image_count+1 )) 18 | echo "${image_count}.${image}" 19 | done 20 | echo "要停止的镜像序号,多个镜像用空格隔开" 21 | read -p "请输入:" user_choice 22 | for i in $user_choice ; do 23 | if [[ $i =~ [1-$image_count] ]]; then 24 | echo "正在停止 ${running_images[$(( i -1 ))]}" 25 | docker stop "${running_images[$(( i -1 ))]}" 26 | echo "${running_images[$(( i -1 ))]} 已经停止" 27 | fi 28 | done 29 | ;; 30 | '3') 31 | docker system prune -af 32 | echo "清理完成" 33 | esac -------------------------------------------------------------------------------- /Config/Docker/manage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "1. 查看已安装的站点" 3 | echo "2. 删除软件" 4 | 5 | declare user_choice 6 | read -p "请输入:" user_choice 7 | 8 | declare site_path="/var/www" 9 | echo "请输入站点安装地址,默认 ${site_path}" 10 | read -p "请输入:" site_path 11 | 12 | if [[ -z $site_path ]]; then 13 | site_path="/var/www" 14 | elif ! [[ -d $site_path ]]; then 15 | echo "该地址不存在目录" 16 | exit 1 17 | fi 18 | 19 | function list_sites() { 20 | local site_number=0 21 | for site in "$site_path"/* ; do 22 | if [[ ! -d $site ]]; then 23 | echo "该地址不存在站点" 24 | return 25 | fi 26 | site_number=$(( site_number + 1 )) 27 | site_name=$(awk -F '.' '{print $1}' <<< "$(basename "$site")") 28 | echo "${site_number}.${site_name}" 29 | site_array[$site_number]=$site_name 30 | done 31 | } 32 | 33 | case $user_choice in 34 | '1') 35 | list_sites 36 | ;; 37 | '2') 38 | declare -a site_array 39 | list_sites 40 | read -p "请输入要删除的序号,多个用空格隔开:" selected_sites 41 | for i in $selected_sites ; do 42 | if [[ $i =~ ^[1-9][0-9]*$ ]] && [ "$i" -le "${#site_array[@]}" ]; then 43 | echo "开始删除 ${site_array[$i]}" 44 | cd "$site_path/${site_array[$i]}" || exit 45 | docker compose down &> /dev/null && echo "站点已停止运行" 46 | rm -rf "$site_path/${site_array[$i]}" &> /dev/null 47 | echo "删除完成" 48 | fi 49 | done 50 | echo "全部删除完成" 51 | ;; 52 | esac -------------------------------------------------------------------------------- /Config/Docker/source.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "========$(basename $0 .sh)========" 3 | echo "1. 查看当前源" 4 | echo "2. 换源" 5 | declare user_choice 6 | read -p "请输入:" user_choice 7 | 8 | case $user_choice in 9 | '1') 10 | grep -oP '(https?://[^\"]+)' /etc/docker/daemon.json 11 | ;; 12 | '2') 13 | declare -A mirror_options 14 | declare -a mirror_list 15 | declare mirror_choice=0 16 | mirror_options['Daocloud(默认)']='https://docker.m.daocloud.io' 17 | mirror_options['官方']='docker.io' 18 | 19 | for mirror in "${!mirror_options[@]}"; 20 | do 21 | mirror_choice=$(( mirror_choice+1 )) 22 | mirror_list[$mirror_choice]=$mirror 23 | echo "${mirror_choice}.${mirror}" 24 | done 25 | read -p "请输入要选择的镜像,也可直接输入镜像网站:" selected_mirror 26 | if [[ -z $selected_mirror ]];then 27 | declare url='https://docker.m.daocloud.io' 28 | elif [[ $selected_mirror =~ [\w\.]+ ]];then 29 | declare url=$selected_mirror 30 | elif [[ ${selected_mirror} =~ [1-${!mirror_options[*]}] ]];then 31 | selected_mirror=${mirror_list[$selected_mirror]} 32 | declare url=${mirror_options[$selected_mirror]} 33 | else 34 | echo "输入错误" 35 | exit 36 | fi 37 | echo "正在写入配置文件" 38 | echo "{\"registry-mirrors\": [\"${url}\"]}" > "/etc/docker/daemon.json" 39 | echo "正在重启 Docker" 40 | systemctl restart docker 2>> /dev/null || echo "Docker 重启失败"&&exit 41 | echo "换源成功" 42 | 43 | ;; 44 | esac -------------------------------------------------------------------------------- /Config/Manage/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ $UID != 0 ]]; then 3 | echo "请以root权限执行该脚本" 4 | exit 5 | fi 6 | 7 | if ! command -v git &>/dev/null; then 8 | if [[ -f "/usr/bin/apt-get" ]]; then 9 | apt-get update -y 10 | apt-get install git -y 11 | elif [[ -f "/usr/bin/apt" ]]; then 12 | apt update -y 13 | apt install git -y 14 | elif [[ -f "/usr/bin/pacman" ]]; then 15 | pacman -Syu --noconfirm 16 | pacman -Sy --noconfirm git 17 | else 18 | echo "git未安装" 19 | exit 20 | fi 21 | fi 22 | 23 | declare path 24 | echo "请输入脚本的安装位置" 25 | read -p "默认 /var/script:" path 26 | if [[ -z $path ]]; then 27 | path="/var/script" 28 | fi 29 | 30 | mkdir -p "$path" 31 | rm -rf "$path/linuxtool" 32 | 33 | declare -A url_dick 34 | declare -a url_arr 35 | declare url_number=0 36 | declare url_pick 37 | declare url 38 | echo "请选择脚本的下载地址" 39 | url_dick['github(default)']='https://github.com/lsy2246/linuxtool.git' 40 | url_dick['gitee']='https://gitee.com/lsy22/linuxtool.git' 41 | 42 | for i in "${!url_dick[@]}"; do 43 | url_number=$((url_number + 1)) 44 | url_arr[$url_number]=$i 45 | echo "${url_number}.${i}" 46 | done 47 | 48 | read -p "请输入:" url_pick 49 | 50 | if [[ $url_pick =~ [1-${#url_dick[@]}] ]]; then 51 | url=${url_dick[${url_arr[$url_pick]}]} 52 | else 53 | url='https://github.com/lsy2246/linuxtool.git' 54 | fi 55 | 56 | echo "正在下载脚本中" 57 | git clone "$url" "$path/linuxtool" &>/dev/null 58 | 59 | if ! [[ -d "${path}/linuxtool" ]]; then 60 | echo "脚本下载失败" 61 | exit 62 | fi 63 | 64 | chmod +x "$path/linuxtool/run.sh" &>/dev/null 65 | 66 | # 创建软链接到 /usr/bin 目录 67 | echo "正在创建软链接..." 68 | ln -sf "$path/linuxtool/run.sh" "/usr/bin/tool" 69 | chmod +x "/usr/bin/tool" 70 | 71 | # 将工具路径写入环境变量配置 72 | echo "tool='$path/linuxtool/run.sh'" >>/etc/profile 73 | 74 | echo "工具箱已经安装成功" 75 | echo "位置:${path}/linuxtool" 76 | echo "命令:tool" 77 | 78 | if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then 79 | kill $PPID &>/dev/null 80 | fi 81 | -------------------------------------------------------------------------------- /Config/Manage/unInstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare tool_path=$(cat /etc/profile | grep "tool=" | awk -F "=" '{print $2}' | tr -d "'") 3 | tool_path=$(dirname $tool_path) 4 | rm -rf $tool_path 5 | 6 | # 删除软链接 7 | if [[ -L "/usr/bin/tool" ]]; then 8 | rm -f "/usr/bin/tool" 9 | fi 10 | 11 | # 从环境变量配置中删除工具路径 12 | sed -i '/tool=.*/d' /etc/profile 13 | 14 | echo "脚本已完整卸载,公众号 lsy22 可获取一键安装脚本" 15 | kill $PPID &>/dev/null 16 | -------------------------------------------------------------------------------- /Config/System/Basic/bbr_open.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare kernel_version=$(uname -r | awk -F "." '{print $1}') 3 | if ! [[ $kernel_version -ge 5 ]];then 4 | echo "系统内核版本过低" 5 | exit 6 | fi 7 | grep -q "net.core.default_qdisc=fq" "/etc/sysctl.conf" || echo 'net.core.default_qdisc=fq' | tee -a "/etc/sysctl.conf" 8 | grep -q "net.ipv4.tcp_congestion_control=bbr" "/etc/sysctl.conf" || echo 'net.ipv4.tcp_congestion_control=bbr' | tee -a "/etc/sysctl.conf" 9 | sysctl -p || echo "BBR 开启失败" 10 | sysctl net.ipv4.tcp_available_congestion_control | grep bbr && echo "BBR 开启成功" -------------------------------------------------------------------------------- /Config/System/Basic/info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare -A info_dict 3 | declare -a info_array 4 | 5 | cpu_info=$(cat /proc/cpuinfo) 6 | info_dict["CPU 型号"]=$(echo "$cpu_info" | grep -m1 -oP 'model name\s*:\s*\K.+') 7 | info_dict["CPU 核心数"]=$(echo "$cpu_info" | grep -m1 -oP 'cpu cores\s*:\s*\K\d+') 8 | info_dict["CPU 频率"]=$(echo "$cpu_info" | grep -m1 -oP 'cpu MHz\s*:\s*\K.+') 9 | info_dict["CPU 缓存"]=$(echo "$cpu_info" | grep -m1 -oP 'cache size\s*:\s*\K.+') 10 | 11 | info_dict["SWAP"]=$(free -m | awk '/Swap/ {printf "%.2f GB", $2/1024}') 12 | info_dict["硬盘空间"]=$(lsblk -b -d -o SIZE,NAME | grep -vE "loop|ram" | awk '{sum += $1} END {printf "%.2f GB", sum/1024/1024/1024}') 13 | info_dict["系统在线时间"]=$(awk '{printf("%d天 %d小时 %d分钟", $1/86400, ($1%86400)/3600, ($1%3600)/60)}' /proc/uptime) 14 | info_dict["内核"]=$(uname -r) 15 | info_dict["TCP加速方式"]=$(sysctl -n net.ipv4.tcp_congestion_control) 16 | info_dict["虚拟化框架"]=$(systemd-detect-virt) 17 | 18 | ip_info=$(curl -s https://ip.lsy22.com/) 19 | info_dict["IPV4 位置"]=$(echo "$ip_info" | grep -oP '"ipv4":\s*"\K[^"]+') 20 | info_dict["IPV6 位置"]=$(echo "$ip_info" | grep -oP '"ipv6":\s*"\K[^"]+') 21 | 22 | info_array=( 23 | "CPU 型号" "CPU 核心数" "CPU 频率" "CPU 缓存" 24 | "SWAP" "硬盘空间" "系统在线时间" "内核" "TCP加速方式" 25 | "虚拟化框架" "IPV4 位置" "IPV6 位置" 26 | ) 27 | 28 | max_length=$(printf "%s\n" "${info_array[@]}" | awk '{print length}' | sort -nr | head -1) 29 | 30 | for title in "${info_array[@]}"; do 31 | printf "%-${max_length}s : %s\n" "$title" "${info_dict[$title]}" 32 | done 33 | 34 | echo -e "\n待办项目:" 35 | echo "CPU 测试中" 36 | echo "内存测试中" 37 | echo "IPV4测试中" 38 | echo "IPV6测试中" 39 | echo "速度测试中" -------------------------------------------------------------------------------- /Config/System/Basic/language.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare language_choice 3 | echo "========$(basename $0 .sh)========" 4 | echo "1. 中文" 5 | echo "2. 英文" 6 | read -p "请输入:" language_choice 7 | if [[ -f "/usr/bin/apt-get" ]];then 8 | apt-get update -y 9 | apt-get install -y locales 10 | apt-get install -y language-pack-zh-hans 11 | elif [[ -f "/usr/bin/apt" ]];then 12 | apt update -y 13 | apt install -y locales 14 | apt install -y language-pack-zh-hans 15 | else 16 | echo "暂不支持该系统一键更换语言" 17 | exit 18 | fi 19 | echo "正在更新配置文件" 20 | sed -i '/^#/! s/^/# /' /etc/locale.gen 21 | if ! grep LC_ALL /etc/default/locale &> /dev/null; then 22 | echo "LC_ALL=en_US.UTF-8" >> /etc/default/locale 23 | fi 24 | case $language_choice in 25 | '1') 26 | sed -i 's/.*zh_CN.UTF-8.*/zh_CN.UTF-8 UTF-8/g' /etc/locale.gen 27 | sed -i "s/^LANG.*/LANG=zh_CN.UTF-8/g" /etc/default/locale 28 | sed -i "s/^LC_ALL.*/LC_ALL=zh_CN.UTF-8/g" /etc/default/locale 29 | ;; 30 | '2') 31 | sed -i 's/.*en_US.UTF-8.*/en_US.UTF-8 UTF-8/g' /etc/locale.gen 32 | sed -i "s/^LANG.*/LANG=en_US.UTF-8/g" /etc/default/locale 33 | sed -i "s/^LC_ALL.*/LC_ALL=en_US.UTF-8/g" /etc/default/locale 34 | ;; 35 | esac 36 | locale-gen 37 | update-locale 38 | source /etc/default/locale 39 | echo "语言更换成功" -------------------------------------------------------------------------------- /Config/System/Basic/reinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare server_choice 3 | declare download_server 4 | echo "========$(basename $0 .sh)========" 5 | echo "请选择下载服务器" 6 | echo "1. 国内服务器" 7 | echo "2. 国外服务器(默认)" 8 | read -p "请输入:" server_choice 9 | if [[ $server_choice == '1' ]];then 10 | download_server="https://jihulab.com/bin456789/reinstall/-/raw/main/reinstall.sh" 11 | else 12 | download_server="https://raw.githubusercontent.com/bin456789/reinstall/main/reinstall.sh" 13 | fi 14 | 15 | declare -A image_options 16 | declare -a image_list 17 | declare image_count=0 18 | image_options['arch']="" 19 | image_options['kali']="" 20 | image_options['debian']="8 9 10 11 12" 21 | image_options['Ubuntu']="16.04 18.04 20.04 22.04 24.04" 22 | 23 | for image in "${!image_options[@]}" ; do 24 | image_count=$(( image_count+1 )) 25 | image_list[$image_count]=$image 26 | echo "${image_count}.${image}" 27 | done 28 | 29 | read -p "请选择需要安装的镜像序号:" selected_image 30 | 31 | if [[ $selected_image =~ [1-"${#image_options[@]}"\ ] ]];then 32 | declare selected_image_name=${image_list[$selected_image]} 33 | declare selected_version='' 34 | declare -a version_list 35 | declare version_count=0 36 | if [[ ! -z ${image_options[$selected_image_name]} ]];then 37 | echo "请输入要安装的版本(默认最新)" 38 | for version in ${image_options[$selected_image_name]} ; do 39 | version_count=$(( version_count+1 )) 40 | version_list[$version_count]=$version 41 | echo "${version_count}.${version}" 42 | done 43 | read -p "请输入:" selected_version 44 | if [ -z $selected_version ]; then 45 | selected_version=${version_list[$version_count]} 46 | elif [[ $selected_version =~ [1-$version_count] ]];then 47 | selected_version=${version_list[$selected_version]} 48 | fi 49 | fi 50 | eval "bash <(curl -Ls ${download_server}) ${selected_image_name} ${selected_version}" 51 | echo "重启后开始重装系统" 52 | echo "用服务器厂家的 VNC 连接可以看到重装进度" 53 | else 54 | echo "选择错误" 55 | fi -------------------------------------------------------------------------------- /Config/System/User/_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if ! command -v ssh &> /dev/null; then 3 | echo "SSH 客户端未安装" 4 | exit 5 | fi 6 | -------------------------------------------------------------------------------- /Config/System/User/account.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | declare user_choice 4 | echo "========$(basename $0 .sh)========" 5 | echo "1. 新建用户" 6 | echo "2. 查看所有用户" 7 | echo "3. 删除用户" 8 | echo "4. 修改用户密码" 9 | echo "任意输入返回主菜单" 10 | read -p "请输入要使用的功能:" user_choice 11 | 12 | case $user_choice in 13 | '1') 14 | declare new_user_name 15 | read -p "请输入要创建的用户名:" new_user_name 16 | 17 | if id "$new_user_name" &>/dev/null; then 18 | echo "用户 $new_user_name 已存在。" 19 | exit 1 20 | fi 21 | 22 | useradd -m -s /bin/bash "$new_user_name" 23 | 24 | if grep -q "^$new_user_name " /etc/sudoers;then 25 | sed -i "s/^#\?$new_user_name.*/$new_user_name ALL=(ALL) NOPASSWD: ALL/g" /etc/sudoers 26 | else 27 | echo "$new_user_name ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers 28 | fi 29 | 30 | declare login_method_choice 31 | echo "用户登录方式" 32 | echo "y. 密码登录" 33 | echo "n. 使用 root 用户公钥" 34 | read -p "默认 y,请输入:" login_method_choice 35 | if [[ ! $login_method_choice =~ [Nn] ]];then 36 | declare user_password 37 | read -p "请输入密码:" user_password 38 | echo "$new_user_name:$user_password" |chpasswd 39 | sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; 40 | echo "创建成功" 41 | echo "账号:$new_user_name" 42 | echo "密码:$user_password" 43 | else 44 | sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/g' /etc/ssh/sshd_config 45 | su "$new_user_name" -c "mkdir -p '/home/$new_user_name/.ssh'" 46 | cp "/root/.ssh/authorized_keys" "/home/$new_user_name/.ssh/authorized_keys" 47 | chown "$new_user_name:$new_user_name" "/home/$new_user_name/.ssh/authorized_keys" 48 | su "$new_user_name" -c "chmod 600 '/home/$new_user_name/.ssh/authorized_keys'" 49 | su "$new_user_name" -c "chmod 700 '/home/$new_user_name/.ssh/'" 50 | 51 | echo "创建成功" 52 | echo "账号:$new_user_name" 53 | echo "密钥登录" 54 | fi 55 | 56 | declare root_login_choice 57 | echo "是否关闭 root 用户登录" 58 | read -p "输入 n 取消关闭:" root_login_choice 59 | 60 | if [[ ! $root_login_choice =~ [Nn] ]];then 61 | sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/g' /etc/ssh/sshd_config 62 | echo "root 用户登录已关闭" 63 | fi 64 | 65 | systemctl restart sshd.service 66 | ;; 67 | '2') 68 | echo "当前系统有以下用户" 69 | cut -d: -f1 /etc/passwd 70 | ;; 71 | '3') 72 | declare user_to_delete 73 | read -p "请输入需要删除的用户名:" user_to_delete 74 | if ! id $user_to_delete &> /dev/null ;then 75 | echo "系统内没有该用户" 76 | exit 77 | fi 78 | sed -i "/^#\?$user_to_delete.*/d" /etc/sudoers &> /dev/null 79 | pkill -u $user_to_delete 80 | userdel -r $user_to_delete &> /dev/null 81 | rm -rf "/home/${user_to_delete}" 82 | echo "用户删除成功" 83 | ;; 84 | '4') 85 | declare new_password 86 | declare user_name 87 | read -p "请输入需要修改密码的用户名:" user_name 88 | if ! id $user_name &> /dev/null;then 89 | echo "系统内没有该用户" 90 | exit 91 | fi 92 | read -p "请输入${user_name}的新密码:" new_password 93 | echo "${user_name}:${new_password}" |chpasswd 94 | if [[ ${user_name} == "root" ]]; then 95 | sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config 96 | fi 97 | sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config 98 | systemctl restart sshd.service 99 | echo "修改成功, 用户 ${user_name} 的新密码为:${new_password}" 100 | ;; 101 | esac -------------------------------------------------------------------------------- /Config/System/User/key.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "========$(basename $0 .sh)========" 3 | echo "1. 生成密钥" 4 | echo "2. 安装密钥" 5 | echo "输入其他字符返回主页" 6 | declare user_choice 7 | read -p "请输入要选择的命令:" user_choice 8 | 9 | function configure_key() { 10 | chmod 600 "$HOME/.ssh/authorized_keys" 11 | chmod 700 "$HOME/.ssh" 12 | 13 | sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/g' /etc/ssh/sshd_config 14 | 15 | declare user_input 16 | echo "是否关闭密码登录:" 17 | read -p "输入 n 取消关闭:" user_input 18 | 19 | if [[ ! $user_input =~ [Nn] ]];then 20 | sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/g' /etc/ssh/sshd_config 21 | fi 22 | 23 | systemctl restart sshd.service 24 | 25 | echo "密钥安装完成" 26 | } 27 | 28 | case $user_choice in 29 | '1') 30 | declare key_directory="${HOME}/.ssh" 31 | read -p "请输入密钥安装位置, 默认:${key_directory}:" user_input 32 | 33 | if [[ -d $user_input ]]; then 34 | key_directory=$user_input 35 | elif [[ ! -z $user_input ]];then 36 | echo "该路径没有文件夹" 37 | exit 38 | fi 39 | 40 | declare key_size="" 41 | declare key_type="" 42 | declare passphrase="" 43 | declare -A key_options 44 | key_options['rsa']="2048 4096" 45 | key_options['ed25519']="" 46 | 47 | declare option_count=0 48 | declare -a option_array 49 | for i in "${!key_options[@]}" ; do 50 | option_count=$(( option_count+1 )) 51 | option_array[$option_count]=$i 52 | echo "${option_count}.${i}" 53 | done 54 | read -p "请选择要生成的密钥类型:" user_input 55 | if ! [[ $user_input =~ [1-${#key_options[@]}] ]]; then 56 | echo "选择错误" 57 | exit 58 | fi 59 | key_type=${option_array[$user_input]} 60 | 61 | if [ ! -z "${key_options[$key_type]}" ]; then 62 | option_count=0 63 | echo "请选择密钥位大小" 64 | for i in ${key_options[$key_type]} ; do 65 | option_count=$(( option_count+1 )) 66 | option_array[$option_count]=$i 67 | echo "${option_count}.${i}" 68 | done 69 | read -p "请选择:" user_input 70 | if ! [[ $user_input =~ [1-${#option_array[@]}] ]]; then 71 | echo "选择错误" 72 | exit 73 | fi 74 | key_size="-b ${option_array[$user_input]}" 75 | fi 76 | 77 | read -p "是否开启密钥短语,输入y开启,请输入:" user_input 78 | if [[ $user_input =~ [Yy] ]]; then 79 | read -p "请输入要设置的密钥短语:" passphrase 80 | fi 81 | eval "ssh-keygen -t ${key_type} ${key_size} -N '${passphrase}' -f '${key_directory}/key' -q" 82 | echo "密钥安装成功" 83 | echo "私钥:${key_directory}/key" 84 | echo "公钥:${key_directory}/key.pub" 85 | read -p "是否开启密钥登录,输入n取消:" user_input 86 | if ! [[ $user_input =~ [Nn] ]]; then 87 | mkdir -p "$HOME/.ssh" 88 | echo "${key_directory}/key.pub" > "$HOME/.ssh/authorized_keys" 89 | configure_key 90 | fi 91 | ;; 92 | '2') 93 | declare public_key 94 | echo "请输入公钥或文件路径:" 95 | echo "默认:$HOME/.ssh/id_rsa.pub" 96 | read -p "回车默认:" public_key 97 | 98 | if [[ -z $public_key ]];then 99 | public_key="$HOME/.ssh/id_rsa.pub" 100 | fi 101 | 102 | if [[ -f $public_key ]];then 103 | public_key=$(cat "$public_key") 104 | fi 105 | if [[ ! $public_key =~ ^ssh-(rsa|ecdsa-sha2-nistp[0-9]+|ed25519|dss) ]];then 106 | echo "公钥不合法" 107 | exit 1 108 | fi 109 | 110 | mkdir -p "$HOME/.ssh" 111 | echo "$public_key" > "$HOME/.ssh/authorized_keys" 112 | configure_key 113 | esac 114 | 115 | -------------------------------------------------------------------------------- /Config/System/User/ssh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare user_choice 3 | echo "========$(basename $0 .sh)========" 4 | echo "1. 更换 SSH 端口" 5 | echo "2. 修改 SSH 登录方式" 6 | echo "任意输入返回主菜单" 7 | read -p "请输入要使用的功能:" user_choice 8 | 9 | case $user_choice in 10 | '1') 11 | read -p "请输入需要修改的端口号(默认22): " new_port 12 | 13 | if [[ -z $new_port ]];then 14 | new_port=22 15 | fi 16 | 17 | if ! [[ $new_port =~ ^[0-9]+$ ]] || ! ((new_port > 0 && new_port < 65535)); then 18 | echo "端口号不合法" 19 | exit 20 | fi 21 | 22 | if lsof -i :$new_port -t >/dev/null; then 23 | echo "$new_port 端口已被占用" 24 | exit 25 | fi 26 | 27 | sed -i "s/^#\?Port.*/Port $new_port/g" /etc/ssh/sshd_config 28 | 29 | systemctl restart sshd.service 30 | 31 | echo "端口已修改为$new_port,请确保防火墙放行该端口" 32 | ;; 33 | '2') 34 | declare root_login_choice 35 | declare password_auth_choice 36 | declare key_auth_choice 37 | echo "是否关闭 root 用户登录" 38 | read -p "输入 n 关闭:" root_login_choice 39 | echo "是否关闭密码登录" 40 | read -p "输入 n 关闭:" password_auth_choice 41 | echo "是否关闭密钥登录" 42 | read -p "输入 n 关闭:" key_auth_choice 43 | 44 | if [[ ! $root_login_choice =~ [Nn] ]];then 45 | sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config 46 | echo "root 用户登录:已开启" 47 | else 48 | sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/g' /etc/ssh/sshd_config 49 | echo "root 用户登录:已关闭" 50 | fi 51 | 52 | if [[ ! $password_auth_choice =~ [Nn] ]];then 53 | sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config 54 | echo "密码登录:已开启" 55 | else 56 | sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/g' /etc/ssh/sshd_config 57 | echo "密码登录:已关闭" 58 | fi 59 | 60 | if [[ ! $key_auth_choice =~ [Nn] ]];then 61 | sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/g' /etc/ssh/sshd_config 62 | echo "密钥登录:已开启" 63 | else 64 | sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication no/g' /etc/ssh/sshd_config 65 | echo "密钥登录:已关闭" 66 | fi 67 | 68 | systemctl restart sshd.service 69 | ;; 70 | esac -------------------------------------------------------------------------------- /Config/Task/Installs/_action.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 接收参数 3 | local_path=$1 4 | selected_script=$2 5 | 6 | # 脚本路径配置 7 | read -p "请输入脚本存放路径(默认:/var/script):" script_path 8 | 9 | if [[ -z $script_path ]];then 10 | script_path='/var/script' 11 | fi 12 | mkdir -p "$script_path" 13 | 14 | # 定时任务配置说明 15 | echo "执行日期" 16 | echo "星号(*):表示匹配任意值" 17 | echo "逗号(,):用于分隔多个值" 18 | echo "斜线(/):用于指定间隔值" 19 | echo "连字符(-):用于指定范围" 20 | 21 | # 配置cron表达式 22 | declare cron_expression 23 | declare -a cron_fields=("分钟 0–59" "小时 0–23" "天数 1–31" "月份 1–12" "星期 0–7" ) 24 | for field in "${cron_fields[@]}";do 25 | read -p "${field},默认为 * :" tmp_time 26 | if [[ $tmp_time =~ ^[0-9]+$ || $tmp_time == '*' ]];then 27 | cron_expression+="${tmp_time} " 28 | elif [[ -z ${tmp_time} ]];then 29 | cron_expression+='* ' 30 | else 31 | echo "输入错误" 32 | exit 33 | fi 34 | done 35 | 36 | # 验证cron表达式 37 | if [[ "$cron_expression" == '* * * * * ' ]];then 38 | read -p "该脚本会无时无刻执行,请重新输入" 39 | exit 40 | fi 41 | 42 | # 检查脚本是否存在 43 | if [[ -f "${script_path}/${selected_script}.sh" ]];then 44 | echo "该路径文件已经存在" 45 | read -p "是否覆盖?(y/n): " overwrite 46 | if [[ ! $overwrite =~ [Yy] ]]; then 47 | echo "已取消操作" 48 | exit 49 | fi 50 | fi 51 | 52 | # 执行原始脚本 53 | bash "${local_path}/${selected_script}.sh" "$script_path" 54 | 55 | # 设置脚本权限 56 | chmod +x "${script_path}/${selected_script}.sh" && echo "脚本执行权限添加成功" || echo "脚本执行权限添加失败" 57 | 58 | # 配置定时任务 59 | declare cron_job="${cron_expression} ${script_path}/${selected_script}.sh" 60 | (crontab -l 2>/dev/null | grep -v "${selected_script}.sh") | crontab - 61 | (crontab -l 2>/dev/null; echo "$cron_job") | crontab - 62 | 63 | # 重启cron服务 64 | systemctl restart cron 2>> /dev/null && echo "自动任务配置成功" || echo "自动任务重启失败" 65 | 66 | echo "配置完成" -------------------------------------------------------------------------------- /Config/Task/Installs/acme_update.sh: -------------------------------------------------------------------------------- 1 | declare update_path="$1" 2 | 3 | cat > "${update_path}/acme_update.sh" << EOF 4 | #!/bin/bash 5 | ${HOME}/.acme.sh/acme.sh --upgrade 6 | ${HOME}/.acme.sh/acme.sh --renew-all --force 7 | EOF -------------------------------------------------------------------------------- /Config/Task/Installs/backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | declare backup_path="$1" 4 | declare data_directory 5 | declare local_backup_choice 6 | declare baidu_backup_choice 7 | declare aliyun_backup_choice 8 | declare ignore_flag=1 9 | 10 | read -p "请输入数据目录,默认 /var/www :" data_directory 11 | if [[ -z ${data_directory} ]];then 12 | data_directory='/var/www' 13 | fi 14 | 15 | for item in "$data_directory"/* ; do 16 | [[ $ignore_flag -eq 1 ]] && echo "当前脚本会备份的目录如下" && ignore_flag= 17 | declare item_name=$(basename "$item") 18 | echo "${item_name}" 19 | done 20 | 21 | echo "请输入需要屏蔽的目录,用空格隔开" 22 | read -p "请输入:" ignore 23 | 24 | read -p "是否备份到本地,默认关闭,输入 y 开启:" local_backup_choice 25 | read -p "是否备份到百度网盘,默认开启,输入 n 关闭:" baidu_backup_choice 26 | read -p "是否备份到阿里云盘,默认开启,输入 n 关闭:" aliyun_backup_choice 27 | 28 | if [[ ! $local_backup_choice =~ [Yy] && $baidu_backup_choice =~ [Nn] && $aliyun_backup_choice =~ [Nn] ]];then 29 | echo "没有选择备份的选项" 30 | exit 31 | fi 32 | 33 | if [[ $local_backup_choice =~ [Yy] ]];then 34 | declare local_backup_path 35 | read -p "请输入本地备份路径,默认 /var/webbackup :" local_backup_path 36 | if [[ -z $local_backup_path ]];then 37 | local_backup_path='/var/webbackup' 38 | fi 39 | if [[ -d $local_backup_path ]];then 40 | mkdir -p "$local_backup_path" 41 | fi 42 | fi 43 | 44 | if [[ ! $baidu_backup_choice =~ [Nn] ]];then 45 | if [[ -f "/usr/bin/apt-get" ]];then 46 | apt-get install python3-venv -y 47 | elif [[ -f "/usr/bin/apt" ]];then 48 | apt-get install python3-venv -y 49 | elif [[ -f "/usr/bin/pacman" ]];then 50 | pacman -Sy python3-venv --noconfirm 51 | else 52 | echo "无法自动安装 python3-venv,请手动安装" 53 | exit 54 | fi 55 | python3 -m venv "${backup_path}/venv" 56 | source "${backup_path}/venv/bin/activate" 57 | pip install bypy 58 | pip install requests 59 | echo "1. 将提示中的链接粘贴到浏览器中登录" 60 | echo "2. 输入账号密码登录后授权,获取授权码" 61 | echo "3. 将授权码粘贴回终端并按回车" 62 | bypy info 63 | fi 64 | 65 | if [[ ! $aliyun_backup_choice =~ [Nn] ]];then 66 | if [[ ! -d "${backup_path}/aliyunpan" ]];then 67 | wget -P "${backup_path}" https://github.com/tickstep/aliyunpan/releases/download/v0.3.2/aliyunpan-v0.3.2-linux-amd64.zip -O "${backup_path}/aliyunpan.zip" 68 | unzip "${backup_path}/aliyunpan.zip" -d "${backup_path}" 69 | rm "${backup_path}/aliyunpan.zip" 70 | mv "${backup_path}/$(ls "${backup_path}" | grep "aliyunpan")" "${backup_path}/aliyunpan" 71 | fi 72 | if [[ "$( ${backup_path}/aliyunpan/aliyunpan who)" == "未登录账号" ]];then 73 | ${backup_path}/aliyunpan/aliyunpan login 74 | fi 75 | fi 76 | 77 | cat > "${backup_path}/backup.sh" << EOF 78 | #!/bin/bash 79 | declare date_time=\$(date +"%Y_%m_%d") # 日期格式 80 | declare year=\$(date +"%Y") #年份 81 | declare ignore="$ignore" 82 | source "${backup_path}/venv/bin/activate" 83 | 84 | for item in "$data_directory"/*; do 85 | declare item_name=\$(basename "\$item") 86 | if [[ "\$ignore" =~ \$item_name ]];then 87 | continue 88 | fi 89 | cd "\$item" || exit 90 | docker compose down 91 | tar -czf "\${item_name}_\${date_time}.tar.gz" \$(ls) 92 | docker compose up -d 93 | bypy upload "\${item_name}_\${date_time}.tar.gz" "/\${item_name}/" 94 | ${backup_path}/aliyunpan/aliyunpan upload "\${item_name}_\${date_time}.tar.gz" "/网站/\${item_name}/\${year}/" 95 | mkdir -p "${local_backup_path}/\${year}/\${item_name}" && cp "\${item_name}_\${date_time}.tar.gz" "${local_backup_path}/\${year}/\${item_name}" 96 | rm "\${item_name}_\${date_time}.tar.gz" 97 | done 98 | EOF 99 | 100 | if [[ $local_backup_choice == [Yy] ]];then 101 | echo "本地备份路径:${data_directory}/年份/目录名称" 102 | else 103 | sed -i '/mkdir.*/d' "${backup_path}/backup.sh" 104 | fi 105 | 106 | if [[ $baidu_backup_choice == [Nn] ]];then 107 | sed -i '/bypy.*/d' "${backup_path}/backup.sh" 108 | sed -i '/source.*/d' "${backup_path}/backup.sh" 109 | else 110 | echo "百度网盘备份路径:我的应用数据/bypy/目录名称" 111 | fi 112 | 113 | if [[ $aliyun_backup_choice == [Nn] ]];then 114 | sed -i '/.*aliyunpan.*/d' "${backup_path}/backup.sh" 115 | else 116 | echo "阿里云盘备份路径:网盘/目录名称/日期" 117 | fi -------------------------------------------------------------------------------- /Config/Task/Installs/up-docker_compose.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | declare docker_compose_path="$1" 4 | if ! command -v docker &> /dev/null; then 5 | echo "未安装 Docker" 6 | exit 7 | fi 8 | 9 | declare data_directory 10 | read -p "请输入数据目录,默认 /var/www :" data_directory 11 | if [[ -z ${data_directory} ]];then 12 | data_directory='/var/www' 13 | fi 14 | cat > "${docker_compose_path}/up-docker_compose.sh" << EOF 15 | #!/bin/bash 16 | for dir in "${data_directory}"/*/; do 17 | cd "\$dir" || exit 18 | docker compose pull 19 | docker compose up -d 20 | done 21 | EOF -------------------------------------------------------------------------------- /Config/Task/Installs/update.sh: -------------------------------------------------------------------------------- 1 | declare update_path="$1" 2 | 3 | echo '#!/bin/bash' > "${update_path}/update.sh" 4 | 5 | if [[ -f "/usr/bin/apt" ]];then 6 | echo 'apt update -y' >> "${update_path}/update.sh" 7 | echo 'apt-get dist-upgrade -y' >> "${update_path}/update.sh" 8 | elif [[ -f "/usr/bin/apt-get" ]];then 9 | echo 'apt-get update -y' >> "${update_path}/update.sh" 10 | echo 'apt dist-upgrade -y' >> "${update_path}/update.sh" 11 | elif [[ -f "/usr/bin/pacman" ]];then 12 | pacman -Syu --noconfirm 13 | else 14 | rm "${update_path}/update.sh" 15 | echo "暂不支持该系统的自动更新配置" 16 | exit 17 | fi 18 | -------------------------------------------------------------------------------- /Config/Task/manage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "1. 查看已安装的脚本" 4 | echo "2. 删除脚本" 5 | 6 | declare user_choice 7 | read -p "请输入您的选择:" user_choice 8 | 9 | declare script_directory="/var/script" 10 | echo "请输入脚本安装目录,默认是 ${script_directory}:" 11 | read -p "请输入:" input_directory 12 | 13 | if [[ -n $input_directory ]]; then 14 | script_directory="$input_directory" 15 | fi 16 | 17 | if [[ ! -d $script_directory ]]; then 18 | echo "该目录不存在" 19 | exit 1 20 | fi 21 | 22 | function list_scripts() { 23 | local script_count=0 24 | for script in "$script_directory"/*; do 25 | if [[ ! -e $script ]]; then 26 | echo "该目录没有脚本" 27 | return 28 | fi 29 | local script_name=$(basename "$script" | awk -F '.' '{print $1}') 30 | if [[ $script_name == "linuxtool" ]]; then 31 | continue 32 | fi 33 | script_count=$((script_count + 1)) 34 | echo "${script_count}.${script_name}" 35 | installed_scripts[$script_count]=$script_name 36 | done 37 | 38 | if [[ ${#installed_scripts[@]} -eq 0 ]]; then 39 | echo "该目录没有脚本" 40 | return 41 | fi 42 | } 43 | 44 | case $user_choice in 45 | '1') 46 | list_scripts 47 | ;; 48 | '2') 49 | declare -a installed_scripts 50 | list_scripts 51 | read -p "请输入要删除的序号(多个用空格隔开):" script_indices 52 | 53 | for index in $script_indices; do 54 | if [[ $index =~ ^[1-9][0-9]*$ ]] && [ $index -le ${#installed_scripts[@]} ]; then 55 | local script_to_delete=${installed_scripts[$((index - 1))]} 56 | echo "开始删除 ${script_to_delete}" 57 | (crontab -l 2>/dev/null | grep -v "$script_to_delete") | crontab - && echo "已删除脚本的自动任务" 58 | rm -rf "$script_directory/$script_to_delete" &>/dev/null 59 | echo "删除完成" 60 | else 61 | echo "无效的序号: $index" 62 | fi 63 | done 64 | ;; 65 | *) 66 | echo "无效的选择" 67 | exit 1 68 | ;; 69 | esac 70 | -------------------------------------------------------------------------------- /Config/Web/acme/_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if ! command -v socat &> /dev/null; then 3 | if [[ -f "/usr/bin/apt-get" ]];then 4 | apt-get update -y 5 | apt-get install socat -y 6 | elif [[ -f "/usr/bin/apt" ]];then 7 | apt update -y 8 | apt install socat -y 9 | elif [[ -f "/usr/bin/pacman" ]];then 10 | pacman -Syu --noconfirm 11 | pacman -Sy --noconfirm socat 12 | else 13 | echo "socat未安装,请手动安装" 14 | exit 15 | fi 16 | fi 17 | 18 | if [[ ! -f "${HOME}/.acme.sh/acme.sh" ]];then 19 | rm -rf ${HOME}/.apple.sh 20 | declare email_address 21 | read -p "请输入用来申请域名的邮箱:" email_address 22 | if [[ ! $email_address =~ .*@.* ]];then 23 | echo "邮箱不合法" 24 | exit 25 | fi 26 | 27 | curl https://get.acme.sh | sh -s "email=$email_address" 28 | fi 29 | -------------------------------------------------------------------------------- /Config/Web/acme/apply.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare selected_mode=$1 3 | declare domain_names=$2 4 | 5 | if ! [[ $selected_mode == "nginx" ]]; then 6 | selected_mode="" 7 | domain_names="" 8 | fi 9 | 10 | declare domain_string 11 | 12 | if [[ ! $domain_names ]];then 13 | echo "请输入需要申请SSL证书的域名" 14 | read -p "请输入要绑定的域名(多个用空格隔开):" domain_names 15 | fi 16 | 17 | for i in ${domain_names} ; do 18 | if [[ ! $i =~ [\w+\.]+ ]];then 19 | echo "域名不合法" 20 | exit 21 | else 22 | domain_string="$domain_string -d $i" 23 | fi 24 | done 25 | 26 | if [[ -z $domain_string ]]; then 27 | echo "需要添加的域名不能为空" 28 | exit 29 | fi 30 | 31 | echo "1.http验证" 32 | echo "2.dns验证" 33 | read -p "请选择验证模式:" selected_mode 34 | 35 | case $selected_mode in 36 | '1') 37 | declare mode 38 | if command -v nginx &> /dev/null; then 39 | mode="nginx" 40 | cat > "/etc/nginx/conf.d/test.conf" << EOF 41 | server { 42 | listen 80; # 监听80端口 43 | server_name ${domain_names}; # 服务器名称(本地) 44 | 45 | location / { 46 | root /usr/share/nginx/html; # 指定根目录 47 | index index.html index.htm; # 默认页面 48 | } 49 | } 50 | EOF 51 | elif command -v apache &> /dev/null; then 52 | mode="apache" 53 | else 54 | mode="standalone" 55 | fi 56 | echo "请到服务器将80和443端口开启,将域名解析到本机" 57 | read -p "解析完成请回车:" 58 | eval "${HOME}/.acme.sh/acme.sh --issue ${domain_string} --${mode}" 59 | rm /etc/nginx/conf.d/test.conf 60 | ;; 61 | '2') 62 | declare pick=0 63 | declare -a mode_array 64 | mode_array[1]="TXT记录" 65 | mode_array[2]='cloudflare' 66 | for i in "${!mode_array[@]}"; do 67 | ((pick++)) 68 | echo "${pick}. ${mode_array[$i]}" 69 | done 70 | read -p "请选择验证模式:" selected_mode 71 | if [[ ! $selected_mode =~ [1-${pick}] ]]; then 72 | exit 73 | fi 74 | 75 | case ${mode_array[$selected_mode]} in 76 | 'TXT记录') 77 | declare log_output=$(${HOME}/.apple.sh/apple.sh --issue --dns $domain_string --yes-I-know-dns-manual-mode-enough-go-ahead-please) 78 | declare -a domain=($( echo "$log_output" | grep "Domain:" | awk -F ": " '{print $2}')) 79 | declare -a txt_value=($(echo "$log_output" | grep "TXT value:" | awk -F ": " '{print $2}')) 80 | echo "请到dns系统解析TXT记录" 81 | for (( i = 0; i < ${#domain[@]}; i++ )); do 82 | echo "需要解析的第$((i+1))条" 83 | echo "名称: ${domain[$i]}" 84 | echo "文本记录:${txt_value[$i]}" 85 | done 86 | 87 | read -p "解析完成请输入 y:" selected_mode 88 | if [[ $selected_mode =~ [Yy] ]]; then 89 | eval "${HOME}/.acme.sh/acme.sh --renew $domain_string --yes-I-know-dns-manual-mode-enough-go-ahead-please" 90 | else 91 | echo "解析完成后请输入下面的命令完成验证" 92 | echo "${HOME}/.acme.sh/acme.sh --renew $domain_string --yes-I-know-dns-manual-mode-enough-go-ahead-please" 93 | fi 94 | ;; 95 | 'cloudflare') 96 | declare CF_Key 97 | declare CF_Email 98 | read -p "请输入cloudflare的邮箱:" CF_Email 99 | if [[ ! $CF_Email =~ .*@.* ]];then 100 | echo "邮箱不合法" 101 | exit 102 | fi 103 | read -p "请输入cloudflare的密钥:" CF_Key 104 | export CF_Key=$CF_Key 105 | export CF_Email=$CF_Email 106 | eval "${HOME}/.acme.sh/acme.sh --issue $domain_string --dns dns_cf" 107 | esac 108 | ;; 109 | esac 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Config/Web/acme/manage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "1.查看已经成功申请证书的域名" 3 | 4 | declare user_choice 5 | read -p "请输入选择:" user_choice 6 | 7 | case $user_choice in 8 | '1') 9 | declare certificate_name 10 | declare certificate_count=0 11 | declare -a certificate_array 12 | 13 | for i in "${HOME}/.acme.sh"/* ; do 14 | certificate_name=$(basename $i ) 15 | if ! echo "$certificate_name" | grep -q "_ecc" ; then 16 | continue 17 | fi 18 | certificate_name=$(echo $certificate_name | sed "s/_ecc//g" ) 19 | certificate_count=$(( certificate_count+1 )) 20 | certificate_array[$certificate_count]=$certificate_name 21 | echo "${certificate_count}.${certificate_name}" 22 | done 23 | if [ ${#certificate_array[@]} == 0 ]; then 24 | echo "暂时没有安装证书" 25 | exit 26 | fi 27 | read -p "请输入要查看证书详细信息的序号:" user_choice 28 | if [[ $user_choice =~ [1-${#certificate_array[@]}] ]]; then 29 | bash "${HOME}/.acme.sh/acme.sh -info -d ${certificate_array[$user_choice]}" 30 | else 31 | echo "选择错误" 32 | fi 33 | ;; 34 | esac -------------------------------------------------------------------------------- /Config/Web/nginx/_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if ! command -v nginx &> /dev/null; then 4 | if [[ -f "/usr/bin/apt-get" ]];then 5 | apt-get update -y 6 | apt-get install nginx -y 7 | elif [[ -f "/usr/bin/apt" ]];then 8 | apt update -y 9 | apt install nginx -y 10 | elif [[ -f "/usr/bin/pacman" ]];then 11 | pacman -Syu --noconfirm 12 | pacman -Sy --noconfirm nginx 13 | else 14 | echo "nginx未安装,请手动安装" 15 | exit 16 | fi 17 | fi -------------------------------------------------------------------------------- /Config/Web/nginx/install.sh: -------------------------------------------------------------------------------- 1 | declare domain_names 2 | read -p "请输入要绑定的域名(多个用空格隔开):" domain_names 3 | 4 | declare ssl_cert_path 5 | declare ssl_key_path 6 | declare primary_domain=$(echo "${domain_names}" | awk '{print $1}') 7 | declare folder_domain 8 | echo "SSL证书选择" 9 | echo "1.自动申请(默认)" 10 | echo "2.手动输入" 11 | read -p "请输入选择:" user_choice 12 | if [[ $user_choice == 2 ]]; then 13 | 14 | folder_domain=$(ls ${HOME}/.acme.sh/ | grep "^${primary_domain}" | head -n1) 15 | echo "证书路径, 默认 ${HOME}/.acme.sh/${folder_domain:-"${primary_domain}_ecc"}/fullchain.cer" 16 | read -p "请输入证书地址:" ssl_cert_path 17 | if [[ -z $ssl_cert_path ]];then 18 | ssl_cert_path="${HOME}/.acme.sh/${folder_domain:-"${primary_domain}_ecc"}/fullchain.cer" 19 | 20 | fi 21 | echo "密钥路径, 默认 ${HOME}/.acme.sh/${folder_domain:-"${primary_domain}_ecc"}/${primary_domain}.key" 22 | 23 | read -p "请输入密钥地址:" ssl_key_path 24 | if [[ -z $ssl_key_path ]];then 25 | ssl_key_path="${HOME}/.acme.sh/${folder_domain:-"${primary_domain}_ecc"}/${primary_domain}.key" 26 | fi 27 | else 28 | echo "1.nginx(默认)" 29 | read -p "请选择:" user_choice 30 | bash "$(dirname $(dirname $0))/acme/test.sh" 31 | bash "$(dirname $(dirname $0))/acme/apply.sh" "nginx" "${domain_names}" 32 | folder_domain=$(ls ${HOME}/.acme.sh/ | grep "^${primary_domain}" | head -n1) 33 | ssl_cert_path="${HOME}/.acme.sh/${folder_domain}/fullchain.cer" 34 | ssl_key_path="${HOME}/.acme.sh/${folder_domain}/${primary_domain}.key" 35 | fi 36 | 37 | declare config_file_name 38 | read -p "请输入配置文件名(默认为域名):" config_file_name 39 | if [[ -z $config_file_name ]]; then 40 | config_file_name=$primary_domain 41 | fi 42 | 43 | echo "工作方式选择" 44 | echo "1.反向代理(默认)" 45 | echo "2.静态文件" 46 | read -p "请选择:" user_choice 47 | declare site_path 48 | if [[ $user_choice == 2 ]]; then 49 | read -p "请输入要代理的站点路径:" site_path 50 | cat > "/etc/nginx/sites-available/${config_file_name}.conf" << EOF 51 | server { 52 | listen 443 ssl http2; # 监听 443 端口并启用 SSL 和 HTTP/2 53 | server_name ${domain_names}; # 替换为你的域名 54 | 55 | # SSL 证书配置 56 | ssl_certificate ${ssl_cert_path}; # 证书文件路径 57 | ssl_certificate_key ${ssl_key_path}; # 证书密钥文件路径 58 | ssl_protocols TLSv1.2 TLSv1.3; # 仅使用安全的 TLS 协议版本 59 | ssl_ciphers HIGH:!aNULL:!MD5; # 安全的密码套件 60 | ssl_prefer_server_ciphers on; # 优先使用服务器的密码套件 61 | ssl_session_cache shared:SSL:10m; 62 | ssl_session_timeout 10m; 63 | 64 | # HSTS(HTTP 严格传输安全)强制浏览器使用 HTTPS 65 | add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; 66 | 67 | # 设置文件传输的最大大小 68 | client_max_body_size 100M; # 上传文件最大大小 (例如 100MB) 69 | proxy_max_temp_file_size 1024m; # 代理最大临时文件大小 70 | 71 | # 超时与缓冲设置 72 | client_body_timeout 60s; # 等待客户端发送请求主体的超时时间 73 | client_header_timeout 60s; # 等待客户端发送请求头的超时时间 74 | send_timeout 60s; # 发送响应的超时时间 75 | client_body_buffer_size 128k; # 上传缓冲区大小 76 | proxy_buffer_size 4k; # 设置代理服务器响应的缓冲区大小 77 | proxy_buffers 8 16k; # 代理服务器的缓冲区数和大小 78 | proxy_busy_buffers_size 64k; # 忙碌代理缓冲区大小 79 | large_client_header_buffers 4 16k; # 设置较大的客户端头部缓冲区,防止上传大文件时出现 413 错误 80 | 81 | # 静态文件目录 82 | root ${site_path}; 83 | index index.html index.htm; 84 | 85 | # 日志 86 | access_log /var/log/nginx/example.com_access.log; 87 | error_log /var/log/nginx/example.com_error.log; 88 | 89 | # 默认处理 90 | location / { 91 | try_files \$uri \$uri/ =404; 92 | } 93 | 94 | # 防止访问隐藏文件(如 .git) 95 | location ~ /\. { 96 | deny all; 97 | } 98 | 99 | # 错误页面配置 100 | error_page 404 /404.html; 101 | location = /404.html { 102 | root /var/www/example.com/html; 103 | } 104 | } 105 | 106 | # HTTP 到 HTTPS 重定向 107 | server { 108 | listen 80; # 监听 80 端口 109 | server_name ${domain_names}; 110 | 111 | # 将所有 HTTP 请求重定向到 HTTPS 112 | return 301 https://\$host\$request_uri; 113 | } 114 | 115 | EOF 116 | else 117 | read -p "请输入后端服务器的地址,如果只输入数字代表端口:" site_path 118 | if [[ $site_path =~ [0-9]+ ]]; then 119 | site_path="http://127.0.0.1:${site_path}" 120 | fi 121 | cat > "/etc/nginx/sites-available/${config_file_name}.conf" << EOF 122 | server { 123 | listen 443 ssl http2; # 监听 443 端口,并启用 HTTP/2 124 | server_name ${domain_names}; # 替换为你的域名 125 | 126 | # SSL 证书配置 127 | ssl_certificate ${ssl_cert_path}; # 证书文件路径 128 | ssl_certificate_key ${ssl_key_path}; # 证书密钥文件路径 129 | ssl_protocols TLSv1.2 TLSv1.3; # 使用安全的 TLS 协议版本 130 | ssl_ciphers HIGH:!aNULL:!MD5; # 安全密码套件 131 | ssl_prefer_server_ciphers on; 132 | 133 | # 启用 SSL session 缓存和超时设置 134 | ssl_session_cache shared:SSL:10m; 135 | ssl_session_timeout 10m; 136 | 137 | # 强制使用 HTTPS (HSTS) 138 | add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; 139 | 140 | # 日志设置 141 | access_log /var/log/nginx/${config_file_name}_access.log; 142 | error_log /var/log/nginx/${config_file_name}_error.log; 143 | 144 | # 错误页面配置 145 | error_page 404 /404.html; 146 | location = /404.html { 147 | root /var/www/example.com/html; 148 | } 149 | 150 | # 设置文件传输的最大大小 151 | client_max_body_size 100M; # 上传文件最大大小 (例如 100MB) 152 | proxy_max_temp_file_size 1024m; # 代理最大临时文件大小 153 | 154 | # 超时与缓冲设置 155 | client_body_timeout 60s; # 等待客户端发送请求主体的超时时间 156 | client_header_timeout 60s; # 等待客户端发送请求头的超时时间 157 | send_timeout 60s; # 发送响应的超时时间 158 | client_body_buffer_size 128k; # 上传缓冲区大小 159 | proxy_buffer_size 4k; # 设置代理服务器响应的缓冲区大小 160 | proxy_buffers 8 16k; # 代理服务器的缓冲区数和大小 161 | proxy_busy_buffers_size 64k; # 忙碌代理缓冲区大小 162 | large_client_header_buffers 4 16k; # 设置较大的客户端头部缓冲区,防止上传大文件时出现 413 错误 163 | 164 | # 反向代理到后台应用 (常规 HTTP/HTTPS) 165 | location / { 166 | proxy_pass ${site_path}; # 反向代理到后端应用服务器 167 | proxy_set_header Host \$host; # 保持原始主机头 168 | proxy_set_header X-Real-IP \$remote_addr; # 传递客户端的真实 IP 169 | proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; # 传递代理链中的 IP 170 | proxy_set_header X-Forwarded-Proto \$scheme; # 传递协议(HTTP 或 HTTPS) 171 | 172 | # 防止后端服务器返回不安全的内容 173 | proxy_redirect off; 174 | 175 | # 超时时间配置 176 | proxy_connect_timeout 60s; 177 | proxy_send_timeout 60s; 178 | proxy_read_timeout 60s; 179 | send_timeout 60s; 180 | } 181 | 182 | # WebSocket 反向代理到后台应用 183 | location /ws { 184 | proxy_pass ${site_path}; # 反向代理到 WebSocket 应用服务器 185 | proxy_http_version 1.1; # WebSocket 必须使用 HTTP 1.1 186 | proxy_set_header Upgrade \$http_upgrade; # 升级请求头,用于 WebSocket 187 | proxy_set_header Connection "Upgrade"; # 持久连接,保持 WebSocket 连接 188 | proxy_set_header Host \$host; # 保持原始主机头 189 | proxy_set_header X-Real-IP \$remote_addr; # 传递客户端的真实 IP 190 | proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; # 传递代理链中的 IP 191 | proxy_set_header X-Forwarded-Proto \$scheme; # 传递协议(HTTP 或 HTTPS) 192 | 193 | # 超时时间配置 (WebSocket 是长连接) 194 | proxy_connect_timeout 60s; 195 | proxy_send_timeout 60s; 196 | proxy_read_timeout 3600s; # WebSocket 长连接需较长读超时 197 | send_timeout 60s; 198 | } 199 | 200 | # 错误页面配置 201 | error_page 502 /502.html; 202 | location = /502.html { 203 | root /usr/share/nginx/html; # 错误页面路径 204 | } 205 | } 206 | 207 | # HTTP 到 HTTPS 重定向 208 | server { 209 | listen 80; # 监听 HTTP 80 端口 210 | server_name ${domain_names}; # 替换为你的域名 211 | 212 | # 将所有 HTTP 请求重定向到 HTTPS 213 | return 301 https://\$host\$request_uri; 214 | } 215 | 216 | EOF 217 | fi 218 | ln -s "/etc/nginx/sites-available/${config_file_name}.conf" "/etc/nginx/sites-enabled" &> /dev/null 219 | nginx -s reload &> /dev/null 220 | echo "配置完成" 221 | -------------------------------------------------------------------------------- /Config/Web/nginx/manage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare user_choice 3 | echo "========$(basename $0 .sh)========" 4 | echo "1.查看已有站点配置文件" 5 | echo "2.删除站点配置文件" 6 | read -p "请选择操作:" user_choice 7 | case $user_choice in 8 | '1') 9 | declare -a site_array 10 | declare site_name 11 | declare site_count=0 12 | for i in "/etc/nginx/sites-available"/* ; do 13 | if [[ $i == "/etc/nginx/sites-available/*" ]];then 14 | echo "暂时没有配置文件" 15 | exit 16 | fi 17 | site_count=$(( site_count+1 )) 18 | site_name=$(basename $i) 19 | echo "${site_count}.${site_name}" 20 | site_array[$site_count]=$site_name 21 | done 22 | if [ ${#site_array[@]} == 0 ]; then 23 | echo "暂时没有配置文件" 24 | exit 25 | fi 26 | ;; 27 | '2') 28 | declare -a site_array 29 | declare site_name 30 | declare site_count=0 31 | for i in "/etc/nginx/sites-available"/* ; do 32 | if [[ $i == "/etc/nginx/sites-available/*" ]];then 33 | echo "暂时没有配置文件" 34 | exit 35 | fi 36 | site_count=$(( site_count+1 )) 37 | site_name=$(basename $i) 38 | echo "${site_count}.${site_name}" 39 | site_array[$site_count]=$site_name 40 | done 41 | if [ ${#site_array[@]} == 0 ]; then 42 | echo "暂时没有配置文件" 43 | exit 44 | fi 45 | read -p "请输入要删除的序号,多个用 空格 隔开:" site_name 46 | for i in $site_name ; do 47 | if [[ $i =~ [1-${#site_array[*]}] ]]; then 48 | echo "开始删除 ${site_array[$i]}" 49 | rm -rf "/etc/nginx/sites-available/${site_array[$i]}" &> /dev/null 50 | rm -rf "/etc/nginx/sites-enabled/${site_array[$i]}" &> /dev/null 51 | echo "删除完成" 52 | fi 53 | done 54 | echo "删除完成" 55 | ;; 56 | esac -------------------------------------------------------------------------------- /Config/software.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "正在更新系统包管理器" 3 | declare install_command 4 | declare os_version="$(cat /etc/os-release | grep "^ID" | awk -F '=' '{print $2}')" 5 | declare install_status=0 6 | 7 | declare package_manager 8 | if [[ -f "/usr/bin/apt-get" ]]; then 9 | package_manager='apt-get' 10 | install_command+="${package_manager} install -y" 11 | apt-get update -y 12 | elif [[ -f "/usr/bin/apt" ]]; then 13 | package_manager='apt' 14 | install_command+="${package_manager} install -y" 15 | apt update -y 16 | elif [[ -f "/usr/bin/pacman" ]]; then 17 | package_manager='pacman' 18 | install_command+="${package_manager} -Sy --noconfirm" 19 | pacman -Syu --noconfirm 20 | else 21 | echo "暂不支持该系统一键安装常用软件" 22 | exit 23 | fi 24 | 25 | declare selected_packages 26 | declare package_count 27 | declare -A package_options 28 | declare -a package_names 29 | package_options['git']=0 30 | package_options['vim']=0 31 | package_options['wget']=0 32 | package_options['curl']=0 33 | package_options['sudo']=0 34 | package_options['ssh']=0 35 | package_options['zsh']=0 36 | package_options['zip']=0 37 | package_options['zsh-beautify']=1 38 | package_options['docker']=1 39 | package_options['x-cmd']=1 40 | 41 | echo "========$(basename $0 .sh)========" 42 | for i in "${!package_options[@]}"; do 43 | package_count=$((package_count + 1)) 44 | package_names[$package_count]=$i 45 | echo "${package_count}.${i}" 46 | done 47 | echo "请输入需要安装的软件序号(默认安装全部)" 48 | read -p "用 空格 隔开:" selected_packages 49 | 50 | if [[ -z $selected_packages ]]; then 51 | for ((i = 1; i <= ${#package_options[@]}; i++)); do 52 | if [[ $i != 1 ]]; then 53 | selected_packages="$selected_packages $i" 54 | else 55 | selected_packages="$i" 56 | fi 57 | done 58 | else 59 | for i in $selected_packages; do 60 | if ! [[ $i =~ ^[1-9]+$ && $i -gt 1 || $i -lt ${#package_options[@]} ]]; then 61 | echo "输入错误$i" 62 | exit 63 | fi 64 | done 65 | fi 66 | for i in $selected_packages; do 67 | if [[ ${package_options[${package_names[$i]}]} == 0 ]]; then 68 | eval "$install_command ${package_names[$i]}" 69 | else 70 | package_options[${package_names[$i]}]=2 71 | fi 72 | done 73 | 74 | if [[ ${package_options['x-cmd']} == 2 ]]; then 75 | eval "$(curl https://get.x-cmd.com)" 76 | fi 77 | 78 | if [[ ${package_options['docker']} == 2 ]]; then 79 | echo "请选择docker下载镜像站" 80 | declare -A docker_mirrors 81 | docker_mirrors['官方']='https://download.docker.com' 82 | docker_mirrors['清华大学']='https://mirrors.tuna.tsinghua.edu.cn/docker-ce' 83 | docker_mirrors['阿里云']='https://mirrors.aliyun.com/docker-ce' 84 | docker_mirrors['网易云']='https://mirrors.163.com/docker-ce' 85 | 86 | declare -a docker_mirror_options 87 | declare docker_mirror_choice=0 88 | 89 | for i in "${!docker_mirrors[@]}"; do 90 | docker_mirror_choice=$((docker_mirror_choice + 1)) 91 | docker_mirror_options[$docker_mirror_choice]=$i 92 | echo "${docker_mirror_choice}.${i}" 93 | done 94 | read -p "请选择Docker镜像站(默认 1):" docker_mirror_choice 95 | declare docker_mirror 96 | if [[ $docker_mirror_choice =~ [1-${#docker_mirrors[@]}] ]]; then 97 | docker_mirror_choice=${docker_mirror_options[$docker_mirror_choice]} 98 | docker_mirror=${docker_mirrors[$docker_mirror_choice]} 99 | else 100 | docker_mirror=${docker_mirrors[${docker_mirror_options[1]}]} 101 | fi 102 | 103 | if [[ ${package_manager} == 'apt' || ${package_manager} == 'apt-get' ]]; then 104 | ${package_manager} update 105 | ${package_manager} install ca-certificates curl -y 106 | install -m 0755 -d /etc/apt/keyrings 107 | curl -fsSL "${docker_mirror}/linux/${os_version}/gpg" -o /etc/apt/keyrings/docker.asc 108 | chmod a+r /etc/apt/keyrings/docker.asc 109 | echo \ 110 | "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] ${docker_mirror}/linux/${os_version} \ 111 | $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | 112 | tee /etc/apt/sources.list.d/docker.list >/dev/null 113 | ${package_manager} update 114 | ${package_manager} install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y 115 | elif [[ ${package_manager} == 'pacman' ]]; then 116 | pacman -Sy docker --noconfirm 117 | systemctl start docker.service 118 | systemctl enable docker.service 119 | usermod -aG docker $USER 120 | newgrp docker 121 | fi 122 | fi 123 | 124 | if [[ ${package_options['zsh-beautify']} == 2 ]]; then 125 | curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | sed 's/read -r opt//g' | sed 's/exec zsh -l//g' | sh 126 | while [[ ! -d "$HOME/.oh-my-zsh" ]]; do 127 | sleep 3 128 | done 129 | git clone --depth=1 https://gitee.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k 130 | git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting 131 | git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions 132 | sed -i 's/^#\?ZSH_THEME.*/ZSH_THEME="powerlevel10k\/powerlevel10k"/g' ~/.zshrc 133 | sed -i 's/^#\?plugins.*/plugins=(zsh-syntax-highlighting zsh-autosuggestions command-not-found)/g' ~/.zshrc 134 | chsh -s /bin/zsh 135 | exec zsh -l 136 | fi 137 | 138 | echo "软件已经全部安装成功" 139 | -------------------------------------------------------------------------------- /Config/sources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | declare os_version=$(cat /etc/os-release | grep VERSION_CODENAME | awk -F '=' '{print $2}') 4 | declare os_id=$(cat /etc/os-release | grep "^ID" | awk -F '=' '{print $2}') 5 | declare update_status=0 6 | 7 | declare -A mirror_sources 8 | mirror_sources['中国科技技术大学(默认)']='http://mirrors.ustc.edu.cn' 9 | mirror_sources['清华大学']='https://mirrors.tuna.tsinghua.edu.cn' 10 | mirror_sources['阿里云']='https://mirrors.aliyun.com' 11 | mirror_sources['网易云']='https://mirrors.163.com' 12 | 13 | declare -a selected_sources 14 | declare source_choice=0 15 | echo "========$(basename $0 .sh)========" 16 | for i in "${!mirror_sources[@]}"; 17 | do 18 | source_choice=$(( source_choice+1 )) 19 | selected_sources[$source_choice]=$i 20 | echo "${source_choice}.${i}" 21 | done 22 | read -p "请输入选择的源:" source_choice 23 | 24 | if [[ -z $source_choice ]];then 25 | declare selected_url='http://mirrors.ustc.edu.cn' 26 | elif [[ ${source_choice} =~ [1-${#mirror_sources[@]}] ]];then 27 | source_choice=${selected_sources[$source_choice]} 28 | declare selected_url=${mirror_sources[$source_choice]} 29 | else 30 | echo "输入错误" 31 | exit 32 | fi 33 | 34 | case "$os_version" in 35 | 'bookworm') 36 | cat > "/etc/apt/sources.list" << EOF 37 | deb ${selected_url}/debian/ bookworm main contrib non-free non-free-firmware 38 | deb ${selected_url}/debian/ bookworm-updates main contrib non-free non-free-firmware 39 | deb ${selected_url}/debian/ bookworm-backports main contrib non-free non-free-firmware 40 | EOF 41 | apt update -y 42 | apt-get update -y 43 | update_status=1 44 | ;; 45 | 'bullseye') 46 | cat > "/etc/apt/sources.list" << EOF 47 | deb ${selected_url}/debian/ bullseye main contrib non-free 48 | deb ${selected_url}/debian/ bullseye-updates main contrib non-free 49 | deb ${selected_url}/debian/ bullseye-backports main contrib non-free 50 | EOF 51 | apt update -y 52 | apt-get update -y 53 | update_status=1 54 | ;; 55 | esac 56 | 57 | case "$os_id" in 58 | 'arch') 59 | pacman -Sy pacman-key --noconfirm 60 | sed -i '/^Server.*/d' "/etc/pacman.conf" 61 | echo "Server = ${selected_url}/archlinuxcn/\$arch" 62 | pacman-key --lsign-key "farseerfc@archlinux.org" 63 | pacman -Syyu 64 | update_status=1 65 | ;; 66 | 'ubuntu') 67 | cat > "/etc/apt/sources.list" << EOF 68 | deb ${selected_url}/ubuntu/ ${os_version} main restricted universe multiverse 69 | deb ${selected_url}/ubuntu/ ${os_version}-security main restricted universe multiverse 70 | deb ${selected_url}/ubuntu/ ${os_version}-updates main restricted universe multiverse 71 | deb ${selected_url}/ubuntu/ ${os_version}-backports main restricted universe multiverse 72 | EOF 73 | apt update -y 74 | apt-get update -y 75 | update_status=1 76 | ;; 77 | esac 78 | 79 | if [[ $update_status == 0 ]]; then 80 | echo "暂不支持该系统一键换源" 81 | exit 82 | fi 83 | 84 | echo "换源成功" -------------------------------------------------------------------------------- /Config/vpn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | declare vpn_count=0 3 | declare -a vpn_options 4 | declare -A vpn_commands 5 | declare user_choice 6 | 7 | vpn_commands["v2ray"]='bash <(curl -s -L https://git.io/v2ray.sh)' 8 | vpn_commands["v2ray-agent"]='wget -P /root -N --no-check-certificate "https://raw.githubusercontent.com/mack-a/v2ray-agent/master/install.sh" && chmod 700 /root/install.sh && /root/install.sh' 9 | vpn_commands["3-ui"]='bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)' 10 | vpn_commands["V2bX"]='wget -N https://raw.githubusercontent.com/wyx2685/V2bX-script/master/install.sh && bash install.sh' 11 | 12 | for i in "${!vpn_commands[@]}";do 13 | vpn_count=$((vpn_count+1)) 14 | vpn_options[${vpn_count}]=${i} 15 | echo "${vpn_count}.${i}" 16 | done 17 | read -p "请输入要选择的序号:" user_choice 18 | 19 | if [[ $user_choice =~ [1-${#vpn_commands[@]}] ]];then 20 | eval "${vpn_commands[${vpn_options[$user_choice]}]}" 21 | echo "安装完成" 22 | else 23 | echo "输入错误" 24 | fi 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🛠 Linux 服务器管理工具箱 2 | 3 | 一个简单易用的 Linux 服务器管理工具,帮助你快速部署和管理服务器。 4 | 5 | ## 🔍 系统要求 6 | 7 | - 系统支持: 8 | 9 | - Debian 8+ 10 | - Ubuntu 16.04+ 11 | - Arch Linux 12 | 13 | - 需要 root 权限 14 | - Linux 内核 5.0+ 15 | - 需要预装工具: curl 16 | 17 | ## 💻 安装方法 18 | 19 | ### 快速安装 20 | 21 | 国内用户推荐使用 Gitee 源: 22 | 23 | ```bash 24 | bash <(curl -Ls https://gitee.com/lsy22/linuxtool/raw/master/Config/Manage/install.sh) 25 | ``` 26 | 27 | 国外用户可以使用 GitHub 源: 28 | 29 | ```bash 30 | bash <(curl -Ls tool.lsy22.com) 31 | ``` 32 | 33 | ### 使用说明 34 | 35 | 1. 运行安装脚本 36 | 2. 选择安装位置(默认 /var/script) 37 | 3. 重启终端或重新连接终端 38 | 4. 输入 `tool` 启动工具箱 39 | 40 | ### ⚠️ 注意事项 41 | 42 | - 请确保系统已安装 curl 工具 43 | - 需要 root 权限或 sudo 权限执行 44 | - 如遇到网络问题,建议国内用户使用 Gitee 源 45 | 46 | ## 🔧 工具箱原理与扩展 47 | 48 | ### 核心原理 49 | 50 | 1. **层级菜单系统**:脚本会自动遍历 Config 目录下的所有文件和文件夹,动态生成菜单选项 51 | 2. **自动执行机制**: 52 | - 选择 `.sh` 文件时会直接执行该脚本 53 | - 选择文件夹时会进入并展示该文件夹下的内容 54 | 55 | ### 特殊文件作用 56 | 57 | - **\_init.sh**:目录初始化脚本,在进入目录时自动执行,用于环境依赖检查 58 | - **位置参数**:不接收位置参数 59 | - **\_menu.sh**:完全替代默认菜单,提供自定义菜单界面 60 | - **位置参数**:`$1` - 当前目录路径 (`local_path`) 61 | - **\_action.sh**:半替代菜单,接收用户选择的脚本名称和当前路径,决定如何执行 62 | - **位置参数**:`$1` - 当前目录路径 (`local_path`),`$2` - 用户选择的脚本名称 (`selected_script`) 63 | 64 | ### 自定义扩展方法 65 | 66 | 1. **添加新功能**: 67 | 68 | - 在相应目录下创建 `.sh` 脚本文件 69 | - 脚本会自动出现在菜单中供用户选择 70 | 71 | 2. **添加新模块**: 72 | 73 | - 在 Config 目录下创建新的文件夹 74 | - 可以在文件夹中添加 \_init.sh 用于依赖检查 75 | - 可以添加 \_menu.sh 提供自定义的选项界面 76 | - 可以添加 \_action.sh 处理用户选择 77 | 78 | 3. **修改菜单行为**: 79 | - 编辑对应目录下的 \_menu.sh 文件实现完全自定义菜单 80 | - 编辑 \_action.sh 实现半自定义菜单,保留默认菜单但自定义执行逻辑 81 | 82 | ## 📚 功能模块说明 83 | 84 | ### 🐳 Docker 应用管理 (Docker) 85 | 86 | #### 应用安装脚本 (Installs) 87 | 88 | - **alist** : 安装 Alist 网盘管理工具,自动配置管理员密码 89 | - **gitea** : 部署 Gitea 代码托管平台,包含 MySQL 数据库配置 90 | - **nginx-proxy-manager** : 安装 Nginx 可视化管理面板 91 | - **safeline** : 部署长亭 WAF 防火墙 92 | - **siyuan** : 安装思源笔记服务端,支持自定义访问密码 93 | - **typecho** : 部署 Typecho 博客系统,自动配置数据库 94 | - **vaultwarden** : 安装密码管理器服务端,支持中文界面 95 | - **xboard** : 部署 xboard 面板 96 | 97 | #### Docker 管理工具 98 | 99 | - **image** : (查看/停止/清理) 100 | - **manage** : 已安装 Docker 应用管理(查看/删除) 101 | - **source** : Docker 镜像源管理(查看/切换) 102 | 103 | ### 🛡️ 系统管理 (System) 104 | 105 | #### 基础配置 (Basic) 106 | 107 | - **bbr_open** : 开启 BBR 网络加速 108 | - **language** : 系统语言切换(中英文) 109 | - **reinstall** : 系统重装工具 110 | - **info** : 系统信息 111 | 112 | #### 用户管理 (User) 113 | 114 | - **account** : 用户账号管理(创建/删除/修改密码) 115 | - **key** : SSH 密钥管理(生成/安装) 116 | - **ssh** : SSH 配置管理(端口/登录方式) 117 | 118 | ### ⏱️ 自动任务管理 (Task) 119 | 120 | #### 任务安装脚本 (Installs) 121 | 122 | - **acme_update** : SSL 证书自动更新任务 123 | - **backup** : 数据自动备份任务(本地/云端) 124 | - **up:docker_compose** : Docker 容器自动更新任务 125 | - **update** : 系统自动更新任务 126 | 127 | #### 任务管理工具 128 | 129 | - **manage** : 已安装任务管理(查看/删除) 130 | 131 | ### 🌐 网站服务管理 (Web) 132 | 133 | #### SSL 证书管理 (acme) 134 | 135 | - **apply** : 申请 SSL 证书 136 | - **manage** : 证书管理(查看信息) 137 | 138 | #### Nginx 管理 (nginx) 139 | 140 | - **install** : 配置 Nginx 站点 141 | - **manage** : 站点管理(查看/删除) 142 | 143 | ### 脚本管理 (manage) 144 | 145 | - **install** : 工具箱安装脚本 146 | - **unInstall** : 工具箱卸载脚本 147 | 148 | ### 常用软件安装 (software) 149 | 150 | ### 系统软件源管理 (sources) 151 | 152 | ### VPN 服务一键部署 (vpn) 153 | 154 | ## 📝 问题反馈 155 | 156 | 如有问题或建议: 157 | 158 | - 提交 Issue 159 | - 关注公众号: lsy22 160 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $UID != 0 ]]; then 4 | echo "请以root权限执行该脚本" 5 | exit 6 | fi 7 | 8 | declare -a function_array 9 | declare selected_function 10 | declare script_path=$(dirname $(readlink -f $0)) 11 | script_path="${script_path}/Config" 12 | declare local_path=$script_path 13 | declare script_name 14 | 15 | while true; do 16 | # 1. 目录初始化脚本 _init.sh 17 | if [[ -e "${local_path}/_init.sh" ]]; then 18 | bash "${local_path}/_init.sh" 19 | if [[ $? -eq 1 ]]; then 20 | local_path=$script_path 21 | continue 22 | fi 23 | fi 24 | 25 | # 2. 完全替代菜单 _menu.sh 26 | if [[ -e "${local_path}/_menu.sh" ]]; then 27 | clear 28 | bash "${local_path}/_menu.sh" "$local_path" 29 | local_path=$script_path 30 | continue 31 | fi 32 | 33 | # 默认菜单逻辑 34 | selected_function=0 35 | function_array=() 36 | echo "======$(basename $local_path .sh)======" 37 | for i in "${local_path}"/*; do 38 | script_name=$(awk -F '.' '{print $1}' <<<"$(basename $i)") 39 | # 忽略特殊文件 40 | if [[ $script_name =~ ^_ ]]; then 41 | continue 42 | fi 43 | selected_function=$((selected_function + 1)) 44 | function_array[$selected_function]=$script_name 45 | echo "${selected_function}.${function_array[$selected_function]}" 46 | done 47 | 48 | if [[ $local_path != $script_path ]]; then 49 | echo "输入任意返回主页" 50 | fi 51 | 52 | read -p "请输入要使用的功能:" user_choice 53 | if [[ "$user_choice" =~ ^[0-9]+$ ]] && [ "$user_choice" -ge 1 ] && [ "$user_choice" -le "${#function_array[*]}" ]; then 54 | clear 55 | selected_script="${function_array[$user_choice]}" 56 | 57 | if [[ -d "${local_path}/${selected_script}" ]]; then 58 | # 进入子目录 59 | local_path="${local_path}/${selected_script}" 60 | elif [[ -e "${local_path}/${selected_script}.sh" ]]; then 61 | # 3. 检查是否存在 _action.sh(半替代菜单) 62 | if [[ -e "${local_path}/_action.sh" ]]; then 63 | # 将用户选择的脚本名称和当前路径传递给 _action.sh 64 | bash "${local_path}/_action.sh" "$local_path" "${selected_script}" 65 | else 66 | # 直接执行用户选择的脚本 67 | bash "${local_path}/${selected_script}.sh" 68 | fi 69 | local_path=$script_path 70 | fi 71 | else 72 | if [[ $local_path == $script_path ]]; then 73 | exit 74 | fi 75 | local_path=$script_path 76 | fi 77 | 78 | done 79 | --------------------------------------------------------------------------------